"Gautham R. Shenoy" <e...@linux.vnet.ibm.com> writes: > diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c > index 80a676d..5b4b450 100644 > --- a/arch/powerpc/kernel/sysfs.c > +++ b/arch/powerpc/kernel/sysfs.c > @@ -19,6 +19,7 @@ > #include <asm/smp.h> > #include <asm/pmc.h> > #include <asm/firmware.h> > +#include <asm/idle.h> > #include <asm/svm.h> > > #include "cacheinfo.h" > @@ -733,6 +734,42 @@ static void create_svm_file(void) > } > #endif /* CONFIG_PPC_SVM */ > > +static void read_idle_purr(void *val) > +{ > + u64 *ret = (u64 *)val;
No cast from void* needed. > + > + *ret = read_this_idle_purr(); > +} > + > +static ssize_t idle_purr_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct cpu *cpu = container_of(dev, struct cpu, dev); > + u64 val; > + > + smp_call_function_single(cpu->dev.id, read_idle_purr, &val, 1); > + return sprintf(buf, "%llx\n", val); > +} > +static DEVICE_ATTR(idle_purr, 0400, idle_purr_show, NULL); > + > +static void read_idle_spurr(void *val) > +{ > + u64 *ret = (u64 *)val; > + > + *ret = read_this_idle_spurr(); > +} > + > +static ssize_t idle_spurr_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct cpu *cpu = container_of(dev, struct cpu, dev); > + u64 val; > + > + smp_call_function_single(cpu->dev.id, read_idle_spurr, &val, 1); > + return sprintf(buf, "%llx\n", val); > +} > +static DEVICE_ATTR(idle_spurr, 0400, idle_spurr_show, NULL); It's regrettable that we have to wake up potentially idle CPUs in order to derive correct idle statistics for them, but I suppose the main user (lparstat) of these interfaces already is causing this to happen by polling the existing per-cpu purr and spurr attributes. So now lparstat will incur at minimum four syscalls and four IPIs per CPU per polling interval -- one for each of purr, spurr, idle_purr and idle_spurr. Correct? At some point it's going to make sense to batch sampling of remote CPUs' SPRs. > static int register_cpu_online(unsigned int cpu) > { > struct cpu *c = &per_cpu(cpu_devices, cpu); > @@ -794,10 +831,15 @@ static int register_cpu_online(unsigned int cpu) > if (!firmware_has_feature(FW_FEATURE_LPAR)) > add_write_permission_dev_attr(&dev_attr_purr); > device_create_file(s, &dev_attr_purr); > + if (firmware_has_feature(FW_FEATURE_LPAR)) > + device_create_file(s, &dev_attr_idle_purr); > } > > - if (cpu_has_feature(CPU_FTR_SPURR)) > + if (cpu_has_feature(CPU_FTR_SPURR)) { > device_create_file(s, &dev_attr_spurr); > + if (firmware_has_feature(FW_FEATURE_LPAR)) > + device_create_file(s, &dev_attr_idle_spurr); > + } > > if (cpu_has_feature(CPU_FTR_DSCR)) > device_create_file(s, &dev_attr_dscr); > @@ -879,11 +921,17 @@ static int unregister_cpu_online(unsigned int cpu) > if (cpu_has_feature(CPU_FTR_MMCRA)) > device_remove_file(s, &dev_attr_mmcra); > > - if (cpu_has_feature(CPU_FTR_PURR)) > + if (cpu_has_feature(CPU_FTR_PURR)) { > device_remove_file(s, &dev_attr_purr); > + if (firmware_has_feature(FW_FEATURE_LPAR)) > + device_remove_file(s, &dev_attr_idle_purr); > + } > > - if (cpu_has_feature(CPU_FTR_SPURR)) > + if (cpu_has_feature(CPU_FTR_SPURR)) { > device_remove_file(s, &dev_attr_spurr); > + if (firmware_has_feature(FW_FEATURE_LPAR)) > + device_remove_file(s, &dev_attr_idle_spurr); > + } > > if (cpu_has_feature(CPU_FTR_DSCR)) > device_remove_file(s, &dev_attr_dscr); The cpu register/unregister stuff here looks correct.