1/* sysfs.c: Toplogy sysfs support code for sparc64. 2 * 3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net> 4 */ 5#include <linux/sysdev.h> 6#include <linux/cpu.h> 7#include <linux/smp.h> 8#include <linux/percpu.h> 9#include <linux/init.h> 10 11#include <asm/hypervisor.h> 12#include <asm/spitfire.h> 13 14static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); 15 16#define SHOW_MMUSTAT_ULONG(NAME) \ 17static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ 18{ \ 19 struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ 20 return sprintf(buf, "%lu\n", p->NAME); \ 21} \ 22static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) 23 24SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); 25SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); 26SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); 27SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); 28SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); 29SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); 30SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); 31SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); 32SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); 33SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); 34SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); 35SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); 36SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); 37SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); 38SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); 39SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); 40SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); 41SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); 42SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); 43SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); 44SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); 45SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); 46SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); 47SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); 48SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); 49SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); 50SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); 51SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); 52SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); 53SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); 54SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); 55SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); 56 57static struct attribute *mmu_stat_attrs[] = { 58 &attr_immu_tsb_hits_ctx0_8k_tte.attr, 59 &attr_immu_tsb_ticks_ctx0_8k_tte.attr, 60 &attr_immu_tsb_hits_ctx0_64k_tte.attr, 61 &attr_immu_tsb_ticks_ctx0_64k_tte.attr, 62 &attr_immu_tsb_hits_ctx0_4mb_tte.attr, 63 &attr_immu_tsb_ticks_ctx0_4mb_tte.attr, 64 &attr_immu_tsb_hits_ctx0_256mb_tte.attr, 65 &attr_immu_tsb_ticks_ctx0_256mb_tte.attr, 66 &attr_immu_tsb_hits_ctxnon0_8k_tte.attr, 67 &attr_immu_tsb_ticks_ctxnon0_8k_tte.attr, 68 &attr_immu_tsb_hits_ctxnon0_64k_tte.attr, 69 &attr_immu_tsb_ticks_ctxnon0_64k_tte.attr, 70 &attr_immu_tsb_hits_ctxnon0_4mb_tte.attr, 71 &attr_immu_tsb_ticks_ctxnon0_4mb_tte.attr, 72 &attr_immu_tsb_hits_ctxnon0_256mb_tte.attr, 73 &attr_immu_tsb_ticks_ctxnon0_256mb_tte.attr, 74 &attr_dmmu_tsb_hits_ctx0_8k_tte.attr, 75 &attr_dmmu_tsb_ticks_ctx0_8k_tte.attr, 76 &attr_dmmu_tsb_hits_ctx0_64k_tte.attr, 77 &attr_dmmu_tsb_ticks_ctx0_64k_tte.attr, 78 &attr_dmmu_tsb_hits_ctx0_4mb_tte.attr, 79 &attr_dmmu_tsb_ticks_ctx0_4mb_tte.attr, 80 &attr_dmmu_tsb_hits_ctx0_256mb_tte.attr, 81 &attr_dmmu_tsb_ticks_ctx0_256mb_tte.attr, 82 &attr_dmmu_tsb_hits_ctxnon0_8k_tte.attr, 83 &attr_dmmu_tsb_ticks_ctxnon0_8k_tte.attr, 84 &attr_dmmu_tsb_hits_ctxnon0_64k_tte.attr, 85 &attr_dmmu_tsb_ticks_ctxnon0_64k_tte.attr, 86 &attr_dmmu_tsb_hits_ctxnon0_4mb_tte.attr, 87 &attr_dmmu_tsb_ticks_ctxnon0_4mb_tte.attr, 88 &attr_dmmu_tsb_hits_ctxnon0_256mb_tte.attr, 89 &attr_dmmu_tsb_ticks_ctxnon0_256mb_tte.attr, 90 NULL, 91}; 92 93static struct attribute_group mmu_stat_group = { 94 .attrs = mmu_stat_attrs, 95 .name = "mmu_stats", 96}; 97 98static unsigned long run_on_cpu(unsigned long cpu, 99 unsigned long (*func)(unsigned long), 100 unsigned long arg) 101{ 102 cpumask_t old_affinity = current->cpus_allowed; 103 unsigned long ret; 104 105 /* should return -EINVAL to userspace */ 106 if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) 107 return 0; 108 109 ret = func(arg); 110 111 set_cpus_allowed(current, old_affinity); 112 113 return ret; 114} 115 116static unsigned long read_mmustat_enable(unsigned long junk) 117{ 118 unsigned long ra = 0; 119 120 sun4v_mmustat_info(&ra); 121 122 return ra != 0; 123} 124 125static unsigned long write_mmustat_enable(unsigned long val) 126{ 127 unsigned long ra, orig_ra; 128 129 if (val) 130 ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); 131 else 132 ra = 0UL; 133 134 return sun4v_mmustat_conf(ra, &orig_ra); 135} 136 137static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) 138{ 139 unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); 140 return sprintf(buf, "%lx\n", val); 141} 142 143static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) 144{ 145 unsigned long val, err; 146 int ret = sscanf(buf, "%ld", &val); 147 148 if (ret != 1) 149 return -EINVAL; 150 151 err = run_on_cpu(s->id, write_mmustat_enable, val); 152 if (err) 153 return -EIO; 154 155 return count; 156} 157 158static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); 159 160static int mmu_stats_supported; 161 162static int register_mmu_stats(struct sys_device *s) 163{ 164 if (!mmu_stats_supported) 165 return 0; 166 sysdev_create_file(s, &attr_mmustat_enable); 167 return sysfs_create_group(&s->kobj, &mmu_stat_group); 168} 169 170#ifdef CONFIG_HOTPLUG_CPU 171static void unregister_mmu_stats(struct sys_device *s) 172{ 173 if (!mmu_stats_supported) 174 return; 175 sysfs_remove_group(&s->kobj, &mmu_stat_group); 176 sysdev_remove_file(s, &attr_mmustat_enable); 177} 178#endif 179 180#define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ 181static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ 182{ \ 183 cpuinfo_sparc *c = &cpu_data(dev->id); \ 184 return sprintf(buf, "%lu\n", c->MEMBER); \ 185} 186 187#define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ 188static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ 189{ \ 190 cpuinfo_sparc *c = &cpu_data(dev->id); \ 191 return sprintf(buf, "%u\n", c->MEMBER); \ 192} 193 194SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); 195SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); 196SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); 197SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); 198SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); 199SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); 200SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); 201SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); 202 203static struct sysdev_attribute cpu_core_attrs[] = { 204 _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), 205 _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL), 206 _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), 207 _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), 208 _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), 209 _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), 210 _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), 211 _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), 212}; 213 214static DEFINE_PER_CPU(struct cpu, cpu_devices); 215 216static void register_cpu_online(unsigned int cpu) 217{ 218 struct cpu *c = &per_cpu(cpu_devices, cpu); 219 struct sys_device *s = &c->sysdev; 220 int i; 221 222 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 223 sysdev_create_file(s, &cpu_core_attrs[i]); 224 225 register_mmu_stats(s); 226} 227 228#ifdef CONFIG_HOTPLUG_CPU 229static void unregister_cpu_online(unsigned int cpu) 230{ 231 struct cpu *c = &per_cpu(cpu_devices, cpu); 232 struct sys_device *s = &c->sysdev; 233 int i; 234 235 unregister_mmu_stats(s); 236 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 237 sysdev_remove_file(s, &cpu_core_attrs[i]); 238} 239#endif 240 241static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, 242 unsigned long action, void *hcpu) 243{ 244 unsigned int cpu = (unsigned int)(long)hcpu; 245 246 switch (action) { 247 case CPU_ONLINE: 248 case CPU_ONLINE_FROZEN: 249 register_cpu_online(cpu); 250 break; 251#ifdef CONFIG_HOTPLUG_CPU 252 case CPU_DEAD: 253 case CPU_DEAD_FROZEN: 254 unregister_cpu_online(cpu); 255 break; 256#endif 257 } 258 return NOTIFY_OK; 259} 260 261static struct notifier_block __cpuinitdata sysfs_cpu_nb = { 262 .notifier_call = sysfs_cpu_notify, 263}; 264 265static void __init check_mmu_stats(void) 266{ 267 unsigned long dummy1, err; 268 269 if (tlb_type != hypervisor) 270 return; 271 272 err = sun4v_mmustat_info(&dummy1); 273 if (!err) 274 mmu_stats_supported = 1; 275} 276 277static int __init topology_init(void) 278{ 279 int cpu; 280 281 check_mmu_stats(); 282 283 register_cpu_notifier(&sysfs_cpu_nb); 284 285 for_each_possible_cpu(cpu) { 286 struct cpu *c = &per_cpu(cpu_devices, cpu); 287 288 register_cpu(c, cpu); 289 if (cpu_online(cpu)) 290 register_cpu_online(cpu); 291 } 292 293 return 0; 294} 295 296subsys_initcall(topology_init); 297