diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:38:49 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:00 -0500 |
commit | 6bcac508fbebdca52f5a55d69a4316997ecb5391 (patch) | |
tree | fa04ce94ef6267676e8edcd2f93ef776bd6e60eb /drivers/s390/sysinfo.c | |
parent | 7a0b4cbc7d7d99763511b488b08bbc2607ddd1e3 (diff) |
[S390] service level interface.
Add a new proc interface /proc/service_levels that allows any code
to report a relevant service level, e.g. the microcode level of
devices, the service level of the hypervisor, etc.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/sysinfo.c')
-rw-r--r-- | drivers/s390/sysinfo.c | 127 |
1 files changed, 125 insertions, 2 deletions
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index c3e4ab07b9cc..0eea90781385 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c | |||
@@ -1,17 +1,21 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/sysinfo.c | 2 | * drivers/s390/sysinfo.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2008 |
5 | * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) | 5 | * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
6 | */ | 7 | */ |
7 | 8 | ||
8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
9 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
10 | #include <linux/proc_fs.h> | 11 | #include <linux/proc_fs.h> |
12 | #include <linux/seq_file.h> | ||
11 | #include <linux/init.h> | 13 | #include <linux/init.h> |
12 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/module.h> | ||
13 | #include <asm/ebcdic.h> | 16 | #include <asm/ebcdic.h> |
14 | #include <asm/sysinfo.h> | 17 | #include <asm/sysinfo.h> |
18 | #include <asm/cpcmd.h> | ||
15 | 19 | ||
16 | /* Sigh, math-emu. Don't ask. */ | 20 | /* Sigh, math-emu. Don't ask. */ |
17 | #include <asm/sfp-util.h> | 21 | #include <asm/sfp-util.h> |
@@ -271,6 +275,125 @@ static __init int create_proc_sysinfo(void) | |||
271 | 275 | ||
272 | __initcall(create_proc_sysinfo); | 276 | __initcall(create_proc_sysinfo); |
273 | 277 | ||
278 | /* | ||
279 | * Service levels interface. | ||
280 | */ | ||
281 | |||
282 | static DECLARE_RWSEM(service_level_sem); | ||
283 | static LIST_HEAD(service_level_list); | ||
284 | |||
285 | int register_service_level(struct service_level *slr) | ||
286 | { | ||
287 | struct service_level *ptr; | ||
288 | |||
289 | down_write(&service_level_sem); | ||
290 | list_for_each_entry(ptr, &service_level_list, list) | ||
291 | if (ptr == slr) { | ||
292 | up_write(&service_level_sem); | ||
293 | return -EEXIST; | ||
294 | } | ||
295 | list_add_tail(&slr->list, &service_level_list); | ||
296 | up_write(&service_level_sem); | ||
297 | return 0; | ||
298 | } | ||
299 | EXPORT_SYMBOL(register_service_level); | ||
300 | |||
301 | int unregister_service_level(struct service_level *slr) | ||
302 | { | ||
303 | struct service_level *ptr, *next; | ||
304 | int rc = -ENOENT; | ||
305 | |||
306 | down_write(&service_level_sem); | ||
307 | list_for_each_entry_safe(ptr, next, &service_level_list, list) { | ||
308 | if (ptr != slr) | ||
309 | continue; | ||
310 | list_del(&ptr->list); | ||
311 | rc = 0; | ||
312 | break; | ||
313 | } | ||
314 | up_write(&service_level_sem); | ||
315 | return rc; | ||
316 | } | ||
317 | EXPORT_SYMBOL(unregister_service_level); | ||
318 | |||
319 | static void *service_level_start(struct seq_file *m, loff_t *pos) | ||
320 | { | ||
321 | down_read(&service_level_sem); | ||
322 | return seq_list_start(&service_level_list, *pos); | ||
323 | } | ||
324 | |||
325 | static void *service_level_next(struct seq_file *m, void *p, loff_t *pos) | ||
326 | { | ||
327 | return seq_list_next(p, &service_level_list, pos); | ||
328 | } | ||
329 | |||
330 | static void service_level_stop(struct seq_file *m, void *p) | ||
331 | { | ||
332 | up_read(&service_level_sem); | ||
333 | } | ||
334 | |||
335 | static int service_level_show(struct seq_file *m, void *p) | ||
336 | { | ||
337 | struct service_level *slr; | ||
338 | |||
339 | slr = list_entry(p, struct service_level, list); | ||
340 | slr->seq_print(m, slr); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static const struct seq_operations service_level_seq_ops = { | ||
345 | .start = service_level_start, | ||
346 | .next = service_level_next, | ||
347 | .stop = service_level_stop, | ||
348 | .show = service_level_show | ||
349 | }; | ||
350 | |||
351 | static int service_level_open(struct inode *inode, struct file *file) | ||
352 | { | ||
353 | return seq_open(file, &service_level_seq_ops); | ||
354 | } | ||
355 | |||
356 | static const struct file_operations service_level_ops = { | ||
357 | .open = service_level_open, | ||
358 | .read = seq_read, | ||
359 | .llseek = seq_lseek, | ||
360 | .release = seq_release | ||
361 | }; | ||
362 | |||
363 | static void service_level_vm_print(struct seq_file *m, | ||
364 | struct service_level *slr) | ||
365 | { | ||
366 | char *query_buffer, *str; | ||
367 | |||
368 | query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA); | ||
369 | if (!query_buffer) | ||
370 | return; | ||
371 | cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL); | ||
372 | str = strchr(query_buffer, '\n'); | ||
373 | if (str) | ||
374 | *str = 0; | ||
375 | seq_printf(m, "VM: %s\n", query_buffer); | ||
376 | kfree(query_buffer); | ||
377 | } | ||
378 | |||
379 | static struct service_level service_level_vm = { | ||
380 | .seq_print = service_level_vm_print | ||
381 | }; | ||
382 | |||
383 | static __init int create_proc_service_level(void) | ||
384 | { | ||
385 | proc_create("service_levels", 0, NULL, &service_level_ops); | ||
386 | if (MACHINE_IS_VM) | ||
387 | register_service_level(&service_level_vm); | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | subsys_initcall(create_proc_service_level); | ||
392 | |||
393 | /* | ||
394 | * Bogomips calculation based on cpu capability. | ||
395 | */ | ||
396 | |||
274 | int get_cpu_capability(unsigned int *capability) | 397 | int get_cpu_capability(unsigned int *capability) |
275 | { | 398 | { |
276 | struct sysinfo_1_2_2 *info; | 399 | struct sysinfo_1_2_2 *info; |