svn commit: r184802 - in head/sys: amd64/include conf dev/hwpmc i386/include modules/hwpmc sys

Joseph Koshy jkoshy at FreeBSD.org
Sun Nov 9 09:37:54 PST 2008


Author: jkoshy
Date: Sun Nov  9 17:37:54 2008
New Revision: 184802
URL: http://svn.freebsd.org/changeset/base/184802

Log:
  - Separate PMC class dependent code from other kinds of machine
    dependencies.  A 'struct pmc_classdep' structure describes operations
    on PMCs; 'struct pmc_mdep' contains one or more 'struct pmc_classdep'
    structures depending on the CPU in question.
  
    Inside PMC class dependent code, row indices are relative to the
    PMCs supported by the PMC class; MI code in "hwpmc_mod.c" translates
    global row indices before invoking class dependent operations.
  
  - Augment the OP_GETCPUINFO request with the number of PMCs present
    in a PMC class.
  
  - Move code common to Intel CPUs to file "hwpmc_intel.c".
  
  - Move TSC handling to file "hwpmc_tsc.c".

Added:
  head/sys/dev/hwpmc/hwpmc_intel.c   (contents, props changed)
  head/sys/dev/hwpmc/hwpmc_tsc.c   (contents, props changed)
  head/sys/dev/hwpmc/hwpmc_tsc.h   (contents, props changed)
Modified:
  head/sys/amd64/include/pmc_mdep.h
  head/sys/conf/files.amd64
  head/sys/conf/files.i386
  head/sys/conf/files.pc98
  head/sys/dev/hwpmc/hwpmc_amd.c
  head/sys/dev/hwpmc/hwpmc_amd.h
  head/sys/dev/hwpmc/hwpmc_mod.c
  head/sys/dev/hwpmc/hwpmc_pentium.c
  head/sys/dev/hwpmc/hwpmc_pentium.h
  head/sys/dev/hwpmc/hwpmc_piv.c
  head/sys/dev/hwpmc/hwpmc_piv.h
  head/sys/dev/hwpmc/hwpmc_ppro.c
  head/sys/dev/hwpmc/hwpmc_ppro.h
  head/sys/dev/hwpmc/hwpmc_x86.c
  head/sys/i386/include/pmc_mdep.h
  head/sys/modules/hwpmc/Makefile
  head/sys/sys/pmc.h

Modified: head/sys/amd64/include/pmc_mdep.h
==============================================================================
--- head/sys/amd64/include/pmc_mdep.h	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/amd64/include/pmc_mdep.h	Sun Nov  9 17:37:54 2008	(r184802)
@@ -35,8 +35,34 @@
 #ifndef _MACHINE_PMC_MDEP_H
 #define	_MACHINE_PMC_MDEP_H 1
 
+#ifdef	_KERNEL
+struct pmc_mdep;
+#endif
+
 #include <dev/hwpmc/hwpmc_amd.h>
 #include <dev/hwpmc/hwpmc_piv.h>
+#include <dev/hwpmc/hwpmc_tsc.h>
+
+/*
+ * Intel processors implementing V2 and later of the Intel performance
+ * measurement architecture have PMCs of the following classes: TSC,
+ * IAF and IAP.
+ */
+#define	PMC_MDEP_CLASS_INDEX_TSC	0
+#define	PMC_MDEP_CLASS_INDEX_K8		1
+#define	PMC_MDEP_CLASS_INDEX_P4		1
+#define	PMC_MDEP_CLASS_INDEX_IAF	1
+#define	PMC_MDEP_CLASS_INDEX_IAP	2
+
+/*
+ * On the amd64 platform we support the following PMCs.
+ *
+ * TSC		The timestamp counter
+ * K8		AMD Athlon64 and Opteron PMCs in 64 bit mode.
+ * PIV		Intel P4/HTT and P4/EMT64
+ * IAP		Intel Core/Core2/Atom CPUs in 64 bits mode.
+ * IAF		Intel fixed-function PMCs in Core2 and later CPUs.
+ */
 
 union pmc_md_op_pmcallocate  {
 	struct pmc_md_amd_op_pmcallocate	pm_amd;
@@ -55,8 +81,6 @@ union pmc_md_pmc {
 	struct pmc_md_p4_pmc	pm_p4;
 };
 
-struct pmc;
-
 #define	PMC_TRAPFRAME_TO_PC(TF)	((TF)->tf_rip)
 #define	PMC_TRAPFRAME_TO_FP(TF)	((TF)->tf_rbp)
 #define	PMC_TRAPFRAME_TO_USER_SP(TF)	((TF)->tf_rsp)
@@ -88,5 +112,10 @@ struct pmc;
 void	start_exceptions(void), end_exceptions(void);
 void	pmc_x86_lapic_enable_pmc_interrupt(void);
 
-#endif
+struct pmc_mdep *pmc_amd_initialize(void);
+void	pmc_amd_finalize(struct pmc_mdep *_md);
+struct pmc_mdep *pmc_intel_initialize(void);
+void	pmc_intel_finalize(struct pmc_mdep *_md);
+
+#endif /* _KERNEL */
 #endif /* _MACHINE_PMC_MDEP_H */

Modified: head/sys/conf/files.amd64
==============================================================================
--- head/sys/conf/files.amd64	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/conf/files.amd64	Sun Nov  9 17:37:54 2008	(r184802)
@@ -188,7 +188,9 @@ dev/hptrr/hptrr_os_bsd.c	optional	hptrr
 dev/hptrr/hptrr_osm_bsd.c	optional	hptrr
 dev/hptrr/hptrr_config.c	optional	hptrr
 dev/hwpmc/hwpmc_amd.c		optional	hwpmc
+dev/hwpmc/hwpmc_intel.c		optional	hwpmc
 dev/hwpmc/hwpmc_piv.c		optional	hwpmc
+dev/hwpmc/hwpmc_tsc.c		optional	hwpmc
 dev/hwpmc/hwpmc_x86.c		optional	hwpmc
 dev/k8temp/k8temp.c		optional	k8temp
 dev/kbd/kbd.c			optional	atkbd | sc | ukbd

Modified: head/sys/conf/files.i386
==============================================================================
--- head/sys/conf/files.i386	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/conf/files.i386	Sun Nov  9 17:37:54 2008	(r184802)
@@ -186,9 +186,11 @@ dev/hptrr/hptrr_os_bsd.c	optional hptrr
 dev/hptrr/hptrr_osm_bsd.c	optional hptrr
 dev/hptrr/hptrr_config.c	optional hptrr
 dev/hwpmc/hwpmc_amd.c		optional hwpmc
+dev/hwpmc/hwpmc_intel.c		optional hwpmc
 dev/hwpmc/hwpmc_pentium.c	optional hwpmc
 dev/hwpmc/hwpmc_piv.c		optional hwpmc
 dev/hwpmc/hwpmc_ppro.c		optional hwpmc
+dev/hwpmc/hwpmc_tsc.c		optional hwpmc
 dev/hwpmc/hwpmc_x86.c		optional hwpmc
 dev/ichwd/ichwd.c		optional ichwd
 dev/if_ndis/if_ndis.c		optional ndis

Modified: head/sys/conf/files.pc98
==============================================================================
--- head/sys/conf/files.pc98	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/conf/files.pc98	Sun Nov  9 17:37:54 2008	(r184802)
@@ -110,9 +110,11 @@ dev/ed/if_ed_wd80x3.c		optional ed isa
 dev/fb/fb.c			optional fb | gdc
 dev/fe/if_fe_cbus.c		optional fe isa
 dev/hwpmc/hwpmc_amd.c		optional hwpmc
+dev/hwpmc/hwpmc_intel.c		optional hwpmc
 dev/hwpmc/hwpmc_pentium.c	optional hwpmc
 dev/hwpmc/hwpmc_piv.c		optional hwpmc
 dev/hwpmc/hwpmc_ppro.c		optional hwpmc
+dev/hwpmc/hwpmc_tsc.c		optional hwpmc
 dev/hwpmc/hwpmc_x86.c		optional hwpmc
 dev/io/iodev.c			optional io
 dev/kbd/kbd.c			optional pckbd | sc | ukbd

Modified: head/sys/dev/hwpmc/hwpmc_amd.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_amd.c	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/dev/hwpmc/hwpmc_amd.c	Sun Nov  9 17:37:54 2008	(r184802)
@@ -26,7 +26,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
  */
 
 #include <sys/cdefs.h>
@@ -64,18 +63,6 @@ static  struct amd_descr amd_pmcdesc[AMD
     {
 	.pm_descr =
 	{
-		.pd_name  = "TSC",
-		.pd_class = PMC_CLASS_TSC,
-		.pd_caps  = PMC_CAP_READ,
-		.pd_width = 64
-	},
-	.pm_evsel   = MSR_TSC,
-	.pm_perfctr = 0	/* unused */
-    },
-
-    {
-	.pm_descr =
-	{
 		.pd_name  = "",
 		.pd_class = -1,
 		.pd_caps  = AMD_PMC_CAPS,
@@ -258,6 +245,16 @@ const int amd_event_codes_size =
 	sizeof(amd_event_codes) / sizeof(amd_event_codes[0]);
 
 /*
+ * Per-processor information
+ */
+
+struct amd_cpu {
+	struct pmc_hw	pc_amdpmcs[AMD_NPMCS];
+};
+
+static struct amd_cpu **amd_pcpu;
+
+/*
  * read a pmc register
  */
 
@@ -267,17 +264,17 @@ amd_read_pmc(int cpu, int ri, pmc_value_
 	enum pmc_mode mode;
 	const struct amd_descr *pd;
 	struct pmc *pm;
-	const struct pmc_hw *phw;
 	pmc_value_t tmp;
 
 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
 	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
+	KASSERT(amd_pcpu[cpu],
+	    ("[amd,%d] null per-cpu, cpu %d", __LINE__, cpu));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
-	pd  = &amd_pmcdesc[ri];
-	pm  = phw->phw_pmc;
+	pm = amd_pcpu[cpu]->pc_amdpmcs[ri].phw_pmc;
+	pd = &amd_pmcdesc[ri];
 
 	KASSERT(pm != NULL,
 	    ("[amd,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__,
@@ -287,15 +284,6 @@ amd_read_pmc(int cpu, int ri, pmc_value_
 
 	PMCDBG(MDP,REA,1,"amd-read id=%d class=%d", ri, pd->pm_descr.pd_class);
 
-	/* Reading the TSC is a special case */
-	if (pd->pm_descr.pd_class == PMC_CLASS_TSC) {
-		KASSERT(PMC_IS_COUNTING_MODE(mode),
-		    ("[amd,%d] TSC counter in non-counting mode", __LINE__));
-		*v = rdtsc();
-		PMCDBG(MDP,REA,2,"amd-read id=%d -> %jd", ri, *v);
-		return 0;
-	}
-
 #ifdef	DEBUG
 	KASSERT(pd->pm_descr.pd_class == amd_pmc_class,
 	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
@@ -324,18 +312,16 @@ static int
 amd_write_pmc(int cpu, int ri, pmc_value_t v)
 {
 	const struct amd_descr *pd;
-	struct pmc *pm;
-	const struct pmc_hw *phw;
 	enum pmc_mode mode;
+	struct pmc *pm;
 
 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
 	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
-	pd  = &amd_pmcdesc[ri];
-	pm  = phw->phw_pmc;
+	pm = amd_pcpu[cpu]->pc_amdpmcs[ri].phw_pmc;
+	pd = &amd_pmcdesc[ri];
 
 	KASSERT(pm != NULL,
 	    ("[amd,%d] PMC not owned (cpu%d,pmc%d)", __LINE__,
@@ -343,9 +329,6 @@ amd_write_pmc(int cpu, int ri, pmc_value
 
 	mode = PMC_TO_MODE(pm);
 
-	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
-		return 0;
-
 #ifdef	DEBUG
 	KASSERT(pd->pm_descr.pd_class == amd_pmc_class,
 	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
@@ -380,7 +363,7 @@ amd_config_pmc(int cpu, int ri, struct p
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
+	phw = &amd_pcpu[cpu]->pc_amdpmcs[ri];
 
 	KASSERT(pm == NULL || phw->phw_pmc == NULL,
 	    ("[amd,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
@@ -397,7 +380,7 @@ amd_config_pmc(int cpu, int ri, struct p
 static int
 amd_get_config(int cpu, int ri, struct pmc **ppm)
 {
-	*ppm = pmc_pcpu[cpu]->pc_hwpmcs[ri]->phw_pmc;
+	*ppm = amd_pcpu[cpu]->pc_amdpmcs[ri].phw_pmc;
 
 	return 0;
 }
@@ -474,18 +457,6 @@ amd_allocate_pmc(int cpu, int ri, struct
 
 	if ((pd->pd_caps & caps) != caps)
 		return EPERM;
-	if (pd->pd_class == PMC_CLASS_TSC) {
-		/* TSC's are always allocated in system-wide counting mode */
-		if (a->pm_ev != PMC_EV_TSC_TSC ||
-		    a->pm_mode != PMC_MODE_SC)
-			return EINVAL;
-		return 0;
-	}
-
-#ifdef	DEBUG
-	KASSERT(pd->pd_class == amd_pmc_class,
-	    ("[amd,%d] Unknown PMC class (%d)", __LINE__, pd->pd_class));
-#endif
 
 	pe = a->pm_ev;
 
@@ -556,7 +527,7 @@ amd_release_pmc(int cpu, int ri, struct 
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
+	phw = &amd_pcpu[cpu]->pc_amdpmcs[ri];
 
 	KASSERT(phw->phw_pmc == NULL,
 	    ("[amd,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
@@ -588,7 +559,7 @@ amd_start_pmc(int cpu, int ri)
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
+	phw = &amd_pcpu[cpu]->pc_amdpmcs[ri];
 	pm  = phw->phw_pmc;
 	pd = &amd_pmcdesc[ri];
 
@@ -598,15 +569,6 @@ amd_start_pmc(int cpu, int ri)
 
 	PMCDBG(MDP,STA,1,"amd-start cpu=%d ri=%d", cpu, ri);
 
-	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
-		return 0;	/* TSCs are always running */
-
-#ifdef	DEBUG
-	KASSERT(pd->pm_descr.pd_class == amd_pmc_class,
-	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
-		pd->pm_descr.pd_class));
-#endif
-
 	KASSERT(AMD_PMC_IS_STOPPED(pd->pm_evsel),
 	    ("[amd,%d] pmc%d,cpu%d: Starting active PMC \"%s\"", __LINE__,
 	    ri, cpu, pd->pm_descr.pd_name));
@@ -637,24 +599,13 @@ amd_stop_pmc(int cpu, int ri)
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
+	phw = &amd_pcpu[cpu]->pc_amdpmcs[ri];
 	pm  = phw->phw_pmc;
 	pd  = &amd_pmcdesc[ri];
 
 	KASSERT(pm != NULL,
 	    ("[amd,%d] cpu%d,pmc%d no PMC to stop", __LINE__,
 		cpu, ri));
-
-	/* can't stop a TSC */
-	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
-		return 0;
-
-#ifdef	DEBUG
-	KASSERT(pd->pm_descr.pd_class == amd_pmc_class,
-	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
-		pd->pm_descr.pd_class));
-#endif
-
 	KASSERT(!AMD_PMC_IS_STOPPED(pd->pm_evsel),
 	    ("[amd,%d] PMC%d, CPU%d \"%s\" already stopped",
 		__LINE__, ri, cpu, pd->pm_descr.pd_name));
@@ -677,10 +628,10 @@ amd_stop_pmc(int cpu, int ri)
 static int
 amd_intr(int cpu, struct trapframe *tf)
 {
-	int i, error, retval, ri;
+	int i, error, retval;
 	uint32_t config, evsel, perfctr;
 	struct pmc *pm;
-	struct pmc_cpu *pc;
+	struct amd_cpu *pac;
 	struct pmc_hw *phw;
 	pmc_value_t v;
 
@@ -692,11 +643,10 @@ amd_intr(int cpu, struct trapframe *tf)
 
 	retval = 0;
 
-	pc = pmc_pcpu[cpu];
+	pac = amd_pcpu[cpu];
 
 	/*
 	 * look for all PMCs that have interrupted:
-	 * - skip over the TSC [PMC#0]
 	 * - look for a running, sampling PMC which has overflowed
 	 *   and which has a valid 'struct pmc' association
 	 *
@@ -708,14 +658,12 @@ amd_intr(int cpu, struct trapframe *tf)
 	 * interrupt at a time.
 	 */
 
-	for (i = 0; retval == 0 && i < AMD_NPMCS-1; i++) {
-
-		ri = i + 1;	/* row index; TSC is at ri == 0 */
+	for (i = 0; retval == 0 && i < AMD_NPMCS; i++) {
 
 		if (!AMD_PMC_HAS_OVERFLOWED(i))
 			continue;
 
-		phw = pc->pc_hwpmcs[ri];
+		phw = &pac->pc_amdpmcs[i];
 
 		KASSERT(phw != NULL, ("[amd,%d] null PHW pointer", __LINE__));
 
@@ -769,7 +717,7 @@ amd_describe(int cpu, int ri, struct pmc
 	KASSERT(ri >= 0 && ri < AMD_NPMCS,
 	    ("[amd,%d] row-index %d out of range", __LINE__, ri));
 
-	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
+	phw = &amd_pcpu[cpu]->pc_amdpmcs[ri];
 	pd  = &amd_pmcdesc[ri];
 
 	if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
@@ -804,33 +752,20 @@ amd_get_msr(int ri, uint32_t *msr)
 	    ("[amd,%d] ri %d out of range", __LINE__, ri));
 
 	*msr = amd_pmcdesc[ri].pm_perfctr - AMD_PMC_PERFCTR_0;
-	return 0;
+
+	return (0);
 }
 
 /*
  * processor dependent initialization.
  */
 
-/*
- * Per-processor data structure
- *
- * [common stuff]
- * [5 struct pmc_hw pointers]
- * [5 struct pmc_hw structures]
- */
-
-struct amd_cpu {
-	struct pmc_cpu	pc_common;
-	struct pmc_hw	*pc_hwpmcs[AMD_NPMCS];
-	struct pmc_hw	pc_amdpmcs[AMD_NPMCS];
-};
-
-
 static int
-amd_init(int cpu)
+amd_pcpu_init(struct pmc_mdep *md, int cpu)
 {
-	int n;
-	struct amd_cpu *pcs;
+	int classindex, first_ri, n;
+	struct pmc_cpu *pc;
+	struct amd_cpu *pac;
 	struct pmc_hw  *phw;
 
 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
@@ -838,29 +773,32 @@ amd_init(int cpu)
 
 	PMCDBG(MDP,INI,1,"amd-init cpu=%d", cpu);
 
-	pcs = malloc(sizeof(struct amd_cpu), M_PMC,
+	amd_pcpu[cpu] = pac = malloc(sizeof(struct amd_cpu), M_PMC,
 	    M_WAITOK|M_ZERO);
 
-	phw = &pcs->pc_amdpmcs[0];
-
 	/*
-	 * Initialize the per-cpu mutex and set the content of the
-	 * hardware descriptors to a known state.
+	 * Set the content of the hardware descriptors to a known
+	 * state and initialize pointers in the MI per-cpu descriptor.
 	 */
+	pc = pmc_pcpu[cpu];
+#if	defined(__amd64__)
+	classindex = PMC_MDEP_CLASS_INDEX_K8;
+#elif	defined(__i386__)
+	classindex = md->pmd_cputype == PMC_CPU_AMD_K8 ?
+	    PMC_MDEP_CLASS_INDEX_K8 : PMC_MDEP_CLASS_INDEX_K7;
+#endif
+	first_ri = md->pmd_classdep[classindex].pcd_ri;
 
-	for (n = 0; n < AMD_NPMCS; n++, phw++) {
+	KASSERT(pc != NULL, ("[amd,%d] NULL per-cpu pointer", __LINE__));
+
+	for (n = 0, phw = pac->pc_amdpmcs; n < AMD_NPMCS; n++, phw++) {
 		phw->phw_state 	  = PMC_PHW_FLAG_IS_ENABLED |
 		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n);
 		phw->phw_pmc	  = NULL;
-		pcs->pc_hwpmcs[n] = phw;
+		pc->pc_hwpmcs[n + first_ri]  = phw;
 	}
 
-	/* Mark the TSC as shareable */
-	pcs->pc_hwpmcs[0]->phw_state |= PMC_PHW_FLAG_IS_SHAREABLE;
-
-	pmc_pcpu[cpu] = (struct pmc_cpu *) pcs;
-
-	return 0;
+	return (0);
 }
 
 
@@ -870,11 +808,12 @@ amd_init(int cpu)
  */
 
 static int
-amd_cleanup(int cpu)
+amd_pcpu_fini(struct pmc_mdep *md, int cpu)
 {
-	int i;
+	int classindex, first_ri, i;
 	uint32_t evsel;
-	struct pmc_cpu *pcs;
+	struct pmc_cpu *pc;
+	struct amd_cpu *pac;
 
 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
 	    ("[amd,%d] insane cpu number (%d)", __LINE__, cpu));
@@ -884,7 +823,6 @@ amd_cleanup(int cpu)
 	/*
 	 * First, turn off all PMCs on this CPU.
 	 */
-
 	for (i = 0; i < 4; i++) { /* XXX this loop is now not needed */
 		evsel = rdmsr(AMD_PMC_EVSEL_0 + i);
 		evsel &= ~AMD_PMC_ENABLE;
@@ -894,25 +832,42 @@ amd_cleanup(int cpu)
 	/*
 	 * Next, free up allocated space.
 	 */
+	if ((pac = amd_pcpu[cpu]) == NULL)
+		return (0);
 
-	if ((pcs = pmc_pcpu[cpu]) == NULL)
-		return 0;
+	amd_pcpu[cpu] = NULL;
 
 #ifdef	DEBUG
-	/* check the TSC */
-	KASSERT(pcs->pc_hwpmcs[0]->phw_pmc == NULL,
-	    ("[amd,%d] CPU%d,PMC0 still in use", __LINE__, cpu));
-	for (i = 1; i < AMD_NPMCS; i++) {
-		KASSERT(pcs->pc_hwpmcs[i]->phw_pmc == NULL,
+	for (i = 0; i < AMD_NPMCS; i++) {
+		KASSERT(pac->pc_amdpmcs[i].phw_pmc == NULL,
 		    ("[amd,%d] CPU%d/PMC%d in use", __LINE__, cpu, i));
 		KASSERT(AMD_PMC_IS_STOPPED(AMD_PMC_EVSEL_0 + (i-1)),
 		    ("[amd,%d] CPU%d/PMC%d not stopped", __LINE__, cpu, i));
 	}
 #endif
 
-	pmc_pcpu[cpu] = NULL;
-	free(pcs, M_PMC);
-	return 0;
+	pc = pmc_pcpu[cpu];
+	KASSERT(pc != NULL, ("[amd,%d] NULL per-cpu state", __LINE__));
+
+#if	defined(__amd64__)
+	classindex = PMC_MDEP_CLASS_INDEX_K8;
+#elif	defined(__i386__)
+	classindex = md->pmd_cputype == PMC_CPU_AMD_K8 ? PMC_MDEP_CLASS_INDEX_K8 :
+	    PMC_MDEP_CLASS_INDEX_K7;
+#endif
+	first_ri = md->pmd_classdep[classindex].pcd_ri;
+
+	/*
+	 * Reset pointers in the MI 'per-cpu' state.
+	 */
+	for (i = 0; i < AMD_NPMCS; i++) {
+		pc->pc_hwpmcs[i + first_ri] = NULL;
+	}
+
+
+	free(pac, M_PMC);
+
+	return (0);
 }
 
 /*
@@ -922,11 +877,12 @@ amd_cleanup(int cpu)
 struct pmc_mdep *
 pmc_amd_initialize(void)
 {
+	int classindex, error, i, nclasses, ncpus;
+	struct pmc_classdep *pcd;
 	enum pmc_cputype cputype;
-	enum pmc_class class;
 	struct pmc_mdep *pmc_mdep;
+	enum pmc_class class;
 	char *name;
-	int i;
 
 	/*
 	 * The presence of hardware performance counters on the AMD
@@ -939,12 +895,16 @@ pmc_amd_initialize(void)
 	class = cputype = -1;
 	name = NULL;
 	switch (cpu_id & 0xF00) {
+#if	defined(__i386__)
 	case 0x600:		/* Athlon(tm) processor */
+		classindex = PMC_MDEP_CLASS_INDEX_K7;
 		cputype = PMC_CPU_AMD_K7;
 		class = PMC_CLASS_K7;
 		name = "K7";
 		break;
+#endif
 	case 0xF00:		/* Athlon64/Opteron processor */
+		classindex = PMC_MDEP_CLASS_INDEX_K8;
 		cputype = PMC_CPU_AMD_K8;
 		class = PMC_CLASS_K8;
 		name = "K8";
@@ -960,53 +920,121 @@ pmc_amd_initialize(void)
 	amd_pmc_class = class;
 #endif
 
-	pmc_mdep = malloc(sizeof(struct pmc_mdep),
-	    M_PMC, M_WAITOK|M_ZERO);
+	/*
+	 * Allocate space for pointers to PMC HW descriptors and for
+	 * the MDEP structure used by MI code.
+	 */
+	amd_pcpu = malloc(sizeof(struct amd_cpu *) * pmc_cpu_max(), M_PMC,
+	    M_WAITOK|M_ZERO);
 
-	pmc_mdep->pmd_cputype	   = cputype;
-	pmc_mdep->pmd_npmc 	   = AMD_NPMCS;
+	/*
+	 * These processors have two classes of PMCs: the TSC and
+	 * programmable PMCs.
+	 */
+	nclasses = 2;
+	pmc_mdep = malloc(sizeof(struct pmc_mdep) + nclasses * sizeof (struct pmc_classdep),
+	    M_PMC, M_WAITOK|M_ZERO);
 
-	/* this processor has two classes of usable PMCs */
-	pmc_mdep->pmd_nclass       = 2;
+	pmc_mdep->pmd_cputype = cputype;
+	pmc_mdep->pmd_nclass  = nclasses;
 
-	/* TSC */
-	pmc_mdep->pmd_classes[0].pm_class   = PMC_CLASS_TSC;
-	pmc_mdep->pmd_classes[0].pm_caps    = PMC_CAP_READ;
-	pmc_mdep->pmd_classes[0].pm_width   = 64;
-
-	/* AMD K7/K8 PMCs */
-	pmc_mdep->pmd_classes[1].pm_class   = class;
-	pmc_mdep->pmd_classes[1].pm_caps    = AMD_PMC_CAPS;
-	pmc_mdep->pmd_classes[1].pm_width   = 48;
+	ncpus = pmc_cpu_max();
 
-	pmc_mdep->pmd_nclasspmcs[0] = 1;
-	pmc_mdep->pmd_nclasspmcs[1] = (AMD_NPMCS-1);
+	/* Initialize the TSC. */
+	error = pmc_tsc_initialize(pmc_mdep, ncpus);
+	if (error)
+		goto error;
+
+	/* Initialize AMD K7 and K8 PMC handling. */
+	pcd = &pmc_mdep->pmd_classdep[classindex];
+
+	pcd->pcd_caps		= AMD_PMC_CAPS;
+	pcd->pcd_class		= class;
+	pcd->pcd_num		= AMD_NPMCS;
+	pcd->pcd_ri		= pmc_mdep->pmd_npmc;
+	pcd->pcd_width		= 48;
 
 	/* fill in the correct pmc name and class */
-	for (i = 1; i < AMD_NPMCS; i++) {
+	for (i = 0; i < AMD_NPMCS; i++) {
 		(void) snprintf(amd_pmcdesc[i].pm_descr.pd_name,
 		    sizeof(amd_pmcdesc[i].pm_descr.pd_name), "%s-%d",
 		    name, i-1);
 		amd_pmcdesc[i].pm_descr.pd_class = class;
 	}
 
-	pmc_mdep->pmd_init    	   = amd_init;
-	pmc_mdep->pmd_cleanup 	   = amd_cleanup;
-	pmc_mdep->pmd_switch_in    = amd_switch_in;
-	pmc_mdep->pmd_switch_out   = amd_switch_out;
-	pmc_mdep->pmd_read_pmc 	   = amd_read_pmc;
-	pmc_mdep->pmd_write_pmc    = amd_write_pmc;
-	pmc_mdep->pmd_config_pmc   = amd_config_pmc;
-	pmc_mdep->pmd_get_config   = amd_get_config;
-	pmc_mdep->pmd_allocate_pmc = amd_allocate_pmc;
-	pmc_mdep->pmd_release_pmc  = amd_release_pmc;
-	pmc_mdep->pmd_start_pmc    = amd_start_pmc;
-	pmc_mdep->pmd_stop_pmc     = amd_stop_pmc;
-	pmc_mdep->pmd_intr	   = amd_intr;
-	pmc_mdep->pmd_describe     = amd_describe;
-	pmc_mdep->pmd_get_msr  	   = amd_get_msr; /* i386 */
+	pcd->pcd_allocate_pmc	= amd_allocate_pmc;
+	pcd->pcd_config_pmc	= amd_config_pmc;
+	pcd->pcd_describe	= amd_describe;
+	pcd->pcd_get_config	= amd_get_config;
+	pcd->pcd_get_msr	= amd_get_msr;
+	pcd->pcd_pcpu_fini	= amd_pcpu_fini;
+	pcd->pcd_pcpu_init	= amd_pcpu_init;
+	pcd->pcd_read_pmc	= amd_read_pmc;
+	pcd->pcd_release_pmc	= amd_release_pmc;
+	pcd->pcd_start_pmc	= amd_start_pmc;
+	pcd->pcd_stop_pmc	= amd_stop_pmc;
+	pcd->pcd_write_pmc	= amd_write_pmc;
+
+	pmc_mdep->pmd_pcpu_init = NULL;
+	pmc_mdep->pmd_pcpu_fini = NULL;
+	pmc_mdep->pmd_intr	= amd_intr;
+	pmc_mdep->pmd_switch_in = amd_switch_in;
+	pmc_mdep->pmd_switch_out = amd_switch_out;
+
+	pmc_mdep->pmd_npmc     += AMD_NPMCS;
 
 	PMCDBG(MDP,INI,0,"%s","amd-initialize");
 
-	return pmc_mdep;
+	return (pmc_mdep);
+
+  error:
+	if (error) {
+		free(pmc_mdep, M_PMC);
+		pmc_mdep = NULL;
+	}
+
+	return (NULL);
+}
+
+/*
+ * Finalization code for AMD CPUs.
+ */
+
+void
+pmc_amd_finalize(struct pmc_mdep *md)
+{
+#if	defined(INVARIANTS)
+	int classindex, i, ncpus, pmcclass;
+#endif
+
+	pmc_tsc_finalize(md);
+
+	KASSERT(amd_pcpu != NULL, ("[amd,%d] NULL per-cpu array pointer",
+	    __LINE__));
+
+#if	defined(INVARIANTS)
+	switch (md->pmd_cputype) {
+#if	defined(__i386__)
+	case PMC_CPU_AMD_K7:
+		classindex = PMC_MDEP_CLASS_INDEX_K7;
+		pmcclass = PMC_CLASS_K7;
+		break;
+#endif
+	default:
+		classindex = PMC_MDEP_CLASS_INDEX_K8;
+		pmcclass = PMC_CLASS_K8;
+	}
+
+	KASSERT(md->pmd_classdep[classindex].pcd_class == pmcclass,
+	    ("[amd,%d] pmc class mismatch", __LINE__));
+
+	ncpus = pmc_cpu_max();
+
+	for (i = 0; i < ncpus; i++)
+		KASSERT(amd_pcpu[i] == NULL, ("[amd,%d] non-null pcpu",
+		    __LINE__));
+#endif
+
+	free(amd_pcpu, M_PMC);
+	amd_pcpu = NULL;
 }

Modified: head/sys/dev/hwpmc/hwpmc_amd.h
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_amd.h	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/dev/hwpmc/hwpmc_amd.h	Sun Nov  9 17:37:54 2008	(r184802)
@@ -44,7 +44,7 @@
 #define	AMD_PMC_PERFCTR_3	0xC0010007
 
 
-#define	AMD_NPMCS		5 /* 1 TSC + 4 PMCs */
+#define	AMD_NPMCS		4
 
 #define	AMD_PMC_COUNTERMASK	0xFF000000
 #define	AMD_PMC_TO_COUNTER(x)	(((x) << 24) & AMD_PMC_COUNTERMASK)
@@ -93,11 +93,5 @@ struct pmc_md_amd_pmc {
 	uint32_t	pm_amd_evsel;
 };
 
-/*
- * Prototypes
- */
-
-struct pmc_mdep *pmc_amd_initialize(void);		/* AMD K7/K8 PMCs */
-
 #endif /* _KERNEL */
 #endif /* _DEV_HWPMC_AMD_H_ */

Added: head/sys/dev/hwpmc/hwpmc_intel.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/hwpmc/hwpmc_intel.c	Sun Nov  9 17:37:54 2008	(r184802)
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 2008 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Common code for handling Intel CPUs.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
+#include <sys/systm.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/specialreg.h>
+
+static int
+intel_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
+{
+	(void) pc;
+
+	PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp,
+	    pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS);
+
+	/* allow the RDPMC instruction if needed */
+	if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS)
+		load_cr4(rcr4() | CR4_PCE);
+
+	PMCDBG(MDP,SWI,1, "cr4=0x%jx", (uintmax_t) rcr4());
+
+	return 0;
+}
+
+static int
+intel_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
+{
+	(void) pc;
+	(void) pp;		/* can be NULL */
+
+	PMCDBG(MDP,SWO,1, "pc=%p pp=%p cr4=0x%jx", pc, pp,
+	    (uintmax_t) rcr4());
+
+	/* always turn off the RDPMC instruction */
+ 	load_cr4(rcr4() & ~CR4_PCE);
+
+	return 0;
+}
+
+struct pmc_mdep *
+pmc_intel_initialize(void)
+{
+	struct pmc_mdep *pmc_mdep;
+	enum pmc_cputype cputype;
+	int error, model, nclasses, ncpus;
+
+	KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
+	    ("[intel,%d] Initializing non-intel processor", __LINE__));
+
+	PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
+
+	cputype = -1;
+	nclasses = 2;
+
+	switch (cpu_id & 0xF00) {
+#if	defined(__i386__)
+	case 0x500:		/* Pentium family processors */
+		cputype = PMC_CPU_INTEL_P5;
+		break;
+	case 0x600:		/* Pentium Pro, Celeron, Pentium II & III */
+		switch ((cpu_id & 0xF0) >> 4) { /* model number field */
+		case 0x1:
+			cputype = PMC_CPU_INTEL_P6;
+			break;
+		case 0x3: case 0x5:
+			cputype = PMC_CPU_INTEL_PII;
+			break;
+		case 0x6:
+			cputype = PMC_CPU_INTEL_CL;
+			break;
+		case 0x7: case 0x8: case 0xA: case 0xB:
+			cputype = PMC_CPU_INTEL_PIII;
+			break;
+		case 0x9: case 0xD:
+			cputype = PMC_CPU_INTEL_PM;
+			break;
+		}
+		break;
+#endif
+#if	defined(__i386__) || defined(__amd64__)
+	case 0xF00:		/* P4 */
+		model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4);
+		if (model >= 0 && model <= 6) /* known models */
+			cputype = PMC_CPU_INTEL_PIV;
+		break;
+	}
+#endif
+
+	if ((int) cputype == -1) {
+		printf("pmc: Unknown Intel CPU.\n");
+		return (NULL);
+	}
+
+	pmc_mdep = malloc(sizeof(struct pmc_mdep) + nclasses *
+	    sizeof(struct pmc_classdep), M_PMC, M_WAITOK|M_ZERO);
+
+	pmc_mdep->pmd_cputype 	 = cputype;
+	pmc_mdep->pmd_nclass	 = nclasses;
+
+	pmc_mdep->pmd_switch_in	 = intel_switch_in;
+	pmc_mdep->pmd_switch_out = intel_switch_out;
+
+	ncpus = pmc_cpu_max();
+
+	error = pmc_tsc_initialize(pmc_mdep, ncpus);
+	if (error)
+		goto error;
+
+	switch (cputype) {
+#if	defined(__i386__) || defined(__amd64__)
+
+		/*
+		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
+		 */
+
+	case PMC_CPU_INTEL_PIV:
+		error = pmc_p4_initialize(pmc_mdep, ncpus);
+
+		KASSERT(md->pmd_npmc == TSC_NPMCS + P4_NPMCS, ("[intel,%d] "
+		    "incorrect npmc count %d", __LINE__, md->pmd_npmc));
+		break;
+#endif
+
+#if	defined(__i386__)
+		/*
+		 * P6 Family Processors
+		 */
+
+	case PMC_CPU_INTEL_P6:
+	case PMC_CPU_INTEL_CL:
+	case PMC_CPU_INTEL_PII:
+	case PMC_CPU_INTEL_PIII:
+	case PMC_CPU_INTEL_PM:
+		error = pmc_p6_initialize(pmc_mdep, ncpus);
+
+		KASSERT(md->pmd_npmc == TSC_NPMCS + P6_NPMCS, ("[intel,%d] "
+		    "incorrect npmc count %d", __LINE__, md->pmd_npmc));
+		break;
+
+		/*
+		 * Intel Pentium PMCs.
+		 */
+
+	case PMC_CPU_INTEL_P5:
+		error = pmc_p5_initialize(pmc_mdep, ncpus);
+
+		KASSERT(md->pmd_npmc == TSC_NPMCS + PENTIUM_NPMCS, ("[intel,%d] "
+		    "incorrect npmc count %d", __LINE__, md->pmd_npmc));
+		break;
+#endif
+
+	default:
+		KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__));
+	}
+
+
+  error:
+	if (error) {
+		free(pmc_mdep, M_PMC);
+		pmc_mdep = NULL;
+	}
+
+	return (pmc_mdep);
+}
+
+void
+pmc_intel_finalize(struct pmc_mdep *md)
+{
+	pmc_tsc_finalize(md);
+
+	switch (md->pmd_cputype) {
+#if	defined(__i386__) || defined(__amd64__)
+	case PMC_CPU_INTEL_PIV:
+		pmc_p4_finalize(md);
+		break;
+#endif
+#if	defined(__i386__)
+	case PMC_CPU_INTEL_P6:
+	case PMC_CPU_INTEL_CL:
+	case PMC_CPU_INTEL_PII:
+	case PMC_CPU_INTEL_PIII:
+	case PMC_CPU_INTEL_PM:
+		pmc_p6_finalize(md);
+		break;
+	case PMC_CPU_INTEL_P5:
+		pmc_p5_finalize(md);
+		break;
+#endif
+	default:
+		KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
+	}
+}

Modified: head/sys/dev/hwpmc/hwpmc_mod.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_mod.c	Sun Nov  9 17:07:52 2008	(r184801)
+++ head/sys/dev/hwpmc/hwpmc_mod.c	Sun Nov  9 17:37:54 2008	(r184802)
@@ -154,6 +154,11 @@ static LIST_HEAD(, pmc_owner)			pmc_ss_o
 
 
 /*
+ * A map of row indices to classdep structures.
+ */
+static struct pmc_classdep **pmc_rowindex_to_classdep;
+
+/*
  * Prototypes
  */
 
@@ -463,7 +468,7 @@ pmc_debugflags_sysctl_handler(SYSCTL_HAN
 	(void) arg1; (void) arg2; /* unused parameters */
 
 	n = sizeof(pmc_debugstr);
-	newstr = malloc(n, M_PMC, M_ZERO|M_WAITOK);
+	newstr = malloc(n, M_PMC, M_WAITOK|M_ZERO);
 	(void) strlcpy(newstr, pmc_debugstr, n);
 
 	error = sysctl_handle_string(oidp, newstr, n, req);
@@ -483,6 +488,33 @@ pmc_debugflags_sysctl_handler(SYSCTL_HAN
 #endif
 
 /*
+ * Map a row index to a classdep structure and return the adjusted row
+ * index for the PMC class index.
+ */
+static struct pmc_classdep *
+pmc_ri_to_classdep(struct pmc_mdep *md, int ri, int *adjri)
+{

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list