diff options
author | Chris Metcalf <cmetcalf@tilera.com> | 2013-08-12 14:39:22 -0400 |
---|---|---|
committer | Chris Metcalf <cmetcalf@tilera.com> | 2013-09-03 14:51:36 -0400 |
commit | 80f184108e364ba1d08dd77339966034c9a9243e (patch) | |
tree | 5ec0337b5f0184e886d12392704289deeb6acd5b /arch/tile | |
parent | 8157107b13099d6eb2e8ccd00b9aba009c698c38 (diff) |
tile: support reporting Tilera hypervisor statistics
Newer hypervisors have an API for reporting per-cpu statistics
information. This change allows seeing that information via
/sys/devices/system/cpu/cpuN/hv_stats file for each core.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile')
-rw-r--r-- | arch/tile/include/hv/hypervisor.h | 16 | ||||
-rw-r--r-- | arch/tile/kernel/sysfs.c | 76 |
2 files changed, 89 insertions, 3 deletions
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h index 0971ebbde1b7..dfcdeb61ba34 100644 --- a/arch/tile/include/hv/hypervisor.h +++ b/arch/tile/include/hv/hypervisor.h | |||
@@ -544,14 +544,24 @@ typedef enum { | |||
544 | HV_CONFSTR_CPUMOD_REV = 18, | 544 | HV_CONFSTR_CPUMOD_REV = 18, |
545 | 545 | ||
546 | /** Human-readable CPU module description. */ | 546 | /** Human-readable CPU module description. */ |
547 | HV_CONFSTR_CPUMOD_DESC = 19 | 547 | HV_CONFSTR_CPUMOD_DESC = 19, |
548 | |||
549 | /** Per-tile hypervisor statistics. When this identifier is specified, | ||
550 | * the hv_confstr call takes two extra arguments. The first is the | ||
551 | * HV_XY_TO_LOTAR of the target tile's coordinates. The second is | ||
552 | * a flag word. The only current flag is the lowest bit, which means | ||
553 | * "zero out the stats instead of retrieving them"; in this case the | ||
554 | * buffer and buffer length are ignored. */ | ||
555 | HV_CONFSTR_HV_STATS = 20 | ||
548 | 556 | ||
549 | } HV_ConfstrQuery; | 557 | } HV_ConfstrQuery; |
550 | 558 | ||
551 | /** Query a configuration string from the hypervisor. | 559 | /** Query a configuration string from the hypervisor. |
552 | * | 560 | * |
553 | * @param query Identifier for the specific string to be retrieved | 561 | * @param query Identifier for the specific string to be retrieved |
554 | * (HV_CONFSTR_xxx). | 562 | * (HV_CONFSTR_xxx). Some strings may require or permit extra |
563 | * arguments to be appended which select specific objects to be | ||
564 | * described; see the string descriptions above. | ||
555 | * @param buf Buffer in which to place the string. | 565 | * @param buf Buffer in which to place the string. |
556 | * @param len Length of the buffer. | 566 | * @param len Length of the buffer. |
557 | * @return If query is valid, then the length of the corresponding string, | 567 | * @return If query is valid, then the length of the corresponding string, |
@@ -559,7 +569,7 @@ typedef enum { | |||
559 | * was truncated. If query is invalid, HV_EINVAL. If the specified | 569 | * was truncated. If query is invalid, HV_EINVAL. If the specified |
560 | * buffer is not writable by the client, HV_EFAULT. | 570 | * buffer is not writable by the client, HV_EFAULT. |
561 | */ | 571 | */ |
562 | int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len); | 572 | int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len, ...); |
563 | 573 | ||
564 | /** Tile coordinate */ | 574 | /** Tile coordinate */ |
565 | typedef struct | 575 | typedef struct |
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c index e25b0a89c18f..a3ed12f8f83b 100644 --- a/arch/tile/kernel/sysfs.c +++ b/arch/tile/kernel/sysfs.c | |||
@@ -157,6 +157,67 @@ hvconfig_bin_read(struct file *filp, struct kobject *kobj, | |||
157 | return count; | 157 | return count; |
158 | } | 158 | } |
159 | 159 | ||
160 | static ssize_t hv_stats_show(struct device *dev, | ||
161 | struct device_attribute *attr, | ||
162 | char *page) | ||
163 | { | ||
164 | int cpu = dev->id; | ||
165 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
166 | |||
167 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, | ||
168 | (unsigned long)page, PAGE_SIZE - 1, | ||
169 | lotar, 0); | ||
170 | n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1); | ||
171 | page[n] = '\0'; | ||
172 | return n; | ||
173 | } | ||
174 | |||
175 | static ssize_t hv_stats_store(struct device *dev, | ||
176 | struct device_attribute *attr, | ||
177 | const char *page, | ||
178 | size_t count) | ||
179 | { | ||
180 | int cpu = dev->id; | ||
181 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
182 | |||
183 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, 0, 0, lotar, 1); | ||
184 | return n < 0 ? n : count; | ||
185 | } | ||
186 | |||
187 | static DEVICE_ATTR(hv_stats, 0644, hv_stats_show, hv_stats_store); | ||
188 | |||
189 | static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif) | ||
190 | { | ||
191 | int err, cpu = dev->id; | ||
192 | |||
193 | if (!cpu_online(cpu)) | ||
194 | return 0; | ||
195 | |||
196 | err = sysfs_create_file(&dev->kobj, &dev_attr_hv_stats.attr); | ||
197 | |||
198 | return err; | ||
199 | } | ||
200 | |||
201 | static int hv_stats_device_remove(struct device *dev, | ||
202 | struct subsys_interface *sif) | ||
203 | { | ||
204 | int cpu = dev->id; | ||
205 | |||
206 | if (!cpu_online(cpu)) | ||
207 | return 0; | ||
208 | |||
209 | sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | |||
214 | static struct subsys_interface hv_stats_interface = { | ||
215 | .name = "hv_stats", | ||
216 | .subsys = &cpu_subsys, | ||
217 | .add_dev = hv_stats_device_add, | ||
218 | .remove_dev = hv_stats_device_remove, | ||
219 | }; | ||
220 | |||
160 | static int __init create_sysfs_entries(void) | 221 | static int __init create_sysfs_entries(void) |
161 | { | 222 | { |
162 | int err = 0; | 223 | int err = 0; |
@@ -188,6 +249,21 @@ static int __init create_sysfs_entries(void) | |||
188 | err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin); | 249 | err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin); |
189 | } | 250 | } |
190 | 251 | ||
252 | if (!err) { | ||
253 | /* | ||
254 | * Don't bother adding the hv_stats files on each CPU if | ||
255 | * our hypervisor doesn't supply statistics. | ||
256 | */ | ||
257 | int cpu = raw_smp_processor_id(); | ||
258 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
259 | char dummy; | ||
260 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, | ||
261 | (unsigned long) &dummy, 1, | ||
262 | lotar, 0); | ||
263 | if (n >= 0) | ||
264 | err = subsys_interface_register(&hv_stats_interface); | ||
265 | } | ||
266 | |||
191 | return err; | 267 | return err; |
192 | } | 268 | } |
193 | subsys_initcall(create_sysfs_entries); | 269 | subsys_initcall(create_sysfs_entries); |