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 16 static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); 17 18 #define SHOW_MMUSTAT_ULONG(NAME) \ 19 static 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 } \ 25 static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) 26 27 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); 28 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); 29 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); 30 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); 31 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); 32 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); 33 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); 34 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); 35 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); 36 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); 37 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); 38 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); 39 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); 40 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); 41 SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); 42 SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); 43 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); 44 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); 45 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); 46 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); 47 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); 48 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); 49 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); 50 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); 51 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); 52 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); 53 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); 54 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); 55 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); 56 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); 57 SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); 58 SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); 59 60 static 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 96 static struct attribute_group mmu_stat_group = { 97 .attrs = mmu_stat_attrs, 98 .name = "mmu_stats", 99 }; 100 101 /* XXX convert to rusty's on_one_cpu */ 102 static unsigned long run_on_cpu(unsigned long cpu, 103 unsigned long (*func)(unsigned long), 104 unsigned long arg) 105 { 106 cpumask_t old_affinity = current->cpus_allowed; 107 unsigned long ret; 108 109 /* should return -EINVAL to userspace */ 110 if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) 111 return 0; 112 113 ret = func(arg); 114 115 set_cpus_allowed_ptr(current, &old_affinity); 116 117 return ret; 118 } 119 120 static unsigned long read_mmustat_enable(unsigned long junk) 121 { 122 unsigned long ra = 0; 123 124 sun4v_mmustat_info(&ra); 125 126 return ra != 0; 127 } 128 129 static unsigned long write_mmustat_enable(unsigned long val) 130 { 131 unsigned long ra, orig_ra; 132 133 if (val) 134 ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); 135 else 136 ra = 0UL; 137 138 return sun4v_mmustat_conf(ra, &orig_ra); 139 } 140 141 static ssize_t show_mmustat_enable(struct sys_device *s, 142 struct sysdev_attribute *attr, char *buf) 143 { 144 unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); 145 return sprintf(buf, "%lx\n", val); 146 } 147 148 static ssize_t store_mmustat_enable(struct sys_device *s, 149 struct sysdev_attribute *attr, const char *buf, 150 size_t count) 151 { 152 unsigned long val, err; 153 int ret = sscanf(buf, "%ld", &val); 154 155 if (ret != 1) 156 return -EINVAL; 157 158 err = run_on_cpu(s->id, write_mmustat_enable, val); 159 if (err) 160 return -EIO; 161 162 return count; 163 } 164 165 static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); 166 167 static int mmu_stats_supported; 168 169 static int register_mmu_stats(struct sys_device *s) 170 { 171 if (!mmu_stats_supported) 172 return 0; 173 sysdev_create_file(s, &attr_mmustat_enable); 174 return sysfs_create_group(&s->kobj, &mmu_stat_group); 175 } 176 177 #ifdef CONFIG_HOTPLUG_CPU 178 static void unregister_mmu_stats(struct sys_device *s) 179 { 180 if (!mmu_stats_supported) 181 return; 182 sysfs_remove_group(&s->kobj, &mmu_stat_group); 183 sysdev_remove_file(s, &attr_mmustat_enable); 184 } 185 #endif 186 187 #define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ 188 static ssize_t show_##NAME(struct sys_device *dev, \ 189 struct sysdev_attribute *attr, char *buf) \ 190 { \ 191 cpuinfo_sparc *c = &cpu_data(dev->id); \ 192 return sprintf(buf, "%lu\n", c->MEMBER); \ 193 } 194 195 #define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ 196 static ssize_t show_##NAME(struct sys_device *dev, \ 197 struct sysdev_attribute *attr, char *buf) \ 198 { \ 199 cpuinfo_sparc *c = &cpu_data(dev->id); \ 200 return sprintf(buf, "%u\n", c->MEMBER); \ 201 } 202 203 SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); 204 SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); 205 SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); 206 SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); 207 SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); 208 SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); 209 SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); 210 211 static struct sysdev_attribute cpu_core_attrs[] = { 212 _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), 213 _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), 214 _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), 215 _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), 216 _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), 217 _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), 218 _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), 219 }; 220 221 static DEFINE_PER_CPU(struct cpu, cpu_devices); 222 223 static void register_cpu_online(unsigned int cpu) 224 { 225 struct cpu *c = &per_cpu(cpu_devices, cpu); 226 struct sys_device *s = &c->sysdev; 227 int i; 228 229 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 230 sysdev_create_file(s, &cpu_core_attrs[i]); 231 232 register_mmu_stats(s); 233 } 234 235 #ifdef CONFIG_HOTPLUG_CPU 236 static void unregister_cpu_online(unsigned int cpu) 237 { 238 struct cpu *c = &per_cpu(cpu_devices, cpu); 239 struct sys_device *s = &c->sysdev; 240 int i; 241 242 unregister_mmu_stats(s); 243 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 244 sysdev_remove_file(s, &cpu_core_attrs[i]); 245 } 246 #endif 247 248 static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, 249 unsigned long action, void *hcpu) 250 { 251 unsigned int cpu = (unsigned int)(long)hcpu; 252 253 switch (action) { 254 case CPU_ONLINE: 255 case CPU_ONLINE_FROZEN: 256 register_cpu_online(cpu); 257 break; 258 #ifdef CONFIG_HOTPLUG_CPU 259 case CPU_DEAD: 260 case CPU_DEAD_FROZEN: 261 unregister_cpu_online(cpu); 262 break; 263 #endif 264 } 265 return NOTIFY_OK; 266 } 267 268 static struct notifier_block __cpuinitdata sysfs_cpu_nb = { 269 .notifier_call = sysfs_cpu_notify, 270 }; 271 272 static void __init check_mmu_stats(void) 273 { 274 unsigned long dummy1, err; 275 276 if (tlb_type != hypervisor) 277 return; 278 279 err = sun4v_mmustat_info(&dummy1); 280 if (!err) 281 mmu_stats_supported = 1; 282 } 283 284 static void register_nodes(void) 285 { 286 #ifdef CONFIG_NUMA 287 int i; 288 289 for (i = 0; i < MAX_NUMNODES; i++) 290 register_one_node(i); 291 #endif 292 } 293 294 static int __init topology_init(void) 295 { 296 int cpu; 297 298 register_nodes(); 299 300 check_mmu_stats(); 301 302 register_cpu_notifier(&sysfs_cpu_nb); 303 304 for_each_possible_cpu(cpu) { 305 struct cpu *c = &per_cpu(cpu_devices, cpu); 306 307 register_cpu(c, cpu); 308 if (cpu_online(cpu)) 309 register_cpu_online(cpu); 310 } 311 312 return 0; 313 } 314 315 subsys_initcall(topology_init); 316