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; 107 unsigned long ret; 108 109 cpumask_copy(&old_affinity, tsk_cpus_allowed(current)); 110 /* should return -EINVAL to userspace */ 111 if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) 112 return 0; 113 114 ret = func(arg); 115 116 set_cpus_allowed_ptr(current, &old_affinity); 117 118 return ret; 119 } 120 121 static unsigned long read_mmustat_enable(unsigned long junk) 122 { 123 unsigned long ra = 0; 124 125 sun4v_mmustat_info(&ra); 126 127 return ra != 0; 128 } 129 130 static unsigned long write_mmustat_enable(unsigned long val) 131 { 132 unsigned long ra, orig_ra; 133 134 if (val) 135 ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); 136 else 137 ra = 0UL; 138 139 return sun4v_mmustat_conf(ra, &orig_ra); 140 } 141 142 static ssize_t show_mmustat_enable(struct sys_device *s, 143 struct sysdev_attribute *attr, char *buf) 144 { 145 unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); 146 return sprintf(buf, "%lx\n", val); 147 } 148 149 static ssize_t store_mmustat_enable(struct sys_device *s, 150 struct sysdev_attribute *attr, const char *buf, 151 size_t count) 152 { 153 unsigned long val, err; 154 int ret = sscanf(buf, "%ld", &val); 155 156 if (ret != 1) 157 return -EINVAL; 158 159 err = run_on_cpu(s->id, write_mmustat_enable, val); 160 if (err) 161 return -EIO; 162 163 return count; 164 } 165 166 static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); 167 168 static int mmu_stats_supported; 169 170 static int register_mmu_stats(struct sys_device *s) 171 { 172 if (!mmu_stats_supported) 173 return 0; 174 sysdev_create_file(s, &attr_mmustat_enable); 175 return sysfs_create_group(&s->kobj, &mmu_stat_group); 176 } 177 178 #ifdef CONFIG_HOTPLUG_CPU 179 static void unregister_mmu_stats(struct sys_device *s) 180 { 181 if (!mmu_stats_supported) 182 return; 183 sysfs_remove_group(&s->kobj, &mmu_stat_group); 184 sysdev_remove_file(s, &attr_mmustat_enable); 185 } 186 #endif 187 188 #define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ 189 static ssize_t show_##NAME(struct sys_device *dev, \ 190 struct sysdev_attribute *attr, char *buf) \ 191 { \ 192 cpuinfo_sparc *c = &cpu_data(dev->id); \ 193 return sprintf(buf, "%lu\n", c->MEMBER); \ 194 } 195 196 #define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ 197 static ssize_t show_##NAME(struct sys_device *dev, \ 198 struct sysdev_attribute *attr, char *buf) \ 199 { \ 200 cpuinfo_sparc *c = &cpu_data(dev->id); \ 201 return sprintf(buf, "%u\n", c->MEMBER); \ 202 } 203 204 SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); 205 SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); 206 SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); 207 SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); 208 SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); 209 SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); 210 SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); 211 212 static struct sysdev_attribute cpu_core_attrs[] = { 213 _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), 214 _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), 215 _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), 216 _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), 217 _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), 218 _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), 219 _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), 220 }; 221 222 static DEFINE_PER_CPU(struct cpu, cpu_devices); 223 224 static void register_cpu_online(unsigned int cpu) 225 { 226 struct cpu *c = &per_cpu(cpu_devices, cpu); 227 struct sys_device *s = &c->sysdev; 228 int i; 229 230 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 231 sysdev_create_file(s, &cpu_core_attrs[i]); 232 233 register_mmu_stats(s); 234 } 235 236 #ifdef CONFIG_HOTPLUG_CPU 237 static void unregister_cpu_online(unsigned int cpu) 238 { 239 struct cpu *c = &per_cpu(cpu_devices, cpu); 240 struct sys_device *s = &c->sysdev; 241 int i; 242 243 unregister_mmu_stats(s); 244 for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) 245 sysdev_remove_file(s, &cpu_core_attrs[i]); 246 } 247 #endif 248 249 static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, 250 unsigned long action, void *hcpu) 251 { 252 unsigned int cpu = (unsigned int)(long)hcpu; 253 254 switch (action) { 255 case CPU_ONLINE: 256 case CPU_ONLINE_FROZEN: 257 register_cpu_online(cpu); 258 break; 259 #ifdef CONFIG_HOTPLUG_CPU 260 case CPU_DEAD: 261 case CPU_DEAD_FROZEN: 262 unregister_cpu_online(cpu); 263 break; 264 #endif 265 } 266 return NOTIFY_OK; 267 } 268 269 static struct notifier_block __cpuinitdata sysfs_cpu_nb = { 270 .notifier_call = sysfs_cpu_notify, 271 }; 272 273 static void __init check_mmu_stats(void) 274 { 275 unsigned long dummy1, err; 276 277 if (tlb_type != hypervisor) 278 return; 279 280 err = sun4v_mmustat_info(&dummy1); 281 if (!err) 282 mmu_stats_supported = 1; 283 } 284 285 static void register_nodes(void) 286 { 287 #ifdef CONFIG_NUMA 288 int i; 289 290 for (i = 0; i < MAX_NUMNODES; i++) 291 register_one_node(i); 292 #endif 293 } 294 295 static int __init topology_init(void) 296 { 297 int cpu; 298 299 register_nodes(); 300 301 check_mmu_stats(); 302 303 register_cpu_notifier(&sysfs_cpu_nb); 304 305 for_each_possible_cpu(cpu) { 306 struct cpu *c = &per_cpu(cpu_devices, cpu); 307 308 register_cpu(c, cpu); 309 if (cpu_online(cpu)) 310 register_cpu_online(cpu); 311 } 312 313 return 0; 314 } 315 316 subsys_initcall(topology_init); 317