[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>
This commit is contained in:
parent
7a0b4cbc7d
commit
6bcac508fb
4 changed files with 149 additions and 2 deletions
|
@ -118,4 +118,15 @@ static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
|
||||||
return r0;
|
return r0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Service level reporting interface.
|
||||||
|
*/
|
||||||
|
struct service_level {
|
||||||
|
struct list_head list;
|
||||||
|
void (*seq_print)(struct seq_file *, struct service_level *);
|
||||||
|
};
|
||||||
|
|
||||||
|
int register_service_level(struct service_level *);
|
||||||
|
int unregister_service_level(struct service_level *);
|
||||||
|
|
||||||
#endif /* __ASM_S390_SYSINFO_H */
|
#endif /* __ASM_S390_SYSINFO_H */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <asm/qdio.h>
|
#include <asm/qdio.h>
|
||||||
#include <asm/ccwdev.h>
|
#include <asm/ccwdev.h>
|
||||||
#include <asm/ccwgroup.h>
|
#include <asm/ccwgroup.h>
|
||||||
|
#include <asm/sysinfo.h>
|
||||||
|
|
||||||
#include "qeth_core_mpc.h"
|
#include "qeth_core_mpc.h"
|
||||||
|
|
||||||
|
@ -733,6 +734,7 @@ struct qeth_card {
|
||||||
struct qeth_osn_info osn_info;
|
struct qeth_osn_info osn_info;
|
||||||
struct qeth_discipline discipline;
|
struct qeth_discipline discipline;
|
||||||
atomic_t force_alloc_skb;
|
atomic_t force_alloc_skb;
|
||||||
|
struct service_level qeth_service_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qeth_card_list_struct {
|
struct qeth_card_list_struct {
|
||||||
|
|
|
@ -1138,6 +1138,14 @@ static int qeth_setup_card(struct qeth_card *card)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr)
|
||||||
|
{
|
||||||
|
struct qeth_card *card = container_of(slr, struct qeth_card,
|
||||||
|
qeth_service_level);
|
||||||
|
seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card),
|
||||||
|
card->info.mcl_level);
|
||||||
|
}
|
||||||
|
|
||||||
static struct qeth_card *qeth_alloc_card(void)
|
static struct qeth_card *qeth_alloc_card(void)
|
||||||
{
|
{
|
||||||
struct qeth_card *card;
|
struct qeth_card *card;
|
||||||
|
@ -1157,6 +1165,8 @@ static struct qeth_card *qeth_alloc_card(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
card->options.layer2 = -1;
|
card->options.layer2 = -1;
|
||||||
|
card->qeth_service_level.seq_print = qeth_core_sl_print;
|
||||||
|
register_service_level(&card->qeth_service_level);
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3730,6 +3740,7 @@ static void qeth_core_free_card(struct qeth_card *card)
|
||||||
free_netdev(card->dev);
|
free_netdev(card->dev);
|
||||||
kfree(card->ip_tbd_list);
|
kfree(card->ip_tbd_list);
|
||||||
qeth_free_qdio_buffers(card);
|
qeth_free_qdio_buffers(card);
|
||||||
|
unregister_service_level(&card->qeth_service_level);
|
||||||
kfree(card);
|
kfree(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
/*
|
/*
|
||||||
* drivers/s390/sysinfo.c
|
* drivers/s390/sysinfo.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
* Copyright IBM Corp. 2001, 2008
|
||||||
* Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
|
* Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
|
||||||
|
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/sysinfo.h>
|
#include <asm/sysinfo.h>
|
||||||
|
#include <asm/cpcmd.h>
|
||||||
|
|
||||||
/* Sigh, math-emu. Don't ask. */
|
/* Sigh, math-emu. Don't ask. */
|
||||||
#include <asm/sfp-util.h>
|
#include <asm/sfp-util.h>
|
||||||
|
@ -271,6 +275,125 @@ static __init int create_proc_sysinfo(void)
|
||||||
|
|
||||||
__initcall(create_proc_sysinfo);
|
__initcall(create_proc_sysinfo);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Service levels interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static DECLARE_RWSEM(service_level_sem);
|
||||||
|
static LIST_HEAD(service_level_list);
|
||||||
|
|
||||||
|
int register_service_level(struct service_level *slr)
|
||||||
|
{
|
||||||
|
struct service_level *ptr;
|
||||||
|
|
||||||
|
down_write(&service_level_sem);
|
||||||
|
list_for_each_entry(ptr, &service_level_list, list)
|
||||||
|
if (ptr == slr) {
|
||||||
|
up_write(&service_level_sem);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
list_add_tail(&slr->list, &service_level_list);
|
||||||
|
up_write(&service_level_sem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(register_service_level);
|
||||||
|
|
||||||
|
int unregister_service_level(struct service_level *slr)
|
||||||
|
{
|
||||||
|
struct service_level *ptr, *next;
|
||||||
|
int rc = -ENOENT;
|
||||||
|
|
||||||
|
down_write(&service_level_sem);
|
||||||
|
list_for_each_entry_safe(ptr, next, &service_level_list, list) {
|
||||||
|
if (ptr != slr)
|
||||||
|
continue;
|
||||||
|
list_del(&ptr->list);
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
up_write(&service_level_sem);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(unregister_service_level);
|
||||||
|
|
||||||
|
static void *service_level_start(struct seq_file *m, loff_t *pos)
|
||||||
|
{
|
||||||
|
down_read(&service_level_sem);
|
||||||
|
return seq_list_start(&service_level_list, *pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *service_level_next(struct seq_file *m, void *p, loff_t *pos)
|
||||||
|
{
|
||||||
|
return seq_list_next(p, &service_level_list, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void service_level_stop(struct seq_file *m, void *p)
|
||||||
|
{
|
||||||
|
up_read(&service_level_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int service_level_show(struct seq_file *m, void *p)
|
||||||
|
{
|
||||||
|
struct service_level *slr;
|
||||||
|
|
||||||
|
slr = list_entry(p, struct service_level, list);
|
||||||
|
slr->seq_print(m, slr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct seq_operations service_level_seq_ops = {
|
||||||
|
.start = service_level_start,
|
||||||
|
.next = service_level_next,
|
||||||
|
.stop = service_level_stop,
|
||||||
|
.show = service_level_show
|
||||||
|
};
|
||||||
|
|
||||||
|
static int service_level_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return seq_open(file, &service_level_seq_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations service_level_ops = {
|
||||||
|
.open = service_level_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = seq_release
|
||||||
|
};
|
||||||
|
|
||||||
|
static void service_level_vm_print(struct seq_file *m,
|
||||||
|
struct service_level *slr)
|
||||||
|
{
|
||||||
|
char *query_buffer, *str;
|
||||||
|
|
||||||
|
query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA);
|
||||||
|
if (!query_buffer)
|
||||||
|
return;
|
||||||
|
cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL);
|
||||||
|
str = strchr(query_buffer, '\n');
|
||||||
|
if (str)
|
||||||
|
*str = 0;
|
||||||
|
seq_printf(m, "VM: %s\n", query_buffer);
|
||||||
|
kfree(query_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct service_level service_level_vm = {
|
||||||
|
.seq_print = service_level_vm_print
|
||||||
|
};
|
||||||
|
|
||||||
|
static __init int create_proc_service_level(void)
|
||||||
|
{
|
||||||
|
proc_create("service_levels", 0, NULL, &service_level_ops);
|
||||||
|
if (MACHINE_IS_VM)
|
||||||
|
register_service_level(&service_level_vm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
subsys_initcall(create_proc_service_level);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bogomips calculation based on cpu capability.
|
||||||
|
*/
|
||||||
|
|
||||||
int get_cpu_capability(unsigned int *capability)
|
int get_cpu_capability(unsigned int *capability)
|
||||||
{
|
{
|
||||||
struct sysinfo_1_2_2 *info;
|
struct sysinfo_1_2_2 *info;
|
||||||
|
|
Loading…
Add table
Reference in a new issue