aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
authorDavid Miller <davem@t1000.davemloft.net>2007-06-04 02:38:09 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-06-05 00:49:57 -0400
commitd887ab3a9b1899f88b8cfba531e726b5fb2ebd14 (patch)
tree2f60de04ddf40419c295da0d9f64024fdc53d372 /arch/sparc64
parent48b67356400dd7866c035024aeaa2f804de7cead (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.S22
-rw-r--r--arch/sparc64/kernel/sysfs.c215
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
2576sun4v_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
2587sun4v_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
11static DEFINE_PER_CPU(struct cpu, cpu_devices); 11#include <asm/hypervisor.h>
12#include <asm/spitfire.h>
13
14static 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) \
14static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ 17static 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} \
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
98/* XXX convert to rusty's on_one_cpu */
99static 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
117static 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
126static 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
138static 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
144static 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
159static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable);
160
161static int mmu_stats_supported;
162
163static 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
172static 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) \
182static 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) \
22static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ 189static 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
29SHOW_ULONG_NAME(clock_tick, clock_tick); 195SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick);
30SHOW_ULONG_NAME(udelay_val, udelay_val); 196SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val);
31SHOW_UINT_NAME(l1_dcache_size, dcache_size); 197SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size);
32SHOW_UINT_NAME(l1_dcache_line_size, dcache_line_size); 198SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size);
33SHOW_UINT_NAME(l1_icache_size, icache_size); 199SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size);
34SHOW_UINT_NAME(l1_icache_line_size, icache_line_size); 200SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size);
35SHOW_UINT_NAME(l2_cache_size, ecache_size); 201SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size);
36SHOW_UINT_NAME(l2_cache_line_size, ecache_line_size); 202SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size);
37 203
38static struct sysdev_attribute cpu_core_attrs[] = { 204static 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
215static DEFINE_PER_CPU(struct cpu, cpu_devices);
216
49static void register_cpu_online(unsigned int cpu) 217static 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
266static 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
95static int __init topology_init(void) 278static 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) {