git: 4b267d4e4f6a - main - hwpmc: fix stopping process PMCs on exit with PerfMonV2

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Fri, 02 Oct 2026 13:58:53 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=4b267d4e4f6a6cd7bd08b9c4854fcb26fab8c18c

commit 4b267d4e4f6a6cd7bd08b9c4854fcb26fab8c18c
Author:     Andre Silva <andasilv@amd.com>
AuthorDate: 2026-10-02 13:55:26 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-10-02 13:55:41 +0000

    hwpmc: fix stopping process PMCs on exit with PerfMonV2
    
    Since 9d3064010590, pmc_process_exit() calls pmc_process_csw_stop_all()
    first. That clears pps_cpustate for every virtual PMC on the CPU, so the
    exit loop then skips the stop and the final read.
    
    On AMD PerfMonV2 this has two effects:
    - The count from the last time slice is lost. A process that never
      switches out before exit reports 0 with pmcstat -p.
    - The EVSEL enable bit stays set. After kldunload, the next kldload
      sees it and says "PMCs maybe in use by firmware!".
    
    It is not required that pmc_process_csw_stop_all() should touch the
    ppc_cpustate field at all; remove this to fix the issues.
    
    Reviewed by:    mhorne
    Fixes:          9d3064010590 ("hwpmc_amd: add PerfMonV2 global-control path")
    Sponsored by:   AMD
    Differential Revision:  https://reviews.freebsd.org/D60141
---
 sys/dev/hwpmc/hwpmc_mod.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index 1a333e137d0a..7db73b5c78c9 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -248,7 +248,6 @@ static void	pmc_post_callchain_callback(void);
 static void	pmc_process_allproc(struct pmc *pm);
 static void	pmc_process_csw_in(struct thread *td);
 static void	pmc_process_csw_out(struct thread *td);
-static void	pmc_process_csw_out_prepare(int cpu);
 static void	pmc_process_csw_start_all(int cpu);
 static void	pmc_process_csw_stop_all(int cpu);
 static void	pmc_process_exec(struct thread *td,
@@ -1449,8 +1448,6 @@ pmc_process_csw_stop_all(int cpu)
 	struct pmc_classdep *pcd;
 	u_int class;
 
-	pmc_process_csw_out_prepare(cpu);
-
 	for (class = 0; class < md->pmd_nclass; class++) {
 		pcd = &md->pmd_classdep[class];
 		if (pcd->pcd_stop_all != NULL)
@@ -1458,32 +1455,6 @@ pmc_process_csw_stop_all(int cpu)
 	}
 }
 
-/*
- * Mark virtual PMCs stopped, before you close hardware gates.
- */
-static void
-pmc_process_csw_out_prepare(int cpu)
-{
-	struct pmc *pm;
-	struct pmc_classdep *pcd;
-	u_int class;
-	int adjri;
-
-	for (class = 0; class < md->pmd_nclass; class++) {
-		pcd = &md->pmd_classdep[class];
-		if (pcd->pcd_stop_all == NULL)
-			continue;
-		for (adjri = 0; adjri < pcd->pcd_num; adjri++) {
-			pm = NULL;
-			(void)pcd->pcd_get_config(cpu, adjri, &pm);
-			if (pm == NULL ||
-			    !PMC_IS_VIRTUAL_MODE(PMC_TO_MODE(pm)))
-				continue;
-			pm->pm_pcpu_state[cpu].pps_cpustate = 0;
-		}
-	}
-}
-
 /*
  * Thread context switch IN.
  */