aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/sysinfo.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:38:49 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:39:00 -0500
commit6bcac508fbebdca52f5a55d69a4316997ecb5391 (patch)
treefa04ce94ef6267676e8edcd2f93ef776bd6e60eb /drivers/s390/sysinfo.c
parent7a0b4cbc7d7d99763511b488b08bbc2607ddd1e3 (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.c127
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
282static DECLARE_RWSEM(service_level_sem);
283static LIST_HEAD(service_level_list);
284
285int 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}
299EXPORT_SYMBOL(register_service_level);
300
301int 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}
317EXPORT_SYMBOL(unregister_service_level);
318
319static 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
325static 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
330static void service_level_stop(struct seq_file *m, void *p)
331{
332 up_read(&service_level_sem);
333}
334
335static 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
344static 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
351static int service_level_open(struct inode *inode, struct file *file)
352{
353 return seq_open(file, &service_level_seq_ops);
354}
355
356static 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
363static 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
379static struct service_level service_level_vm = {
380 .seq_print = service_level_vm_print
381};
382
383static __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
391subsys_initcall(create_proc_service_level);
392
393/*
394 * Bogomips calculation based on cpu capability.
395 */
396
274int get_cpu_capability(unsigned int *capability) 397int get_cpu_capability(unsigned int *capability)
275{ 398{
276 struct sysinfo_1_2_2 *info; 399 struct sysinfo_1_2_2 *info;