From: Mikael Pettersson This patch updates the performance-monitoring counters extensions' ppc32 low-level driver as follows: - Replace ugly /proc/cpuinfo parsing code (for detecting core clock frequency) with code that asks Open Firmware instead. This way we also get the important timebase frequency. - Using new OF interface, detect and support generic chips having a timebase register. This is useful because that's enough for user-space to implement hrvtime(). - Using new OF interface, finally be able to derive the correct timebase-to-core multiplier on old 604 (not 604e) chips. - Avoid having to do partial processor detection in ppc_tests.c. - Some code cleanups. Signed-off-by: Mikael Pettersson Signed-off-by: Andrew Morton --- 25-akpm/drivers/perfctr/ppc.c | 153 +++++++++++++++--------------------- 25-akpm/drivers/perfctr/ppc_tests.c | 4 25-akpm/drivers/perfctr/ppc_tests.h | 4 25-akpm/include/asm-ppc/perfctr.h | 1 4 files changed, 71 insertions(+), 91 deletions(-) diff -puN drivers/perfctr/ppc.c~perfctr-ppc32-update drivers/perfctr/ppc.c --- 25/drivers/perfctr/ppc.c~perfctr-ppc32-update 2004-06-21 23:19:22.751668320 -0700 +++ 25-akpm/drivers/perfctr/ppc.c 2004-06-21 23:19:22.762666648 -0700 @@ -8,8 +8,7 @@ #include #include #include -#include -#include +#include #include /* tb_ticks_per_jiffy, get_tbl() */ #include "ppc_tests.h" @@ -23,6 +22,7 @@ struct per_cpu_cache { /* roughly a subs unsigned int ppc_mmcr[3]; } ____cacheline_aligned; static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache); +#define get_cpu_cache() __get_cpu_var(per_cpu_cache) /* Structure for counter snapshots, as 32-bit values. */ struct perfctr_low_ctrs { @@ -31,11 +31,12 @@ struct perfctr_low_ctrs { }; enum pm_type { - PM_604, - PM_604e, - PM_750, /* XXX: Minor event set diffs between IBM and Moto. */ - PM_7400, - PM_7450, + PM_NONE, + PM_604, + PM_604e, + PM_750, /* XXX: Minor event set diffs between IBM and Moto. */ + PM_7400, + PM_7450, }; static enum pm_type pm_type; @@ -244,7 +245,7 @@ static void ppc_read_counters(/*const*/ if (state->cstatus & (1<<30)) { unsigned int mmcr0 = mfspr(SPRN_MMCR0); state->ppc_mmcr[0] = mmcr0; - __get_cpu_var(per_cpu_cache).ppc_mmcr[0] = mmcr0; + get_cpu_cache().ppc_mmcr[0] = mmcr0; } } @@ -276,9 +277,10 @@ static unsigned int get_nr_pmcs(void) case PM_750: case PM_604e: return 4; - default: /* impossible, but silences gcc warning */ case PM_604: return 2; + default: /* PM_NONE, but silences gcc warning */ + return 0; } } @@ -365,7 +367,7 @@ static void ppc_write_control(const stru struct per_cpu_cache *cache; unsigned int value; - cache = &__get_cpu_var(per_cpu_cache); + cache = &get_cpu_cache(); if (cache->k1.id == state->k1.id) return; /* @@ -411,6 +413,8 @@ static void ppc_clear_counters(void) mtspr(SPRN_MMCR1, 0); case PM_604: mtspr(SPRN_MMCR0, 0); + case PM_NONE: + ; } switch (pm_type) { case PM_7450: @@ -424,6 +428,8 @@ static void ppc_clear_counters(void) case PM_604: mtspr(SPRN_PMC2, 0); mtspr(SPRN_PMC1, 0); + case PM_NONE: + ; } } @@ -460,7 +466,7 @@ void perfctr_cpu_ireload(struct perfctr_ #ifdef CONFIG_SMP clear_isuspend_cpu(state); #else - __get_cpu_var(per_cpu_cache).k1.id = 0; + get_cpu_cache().k1.id = 0; #endif } @@ -603,7 +609,7 @@ static void perfctr_cpu_clear_counters(v { struct per_cpu_cache *cache; - cache = &__get_cpu_var(per_cpu_cache); + cache = &get_cpu_cache(); memset(cache, 0, sizeof *cache); cache->k1.id = -1; @@ -715,8 +721,7 @@ static unsigned int __init tb_to_core_ra pll_cfg = (hid1 >> shift) & mask; ratio = cfg_ratio[pll_cfg]; if (!ratio) - printk(KERN_WARNING "perfctr/%s: unknown PLL_CFG 0x%x\n", - __FILE__, pll_cfg); + printk(KERN_WARNING "perfctr: unknown PLL_CFG 0x%x\n", pll_cfg); return (4/2) * ratio; } @@ -727,102 +732,59 @@ static unsigned int __init pll_to_core_k return tb_ticks_per_jiffy * tb_to_core * (HZ/10) / (1000/10); } -/* Extract the CPU clock frequency from /proc/cpuinfo. */ +/* Extract core and timebase frequencies from Open Firmware. */ -static unsigned int __init parse_clock_khz(struct seq_file *m) +static unsigned int __init of_to_core_khz(void) { - /* "/proc/cpuinfo" formats: - * - * "core clock\t: %d MHz\n" // 8260 (show_percpuinfo) - * "clock\t\t: %ldMHz\n" // 4xx (show_percpuinfo) - * "clock\t\t: %dMHz\n" // oak (show_percpuinfo) - * "clock\t\t: %ldMHz\n" // prep (show_percpuinfo) - * "clock\t\t: %dMHz\n" // pmac (show_percpuinfo) - * "clock\t\t: %dMHz\n" // gemini (show_cpuinfo!) - */ - char *p; - unsigned int mhz; + struct device_node *cpu; + unsigned int *fp, core, tb; - p = m->buf; - p[m->count] = '\0'; - - for(;;) { /* for each line */ - if (strncmp(p, "core ", 5) == 0) - p += 5; - do { - if (strncmp(p, "clock\t", 6) != 0) - break; - p += 6; - while (*p == '\t') - ++p; - if (*p != ':') - break; - do { - ++p; - } while (*p == ' '); - mhz = simple_strtoul(p, 0, 10); - if (mhz) - return mhz * 1000; - } while (0); - for(;;) { /* skip to next line */ - switch (*p++) { - case '\n': - break; - case '\0': - return 0; - default: - continue; - } - break; - } - } + cpu = find_type_devices("cpu"); + if (!cpu) + return 0; + fp = (unsigned int*)get_property(cpu, "clock-frequency", NULL); + if (!fp || !(core = *fp)) + return 0; + fp = (unsigned int*)get_property(cpu, "timebase-frequency", NULL); + if (!fp || !(tb = *fp)) + return 0; + perfctr_info.tsc_to_cpu_mult = core / tb; + return core / 1000; } static unsigned int __init detect_cpu_khz(enum pll_type pll_type) { - char buf[512]; - struct seq_file m; unsigned int khz; khz = pll_to_core_khz(pll_type); if (khz) return khz; - memset(&m, 0, sizeof m); - m.buf = buf; - m.size = (sizeof buf)-1; - - m.count = 0; - if (ppc_md.show_percpuinfo != 0 && - ppc_md.show_percpuinfo(&m, 0) == 0 && - (khz = parse_clock_khz(&m)) != 0) - return khz; - - m.count = 0; - if (ppc_md.show_cpuinfo != 0 && - ppc_md.show_cpuinfo(&m) == 0 && - (khz = parse_clock_khz(&m)) != 0) + khz = of_to_core_khz(); + if (khz) return khz; - printk(KERN_WARNING "perfctr/%s: unable to determine CPU speed\n", - __FILE__); + printk(KERN_WARNING "perfctr: unable to determine CPU speed\n"); return 0; } -static int __init generic_init(void) +static int __init known_init(void) { - static char generic_name[] __initdata = "PowerPC 60x/7xx/74xx"; + static char known_name[] __initdata = "PowerPC 60x/7xx/74xx"; unsigned int features; enum pll_type pll_type; unsigned int pvr; + int have_mmcr1; features = PERFCTR_FEATURE_RDTSC | PERFCTR_FEATURE_RDPMC; + have_mmcr1 = 1; pvr = mfspr(SPRN_PVR); switch (PVR_VER(pvr)) { case 0x0004: /* 604 */ pm_type = PM_604; pll_type = PLL_NONE; features = PERFCTR_FEATURE_RDTSC; + have_mmcr1 = 0; break; case 0x0009: /* 604e; */ case 0x000A: /* 604ev */ @@ -860,15 +822,29 @@ static int __init generic_init(void) pll_type = PLL_7457; break; default: - printk(KERN_WARNING "perfctr/%s: unknown PowerPC with " - "PVR 0x%08x -- bailing out\n", __FILE__, pvr); return -ENODEV; } perfctr_info.cpu_features = features; perfctr_info.cpu_type = 0; /* user-space should inspect PVR */ - perfctr_cpu_name = generic_name; + perfctr_cpu_name = known_name; perfctr_info.cpu_khz = detect_cpu_khz(pll_type); - perfctr_ppc_init_tests(); + perfctr_ppc_init_tests(have_mmcr1); + return 0; +} + +static int __init unknown_init(void) +{ + static char unknown_name[] __initdata = "Generic PowerPC with TB"; + unsigned int khz; + + khz = detect_cpu_khz(PLL_NONE); + if (!khz) + return -ENODEV; + perfctr_info.cpu_features = PERFCTR_FEATURE_RDTSC; + perfctr_info.cpu_type = 0; + perfctr_cpu_name = unknown_name; + perfctr_info.cpu_khz = khz; + pm_type = PM_NONE; return 0; } @@ -896,9 +872,12 @@ int __init perfctr_cpu_init(void) perfctr_info.cpu_features = 0; - err = generic_init(); - if (err) - goto out; + err = known_init(); + if (err) { + err = unknown_init(); + if (err) + goto out; + } perfctr_cpu_init_one(NULL); smp_call_function(perfctr_cpu_init_one, NULL, 1, 1); diff -puN drivers/perfctr/ppc_tests.c~perfctr-ppc32-update drivers/perfctr/ppc_tests.c --- 25/drivers/perfctr/ppc_tests.c~perfctr-ppc32-update 2004-06-21 23:19:22.753668016 -0700 +++ 25-akpm/drivers/perfctr/ppc_tests.c 2004-06-21 23:19:22.762666648 -0700 @@ -280,7 +280,7 @@ measure_overheads(int have_mmcr1) check_trigger(1); } -void __init perfctr_ppc_init_tests(void) +void __init perfctr_ppc_init_tests(int have_mmcr1) { - measure_overheads(PVR_VER(mfspr(SPRN_PVR)) != 0x0004); + measure_overheads(have_mmcr1); } diff -puN drivers/perfctr/ppc_tests.h~perfctr-ppc32-update drivers/perfctr/ppc_tests.h --- 25/drivers/perfctr/ppc_tests.h~perfctr-ppc32-update 2004-06-21 23:19:22.754667864 -0700 +++ 25-akpm/drivers/perfctr/ppc_tests.h 2004-06-21 23:19:22.763666496 -0700 @@ -6,7 +6,7 @@ */ #ifdef CONFIG_PERFCTR_INIT_TESTS -extern void perfctr_ppc_init_tests(void); +extern void perfctr_ppc_init_tests(int have_mmcr1); #else -#define perfctr_ppc_init_tests() +static inline void perfctr_ppc_init_tests(int have_mmcr1) { } #endif diff -puN include/asm-ppc/perfctr.h~perfctr-ppc32-update include/asm-ppc/perfctr.h --- 25/include/asm-ppc/perfctr.h~perfctr-ppc32-update 2004-06-21 23:19:22.756667560 -0700 +++ 25-akpm/include/asm-ppc/perfctr.h 2004-06-21 23:19:22.764666344 -0700 @@ -7,6 +7,7 @@ #define _ASM_PPC_PERFCTR_H /* perfctr_info.cpu_type values */ +#define PERFCTR_PPC_GENERIC 0 #define PERFCTR_PPC_604 1 #define PERFCTR_PPC_604e 2 #define PERFCTR_PPC_750 3 _