git: 34b00ed041a4 - main - hwpmc: fix IBS fetch and op NMI handling

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Mon, 28 Sep 2026 17:43:35 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=34b00ed041a49eecc85b9a91748145ada14d83c5

commit 34b00ed041a49eecc85b9a91748145ada14d83c5
Author:     Andre Silva <andasilv@amd.com>
AuthorDate: 2026-09-28 17:39:56 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-09-28 17:40:14 +0000

    hwpmc: fix IBS fetch and op NMI handling
    
    Service each IBS unit with a valid bit set when fetch and op share an
    NMI. Otherwise, op samples can be lost. Treat the extra NMI that follows
    as expected (skip it).
    
    Reviewed by:    mhorne
    Fixes:  e51ef8ae490f ("hwpmc: Initial support for AMD IBS")
    Differential Revision:  https://reviews.freebsd.org/D60004
---
 sys/dev/hwpmc/hwpmc_ibs.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_ibs.c b/sys/dev/hwpmc/hwpmc_ibs.c
index 17c3495f6a79..9e4af386f8d8 100644
--- a/sys/dev/hwpmc/hwpmc_ibs.c
+++ b/sys/dev/hwpmc/hwpmc_ibs.c
@@ -97,6 +97,7 @@ SYSCTL_U64(_kern_hwpmc, OID_AUTO, ibs_op_ctl2_extra_mask, CTLFLAG_RDTUN,
 
 struct ibs_cpu {
 	int		pc_status;
+	int		pc_nmi_credit;	/* latched NMIs already serviced */
 	struct pmc_hw	pc_ibspmcs[IBS_NPMCS];
 };
 static struct ibs_cpu **ibs_pcpu;
@@ -702,24 +703,40 @@ pmc_ibs_intr(struct trapframe *tf)
 
 	pac = ibs_pcpu[cpu];
 
+	/*
+	 * Fetch and op share an NMI.  Both valid bits may be set on entry,
+	 * so service each valid source or the skipped unit can stay frozen
+	 * with no NMI pending to re-arm it.
+	 */
 	config = rdmsr(IBS_FETCH_CTL);
 	if ((config & IBS_FETCH_CTL_VALID) != 0) {
 		pm = pac->pc_ibspmcs[IBS_PMC_FETCH].phw_pmc;
 
-		retval = 1;
+		retval++;
 
 		pmc_ibs_process_fetch(pm, tf, config);
 	}
 
 	config = rdmsr(IBS_OP_CTL);
-	if ((retval == 0) && ((config & IBS_OP_CTL_VALID) != 0)) {
+	if ((config & IBS_OP_CTL_VALID) != 0) {
 		pm = pac->pc_ibspmcs[IBS_PMC_OP].phw_pmc;
 
-		retval = 1;
+		retval++;
 
 		pmc_ibs_process_op(pm, tf, config);
 	}
 
+	/*
+	 * When both units were serviced, the second unit's NMI may still be
+	 * latched and will arrive with no valid bit set.  Claim that one
+	 * NMI so it is not reported as unknown.
+	 */
+	if (retval == 0 && pac->pc_nmi_credit != 0)
+		retval = 1;
+	pac->pc_nmi_credit = (retval == 2);
+	if (retval > 1)
+		retval = 1;
+
 	if (retval == 0) {
 		// Lets check for a stray NMI when stopping
 		if (atomic_load_int(&pac->pc_status) == IBS_CPU_STOPPING) {