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