aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2013-08-12 14:39:22 -0400
committerChris Metcalf <cmetcalf@tilera.com>2013-09-03 14:51:36 -0400
commit80f184108e364ba1d08dd77339966034c9a9243e (patch)
tree5ec0337b5f0184e886d12392704289deeb6acd5b /arch/tile
parent8157107b13099d6eb2e8ccd00b9aba009c698c38 (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.h16
-rw-r--r--arch/tile/kernel/sysfs.c76
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 */
562int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len); 572int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len, ...);
563 573
564/** Tile coordinate */ 574/** Tile coordinate */
565typedef struct 575typedef 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
160static 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
175static 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
187static DEVICE_ATTR(hv_stats, 0644, hv_stats_show, hv_stats_store);
188
189static 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
201static 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
214static 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
160static int __init create_sysfs_entries(void) 221static 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}
193subsys_initcall(create_sysfs_entries); 269subsys_initcall(create_sysfs_entries);