Subject: User-space access to bookmark registers. From: Kevin Corry Add the files /sys/devices/system/cpu/cpu*/pmu_bookmark to provide user-space with a method for writing to the bookmark registers in the Cell processor. Writes to these registers can be used by the performance monitoring unit to generate trace data and to trigger the starting and stopping of the hardware performance counters. This renames the existing cbe_init_pm_irq() routine to cbe_init_pmu(), and adds the initialization of these new sysfs files to that init routine. This also patches the smp_call_function_single() routine to match the recent change in mainline, which allows calling the routine with the current CPU as the target. See linux-2.6.git commit adff093d6c545c882f1503607f6af14ddd90bb89. Signed-off-by: Kevin Corry Signed-off-by: Arnd Bergmann Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c =================================================================== --- linux-2.6.orig/arch/powerpc/platforms/cell/pmu.c +++ linux-2.6/arch/powerpc/platforms/cell/pmu.c @@ -22,6 +22,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -376,7 +377,61 @@ static irqreturn_t cbe_pm_irq(int irq, v return IRQ_HANDLED; } -static int __init cbe_init_pm_irq(void) +/* + * Provide files in sysfs to allow user-space to access the bookmark registers. + * The sysfs files are /sys/devices/system/cpu/cpu?/pmu_bookmark. The registers + * are write only, so we'll provide "shadow" values so user-space can read the + * values as well. + */ + +static DEFINE_PER_CPU(u64, pmu_bookmark); + +static void read_bookmark(void *data) +{ + u64 *val = data; + *val = __get_cpu_var(pmu_bookmark); +} + +static ssize_t cbe_show_pmu_bookmark(struct sys_device *dev, char *buf) +{ + int rc, cpu = dev->id; + u64 val; + + rc = smp_call_function_single(cpu, read_bookmark, &val, 0, 1); + if (rc) + return rc; + + return sprintf(buf, "%lu\n", val); +} + +static void write_bookmark(void *data) +{ + u64 *val = data; + __get_cpu_var(pmu_bookmark) = *val; + mtspr(SPRN_BKMK, *val); +} + +static ssize_t cbe_store_pmu_bookmark(struct sys_device *dev, + const char *buf, size_t count) +{ + int rc, cpu = dev->id; + u64 val; + + rc = sscanf(buf, "%lu", &val); + if (rc != 1) + return -EINVAL; + + rc = smp_call_function_single(cpu, write_bookmark, &val, 0, 1); + if (rc) + return rc; + + return count; +} + +static SYSDEV_ATTR(pmu_bookmark, 0600, + cbe_show_pmu_bookmark, cbe_store_pmu_bookmark); + +static int __init cbe_init_pmu(void) { unsigned int irq; int rc, node; @@ -402,9 +457,9 @@ static int __init cbe_init_pm_irq(void) } } - return 0; + return cpu_add_sysdev_attr(&attr_pmu_bookmark); } -arch_initcall(cbe_init_pm_irq); +__initcall(cbe_init_pmu); void cbe_sync_irq(int node) { Index: linux-2.6/include/asm-powerpc/reg.h =================================================================== --- linux-2.6.orig/include/asm-powerpc/reg.h +++ linux-2.6/include/asm-powerpc/reg.h @@ -427,6 +427,8 @@ #define SPRN_SCOMC 0x114 /* SCOM Access Control */ #define SPRN_SCOMD 0x115 /* SCOM Access DATA */ +#define SPRN_BKMK 1020 /* Cell Bookmark Register */ + /* Performance monitor SPRs */ #ifdef CONFIG_PPC64 #define SPRN_MMCR0 795 Index: linux-2.6/arch/powerpc/kernel/smp.c =================================================================== --- linux-2.6.orig/arch/powerpc/kernel/smp.c +++ linux-2.6/arch/powerpc/kernel/smp.c @@ -284,7 +284,7 @@ int smp_call_function_single(int cpu, vo int wait) { cpumask_t map = CPU_MASK_NONE; - int ret = -EBUSY; + int ret = 0; if (!cpu_online(cpu)) return -EINVAL; @@ -292,6 +292,11 @@ int smp_call_function_single(int cpu, vo cpu_set(cpu, map); if (cpu != get_cpu()) ret = smp_call_function_map(func,info,nonatomic,wait,map); + else { + local_irq_disable(); + func(info); + local_irq_enable(); + } put_cpu(); return ret; }