* [PATCH][2.6.11-mm3] perfctr API update 2/9: physical indexing, ppc32
@ 2005-03-12 23:18 Mikael Pettersson
0 siblings, 0 replies; only message in thread
From: Mikael Pettersson @ 2005-03-12 23:18 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel
- Switch ppc32 driver to use physically-indexed control data.
- Rearrange struct perfctr_cpu_control. Remove _reserved fields.
- ppc_mmcr[] array in struct perfctr_cpu_state is no longer needed.
- In perfctr_cpu_update_control, call check_ireset after check_control,
since check_ireset now needs to use the virtual-to-physical map.
- Users must now format the 2-6 event selector values into the
MMCR0/MMCR1 images.
- Verify that unused/non-existent parts of MMCR images are zero.
Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se>
/Mikael
drivers/perfctr/ppc.c | 90 +++++++++++++++++++++++-----------------------
include/asm-ppc/perfctr.h | 21 +++-------
2 files changed, 52 insertions(+), 59 deletions(-)
diff -rupN linux-2.6.11-mm3/drivers/perfctr/ppc.c linux-2.6.11-mm3.perfctr-physical-indexing/drivers/perfctr/ppc.c
--- linux-2.6.11-mm3/drivers/perfctr/ppc.c 2005-03-12 19:26:25.000000000 +0100
+++ linux-2.6.11-mm3.perfctr-physical-indexing/drivers/perfctr/ppc.c 2005-03-12 19:55:49.000000000 +0100
@@ -41,11 +41,6 @@ enum pm_type {
};
static enum pm_type pm_type;
-/* Bits users shouldn't set in control.ppc.mmcr0:
- * - PMC1SEL/PMC2SEL because event selectors are in control.evntsel[]
- */
-#define MMCR0_RESERVED (MMCR0_PMC1SEL | MMCR0_PMC2SEL)
-
static unsigned int new_id(void)
{
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
@@ -297,9 +292,15 @@ static int ppc_check_control(struct perf
pmc_mask = 0;
pmi_mask = 0;
- memset(evntsel, 0, sizeof evntsel);
+ evntsel[1-1] = (state->control.mmcr0 >> (31-25)) & 0x7F;
+ evntsel[2-1] = (state->control.mmcr0 >> (31-31)) & 0x3F;
+ evntsel[3-1] = (state->control.mmcr1 >> (31- 4)) & 0x1F;
+ evntsel[4-1] = (state->control.mmcr1 >> (31- 9)) & 0x1F;
+ evntsel[5-1] = (state->control.mmcr1 >> (31-14)) & 0x1F;
+ evntsel[6-1] = (state->control.mmcr1 >> (31-20)) & 0x3F;
+
for(i = 0; i < nrctrs; ++i) {
- pmc = state->control.pmc[i].map;
+ pmc = state->control.pmc_map[i];
state->pmc[i].map = pmc;
if (pmc >= nr_pmcs || (pmc_mask & (1<<pmc)))
return -EINVAL;
@@ -308,11 +309,15 @@ static int ppc_check_control(struct perf
if (i >= nractrs)
pmi_mask |= (1<<pmc);
- evntsel[pmc] = state->control.pmc[i].evntsel;
if (evntsel[pmc] > pmc_max_event(pmc))
return -EINVAL;
}
+ /* unused event selectors must be zero */
+ for(i = 0; i < ARRAY_SIZE(evntsel); ++i)
+ if (!(pmc_mask & (1<<i)) && evntsel[i] != 0)
+ return -EINVAL;
+
/* XXX: temporary limitation */
if ((pmi_mask & ~1) && (pmi_mask & ~1) != (pmc_mask & ~1))
return -EINVAL;
@@ -320,30 +325,23 @@ static int ppc_check_control(struct perf
switch (pm_type) {
case PM_7450:
case PM_7400:
- if (state->control.ppc.mmcr2 & MMCR2_RESERVED)
+ if (state->control.mmcr2 & MMCR2_RESERVED)
return -EINVAL;
- state->ppc_mmcr[2] = state->control.ppc.mmcr2;
break;
default:
- if (state->control.ppc.mmcr2)
+ if (state->control.mmcr2)
return -EINVAL;
- state->ppc_mmcr[2] = 0;
}
+ /* check MMCR1; non-existent event selectors are taken care of
+ by the "unused event selectors must be zero" check above */
+ if (state->control.mmcr1 & MMCR1__RESERVED)
+ return -EINVAL;
+
/* We do not yet handle TBEE as the only exception cause,
so PMXE requires at least one interrupt-mode counter. */
- if ((state->control.ppc.mmcr0 & MMCR0_PMXE) && !state->control.nrictrs)
- return -EINVAL;
- if (state->control.ppc.mmcr0 & MMCR0_RESERVED)
+ if ((state->control.mmcr0 & MMCR0_PMXE) && !state->control.nrictrs)
return -EINVAL;
- state->ppc_mmcr[0] = (state->control.ppc.mmcr0
- | (evntsel[0] << (31-25))
- | (evntsel[1] << (31-31)));
-
- state->ppc_mmcr[1] = (( evntsel[2] << (31-4))
- | (evntsel[3] << (31-9))
- | (evntsel[4] << (31-14))
- | (evntsel[5] << (31-20)));
state->k1.id = new_id();
@@ -356,14 +354,14 @@ static int ppc_check_control(struct perf
switch (pm_type) {
case PM_7450:
case PM_7400:
- if (state->ppc_mmcr[0] & (MMCR0_FCECE | MMCR0_TRIGGER))
+ if (state->control.mmcr0 & (MMCR0_FCECE | MMCR0_TRIGGER))
state->cstatus = perfctr_cstatus_set_mmcr0_quirk(state->cstatus);
default:
;
}
/* The MMCR0 handling for FCECE and TRIGGER is also needed for PMXE. */
- if (state->ppc_mmcr[0] & (MMCR0_PMXE | MMCR0_FCECE | MMCR0_TRIGGER))
+ if (state->control.mmcr0 & (MMCR0_PMXE | MMCR0_FCECE | MMCR0_TRIGGER))
state->cstatus = perfctr_cstatus_set_mmcr0_quirk(state->cstatus);
return 0;
@@ -466,17 +464,17 @@ static void ppc_write_control(const stru
* cache and the state indicate the same value for it,
* preventing any actual mtspr to it. Ditto for MMCR1.
*/
- value = state->ppc_mmcr[2];
+ value = state->control.mmcr2;
if (value != cache->ppc_mmcr[2]) {
cache->ppc_mmcr[2] = value;
mtspr(SPRN_MMCR2, value);
}
- value = state->ppc_mmcr[1];
+ value = state->control.mmcr1;
if (value != cache->ppc_mmcr[1]) {
cache->ppc_mmcr[1] = value;
mtspr(SPRN_MMCR1, value);
}
- value = state->ppc_mmcr[0];
+ value = state->control.mmcr0;
if (value != cache->ppc_mmcr[0]) {
cache->ppc_mmcr[0] = value;
mtspr(SPRN_MMCR0, value);
@@ -546,7 +544,7 @@ static void perfctr_cpu_iresume(const st
bypass internal caching and force a reload if the I-mode PMCs. */
void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
{
- state->ppc_mmcr[0] |= MMCR0_PMXE;
+ state->control.mmcr0 |= MMCR0_PMXE;
#ifdef CONFIG_SMP
clear_isuspend_cpu(state);
#else
@@ -557,20 +555,20 @@ void perfctr_cpu_ireload(struct perfctr_
/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
{
- unsigned int cstatus, nrctrs, pmc, pmc_mask;
+ unsigned int cstatus, nrctrs, i, pmc_mask;
cstatus = state->cstatus;
- pmc = perfctr_cstatus_nractrs(cstatus);
nrctrs = perfctr_cstatus_nrctrs(cstatus);
-
- for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
- if ((int)state->pmc[pmc].start < 0) { /* PPC-specific */
+ pmc_mask = 0;
+ for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
+ if ((int)state->pmc[i].start < 0) { /* PPC-specific */
+ unsigned int pmc = state->pmc[i].map;
/* XXX: "+=" to correct for overshots */
- state->pmc[pmc].start = state->control.pmc[pmc].ireset;
- pmc_mask |= (1 << pmc);
+ state->pmc[i].start = state->control.ireset[pmc];
+ pmc_mask |= (1 << i);
}
}
- if (!pmc_mask && (state->ppc_mmcr[0] & MMCR0_TBEE))
+ if (!pmc_mask && (state->control.mmcr0 & MMCR0_TBEE))
pmc_mask = (1<<8); /* fake TB bit flip indicator */
return pmc_mask;
}
@@ -581,9 +579,11 @@ static inline int check_ireset(const str
i = state->control.nractrs;
nrctrs = i + state->control.nrictrs;
- for(; i < nrctrs; ++i)
- if (state->control.pmc[i].ireset < 0) /* PPC-specific */
+ for(; i < nrctrs; ++i) {
+ unsigned int pmc = state->pmc[i].map;
+ if ((int)state->control.ireset[pmc] < 0) /* PPC-specific */
return -EINVAL;
+ }
return 0;
}
@@ -593,8 +593,10 @@ static inline void setup_imode_start_val
cstatus = state->cstatus;
nrctrs = perfctr_cstatus_nrctrs(cstatus);
- for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
- state->pmc[i].start = state->control.pmc[i].ireset;
+ for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
+ unsigned int pmc = state->pmc[i].map;
+ state->pmc[i].start = state->control.ireset[pmc];
+ }
}
#else /* CONFIG_PERFCTR_INTERRUPT_SUPPORT */
@@ -621,10 +623,10 @@ int perfctr_cpu_update_control(struct pe
&& state->control.nrictrs)
return -EPERM;
- err = check_ireset(state);
+ err = check_control(state); /* may initialise state->cstatus */
if (err < 0)
return err;
- err = check_control(state); /* may initialise state->cstatus */
+ err = check_ireset(state);
if (err < 0)
return err;
state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on,
@@ -643,7 +645,7 @@ void perfctr_cpu_suspend(struct perfctr_
unsigned int mmcr0 = mfspr(SPRN_MMCR0);
mtspr(SPRN_MMCR0, mmcr0 | MMCR0_FC);
get_cpu_cache()->ppc_mmcr[0] = mmcr0 | MMCR0_FC;
- state->ppc_mmcr[0] = mmcr0;
+ state->control.mmcr0 = mmcr0;
}
if (perfctr_cstatus_has_ictrs(state->cstatus))
perfctr_cpu_isuspend(state);
diff -rupN linux-2.6.11-mm3/include/asm-ppc/perfctr.h linux-2.6.11-mm3.perfctr-physical-indexing/include/asm-ppc/perfctr.h
--- linux-2.6.11-mm3/include/asm-ppc/perfctr.h 2005-03-12 19:26:26.000000000 +0100
+++ linux-2.6.11-mm3.perfctr-physical-indexing/include/asm-ppc/perfctr.h 2005-03-12 19:55:49.000000000 +0100
@@ -23,20 +23,12 @@ struct perfctr_cpu_control {
unsigned int tsc_on;
unsigned int nractrs; /* # of a-mode counters */
unsigned int nrictrs; /* # of i-mode counters */
- struct {
- unsigned int mmcr0; /* sans PMC{1,2}SEL */
- unsigned int mmcr2; /* only THRESHMULT */
- /* IABR/DABR/BAMR not supported */
- } ppc;
- unsigned int _reserved1;
- unsigned int _reserved2;
- unsigned int _reserved3;
- unsigned int _reserved4;
- struct {
- unsigned int map; /* physical counter to use */
- unsigned int evntsel;
- int ireset; /* [0,0x7fffffff], for i-mode counters */
- } pmc[8];
+ unsigned int mmcr0;
+ unsigned int mmcr1;
+ unsigned int mmcr2;
+ /* IABR/DABR/BAMR not supported */
+ unsigned int ireset[8]; /* [0,0x7fffffff], for i-mode counters, physical indices */
+ unsigned int pmc_map[8]; /* virtual to physical index map */
};
struct perfctr_cpu_state {
@@ -55,7 +47,6 @@ struct perfctr_cpu_state {
unsigned long long sum;
} pmc[8]; /* the size is not part of the user ABI */
#ifdef __KERNEL__
- unsigned int ppc_mmcr[3];
struct perfctr_cpu_control control;
#endif
};
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-03-12 23:21 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-12 23:18 [PATCH][2.6.11-mm3] perfctr API update 2/9: physical indexing, ppc32 Mikael Pettersson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.