diff options
author | David Miller <davem@t1000.davemloft.net> | 2007-06-04 02:38:09 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-06-05 00:49:57 -0400 |
commit | d887ab3a9b1899f88b8cfba531e726b5fb2ebd14 (patch) | |
tree | 2f60de04ddf40419c295da0d9f64024fdc53d372 /arch/sparc64 | |
parent | 48b67356400dd7866c035024aeaa2f804de7cead (diff) |
[SPARC64]: Provide mmu statistics via sysfs.
If the system supports hypervisor based statistics, allow them to
be fetched, enabled, and disabled via sysfs.
Enable and disable via the boolean:
/sys/devices/systems/cpu/cpuN/mmustat_enable
Statistic values are provided under:
/sys/devices/systems/cpu/cpuN/mmu_status/
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/entry.S | 22 | ||||
-rw-r--r-- | arch/sparc64/kernel/sysfs.c | 215 |
2 files changed, 222 insertions, 15 deletions
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 5b2831590093..7d1a11822a1e 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S | |||
@@ -2570,3 +2570,25 @@ sun4v_svc_clrstatus: | |||
2570 | retl | 2570 | retl |
2571 | nop | 2571 | nop |
2572 | .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus | 2572 | .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus |
2573 | |||
2574 | .globl sun4v_mmustat_conf | ||
2575 | .type sun4v_mmustat_conf,#function | ||
2576 | sun4v_mmustat_conf: | ||
2577 | mov %o1, %o4 | ||
2578 | mov HV_FAST_MMUSTAT_CONF, %o5 | ||
2579 | ta HV_FAST_TRAP | ||
2580 | stx %o1, [%o4] | ||
2581 | retl | ||
2582 | nop | ||
2583 | .size sun4v_mmustat_conf, .-sun4v_mmustat_conf | ||
2584 | |||
2585 | .globl sun4v_mmustat_info | ||
2586 | .type sun4v_mmustat_info,#function | ||
2587 | sun4v_mmustat_info: | ||
2588 | mov %o0, %o4 | ||
2589 | mov HV_FAST_MMUSTAT_INFO, %o5 | ||
2590 | ta HV_FAST_TRAP | ||
2591 | stx %o1, [%o4] | ||
2592 | retl | ||
2593 | nop | ||
2594 | .size sun4v_mmustat_info, .-sun4v_mmustat_info | ||
diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c index a684a79ece44..cdb1477af89f 100644 --- a/arch/sparc64/kernel/sysfs.c +++ b/arch/sparc64/kernel/sysfs.c | |||
@@ -8,32 +8,198 @@ | |||
8 | #include <linux/percpu.h> | 8 | #include <linux/percpu.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | 10 | ||
11 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 11 | #include <asm/hypervisor.h> |
12 | #include <asm/spitfire.h> | ||
13 | |||
14 | static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); | ||
12 | 15 | ||
13 | #define SHOW_ULONG_NAME(NAME, MEMBER) \ | 16 | #define SHOW_MMUSTAT_ULONG(NAME) \ |
14 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ | 17 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ |
15 | { \ | 18 | { \ |
16 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | 19 | struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ |
17 | cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ | 20 | return sprintf(buf, "%lu\n", p->NAME); \ |
21 | } \ | ||
22 | static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) | ||
23 | |||
24 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); | ||
25 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); | ||
26 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); | ||
27 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); | ||
28 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); | ||
29 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); | ||
30 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); | ||
31 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); | ||
32 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); | ||
33 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); | ||
34 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); | ||
35 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); | ||
36 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); | ||
37 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); | ||
38 | SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); | ||
39 | SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); | ||
40 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); | ||
41 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); | ||
42 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); | ||
43 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); | ||
44 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); | ||
45 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); | ||
46 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); | ||
47 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); | ||
48 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); | ||
49 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); | ||
50 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); | ||
51 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); | ||
52 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); | ||
53 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); | ||
54 | SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); | ||
55 | SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); | ||
56 | |||
57 | static 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 | |||
93 | static struct attribute_group mmu_stat_group = { | ||
94 | .attrs = mmu_stat_attrs, | ||
95 | .name = "mmu_stats", | ||
96 | }; | ||
97 | |||
98 | /* XXX convert to rusty's on_one_cpu */ | ||
99 | static unsigned long run_on_cpu(unsigned long cpu, | ||
100 | unsigned long (*func)(unsigned long), | ||
101 | unsigned long arg) | ||
102 | { | ||
103 | cpumask_t old_affinity = current->cpus_allowed; | ||
104 | unsigned long ret; | ||
105 | |||
106 | /* should return -EINVAL to userspace */ | ||
107 | if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) | ||
108 | return 0; | ||
109 | |||
110 | ret = func(arg); | ||
111 | |||
112 | set_cpus_allowed(current, old_affinity); | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static unsigned long read_mmustat_enable(unsigned long junk) | ||
118 | { | ||
119 | unsigned long ra = 0; | ||
120 | |||
121 | sun4v_mmustat_info(&ra); | ||
122 | |||
123 | return ra != 0; | ||
124 | } | ||
125 | |||
126 | static unsigned long write_mmustat_enable(unsigned long val) | ||
127 | { | ||
128 | unsigned long ra, orig_ra; | ||
129 | |||
130 | if (val) | ||
131 | ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); | ||
132 | else | ||
133 | ra = 0UL; | ||
134 | |||
135 | return sun4v_mmustat_conf(ra, &orig_ra); | ||
136 | } | ||
137 | |||
138 | static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) | ||
139 | { | ||
140 | unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); | ||
141 | return sprintf(buf, "%lx\n", val); | ||
142 | } | ||
143 | |||
144 | static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) | ||
145 | { | ||
146 | unsigned long val, err; | ||
147 | int ret = sscanf(buf, "%ld", &val); | ||
148 | |||
149 | if (ret != 1) | ||
150 | return -EINVAL; | ||
151 | |||
152 | err = run_on_cpu(s->id, write_mmustat_enable, val); | ||
153 | if (err) | ||
154 | return -EIO; | ||
155 | |||
156 | return count; | ||
157 | } | ||
158 | |||
159 | static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); | ||
160 | |||
161 | static int mmu_stats_supported; | ||
162 | |||
163 | static int register_mmu_stats(struct sys_device *s) | ||
164 | { | ||
165 | if (!mmu_stats_supported) | ||
166 | return 0; | ||
167 | sysdev_create_file(s, &attr_mmustat_enable); | ||
168 | return sysfs_create_group(&s->kobj, &mmu_stat_group); | ||
169 | } | ||
170 | |||
171 | #ifdef CONFIG_HOTPLUG_CPU | ||
172 | static void unregister_mmu_stats(struct sys_device *s) | ||
173 | { | ||
174 | if (!mmu_stats_supported) | ||
175 | return; | ||
176 | sysfs_remove_group(&s->kobj, &mmu_stat_group); | ||
177 | sysdev_remove_file(s, &attr_mmustat_enable); | ||
178 | } | ||
179 | #endif | ||
180 | |||
181 | #define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ | ||
182 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ | ||
183 | { \ | ||
184 | cpuinfo_sparc *c = &cpu_data(dev->id); \ | ||
18 | return sprintf(buf, "%lu\n", c->MEMBER); \ | 185 | return sprintf(buf, "%lu\n", c->MEMBER); \ |
19 | } | 186 | } |
20 | 187 | ||
21 | #define SHOW_UINT_NAME(NAME, MEMBER) \ | 188 | #define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ |
22 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ | 189 | static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ |
23 | { \ | 190 | { \ |
24 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | 191 | cpuinfo_sparc *c = &cpu_data(dev->id); \ |
25 | cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ | ||
26 | return sprintf(buf, "%u\n", c->MEMBER); \ | 192 | return sprintf(buf, "%u\n", c->MEMBER); \ |
27 | } | 193 | } |
28 | 194 | ||
29 | SHOW_ULONG_NAME(clock_tick, clock_tick); | 195 | SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); |
30 | SHOW_ULONG_NAME(udelay_val, udelay_val); | 196 | SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); |
31 | SHOW_UINT_NAME(l1_dcache_size, dcache_size); | 197 | SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); |
32 | SHOW_UINT_NAME(l1_dcache_line_size, dcache_line_size); | 198 | SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); |
33 | SHOW_UINT_NAME(l1_icache_size, icache_size); | 199 | SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); |
34 | SHOW_UINT_NAME(l1_icache_line_size, icache_line_size); | 200 | SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); |
35 | SHOW_UINT_NAME(l2_cache_size, ecache_size); | 201 | SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); |
36 | SHOW_UINT_NAME(l2_cache_line_size, ecache_line_size); | 202 | SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); |
37 | 203 | ||
38 | static struct sysdev_attribute cpu_core_attrs[] = { | 204 | static struct sysdev_attribute cpu_core_attrs[] = { |
39 | _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), | 205 | _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), |
@@ -46,6 +212,8 @@ static struct sysdev_attribute cpu_core_attrs[] = { | |||
46 | _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), | 212 | _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), |
47 | }; | 213 | }; |
48 | 214 | ||
215 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | ||
216 | |||
49 | static void register_cpu_online(unsigned int cpu) | 217 | static void register_cpu_online(unsigned int cpu) |
50 | { | 218 | { |
51 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 219 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
@@ -54,6 +222,8 @@ static void register_cpu_online(unsigned int cpu) | |||
54 | 222 | ||
55 | for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) | 223 | for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) |
56 | sysdev_create_file(s, &cpu_core_attrs[i]); | 224 | sysdev_create_file(s, &cpu_core_attrs[i]); |
225 | |||
226 | register_mmu_stats(s); | ||
57 | } | 227 | } |
58 | 228 | ||
59 | #ifdef CONFIG_HOTPLUG_CPU | 229 | #ifdef CONFIG_HOTPLUG_CPU |
@@ -63,6 +233,7 @@ static void unregister_cpu_online(unsigned int cpu) | |||
63 | struct sys_device *s = &c->sysdev; | 233 | struct sys_device *s = &c->sysdev; |
64 | int i; | 234 | int i; |
65 | 235 | ||
236 | unregister_mmu_stats(s); | ||
66 | for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) | 237 | for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) |
67 | sysdev_remove_file(s, &cpu_core_attrs[i]); | 238 | sysdev_remove_file(s, &cpu_core_attrs[i]); |
68 | } | 239 | } |
@@ -92,10 +263,24 @@ static struct notifier_block __cpuinitdata sysfs_cpu_nb = { | |||
92 | .notifier_call = sysfs_cpu_notify, | 263 | .notifier_call = sysfs_cpu_notify, |
93 | }; | 264 | }; |
94 | 265 | ||
266 | static void __init check_mmu_stats(void) | ||
267 | { | ||
268 | unsigned long dummy1, err; | ||
269 | |||
270 | if (tlb_type != hypervisor) | ||
271 | return; | ||
272 | |||
273 | err = sun4v_mmustat_info(&dummy1); | ||
274 | if (!err) | ||
275 | mmu_stats_supported = 1; | ||
276 | } | ||
277 | |||
95 | static int __init topology_init(void) | 278 | static int __init topology_init(void) |
96 | { | 279 | { |
97 | int cpu; | 280 | int cpu; |
98 | 281 | ||
282 | check_mmu_stats(); | ||
283 | |||
99 | register_cpu_notifier(&sysfs_cpu_nb); | 284 | register_cpu_notifier(&sysfs_cpu_nb); |
100 | 285 | ||
101 | for_each_possible_cpu(cpu) { | 286 | for_each_possible_cpu(cpu) { |