diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2007-04-27 16:01:56 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 16:01:46 +0200 |
commit | 2fc2d1e9ffcde78af7ab63ed640d9a4901797de2 (patch) | |
tree | 9fd8fcbf4b6882200480da1f04e30b406d1f8a57 /drivers/s390/char/sclp_config.c | |
parent | db77aa5f3d01fe6a6cc629dbd37936b1fdd129ba (diff) | |
download | op-kernel-dev-2fc2d1e9ffcde78af7ab63ed640d9a4901797de2.zip op-kernel-dev-2fc2d1e9ffcde78af7ab63ed640d9a4901797de2.tar.gz |
[S390] Processor degradation notification.
Generate uevents for all cpus if cpu capability changes. This can
happen e.g. because the cpus are overheating. The cpu capability can
be read via /sys/devices/system/cpu/cpuN/capability.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/char/sclp_config.c')
-rw-r--r-- | drivers/s390/char/sclp_config.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c new file mode 100644 index 0000000..5322e5e --- /dev/null +++ b/drivers/s390/char/sclp_config.c @@ -0,0 +1,75 @@ +/* + * drivers/s390/char/sclp_config.c + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + */ + +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/cpu.h> +#include <linux/sysdev.h> +#include <linux/workqueue.h> +#include "sclp.h" + +#define TAG "sclp_config: " + +struct conf_mgm_data { + u8 reserved; + u8 ev_qualifier; +} __attribute__((packed)); + +#define EV_QUAL_CAP_CHANGE 3 + +static struct work_struct sclp_cpu_capability_work; + +static void sclp_cpu_capability_notify(struct work_struct *work) +{ + int cpu; + struct sys_device *sysdev; + + printk(KERN_WARNING TAG "cpu capability changed.\n"); + lock_cpu_hotplug(); + for_each_online_cpu(cpu) { + sysdev = get_cpu_sysdev(cpu); + kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); + } + unlock_cpu_hotplug(); +} + +static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) +{ + struct conf_mgm_data *cdata; + + cdata = (struct conf_mgm_data *)(evbuf + 1); + if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE) + schedule_work(&sclp_cpu_capability_work); +} + +static struct sclp_register sclp_conf_register = +{ + .receive_mask = EVTYP_CONFMGMDATA_MASK, + .receiver_fn = sclp_conf_receiver_fn, +}; + +static int __init sclp_conf_init(void) +{ + int rc; + + INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); + + rc = sclp_register(&sclp_conf_register); + if (rc) { + printk(KERN_ERR TAG "failed to register (%d).\n", rc); + return rc; + } + + if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK)) { + printk(KERN_WARNING TAG "no configuration management.\n"); + sclp_unregister(&sclp_conf_register); + rc = -ENOSYS; + } + return rc; +} + +__initcall(sclp_conf_init); |