diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2007-04-27 10:01:56 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:46 -0400 |
commit | 2fc2d1e9ffcde78af7ab63ed640d9a4901797de2 (patch) | |
tree | 9fd8fcbf4b6882200480da1f04e30b406d1f8a57 | |
parent | db77aa5f3d01fe6a6cc629dbd37936b1fdd129ba (diff) |
[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>
-rw-r--r-- | arch/s390/kernel/smp.c | 48 | ||||
-rw-r--r-- | drivers/s390/char/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_config.c | 75 | ||||
-rw-r--r-- | drivers/s390/sysinfo.c | 18 | ||||
-rw-r--r-- | include/asm-s390/processor.h | 1 |
6 files changed, 140 insertions, 6 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 7c0143fdf710..2c5de92958dd 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -821,19 +821,57 @@ int setup_profiling_timer(unsigned int multiplier) | |||
821 | 821 | ||
822 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 822 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
823 | 823 | ||
824 | static ssize_t show_capability(struct sys_device *dev, char *buf) | ||
825 | { | ||
826 | unsigned int capability; | ||
827 | int rc; | ||
828 | |||
829 | rc = get_cpu_capability(&capability); | ||
830 | if (rc) | ||
831 | return rc; | ||
832 | return sprintf(buf, "%u\n", capability); | ||
833 | } | ||
834 | static SYSDEV_ATTR(capability, 0444, show_capability, NULL); | ||
835 | |||
836 | static int __cpuinit smp_cpu_notify(struct notifier_block *self, | ||
837 | unsigned long action, void *hcpu) | ||
838 | { | ||
839 | unsigned int cpu = (unsigned int)(long)hcpu; | ||
840 | struct cpu *c = &per_cpu(cpu_devices, cpu); | ||
841 | struct sys_device *s = &c->sysdev; | ||
842 | |||
843 | switch (action) { | ||
844 | case CPU_ONLINE: | ||
845 | if (sysdev_create_file(s, &attr_capability)) | ||
846 | return NOTIFY_BAD; | ||
847 | break; | ||
848 | case CPU_DEAD: | ||
849 | sysdev_remove_file(s, &attr_capability); | ||
850 | break; | ||
851 | } | ||
852 | return NOTIFY_OK; | ||
853 | } | ||
854 | |||
855 | static struct notifier_block __cpuinitdata smp_cpu_nb = { | ||
856 | .notifier_call = smp_cpu_notify, | ||
857 | }; | ||
858 | |||
824 | static int __init topology_init(void) | 859 | static int __init topology_init(void) |
825 | { | 860 | { |
826 | int cpu; | 861 | int cpu; |
827 | int ret; | 862 | |
863 | register_cpu_notifier(&smp_cpu_nb); | ||
828 | 864 | ||
829 | for_each_possible_cpu(cpu) { | 865 | for_each_possible_cpu(cpu) { |
830 | struct cpu *c = &per_cpu(cpu_devices, cpu); | 866 | struct cpu *c = &per_cpu(cpu_devices, cpu); |
867 | struct sys_device *s = &c->sysdev; | ||
831 | 868 | ||
832 | c->hotpluggable = 1; | 869 | c->hotpluggable = 1; |
833 | ret = register_cpu(c, cpu); | 870 | register_cpu(c, cpu); |
834 | if (ret) | 871 | if (!cpu_online(cpu)) |
835 | printk(KERN_WARNING "topology_init: register_cpu %d " | 872 | continue; |
836 | "failed (%d)\n", cpu, ret); | 873 | s = &c->sysdev; |
874 | sysdev_create_file(s, &attr_capability); | ||
837 | } | 875 | } |
838 | return 0; | 876 | return 0; |
839 | } | 877 | } |
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index a0f6db21855a..c210784bdf46 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
6 | sclp_info.o sclp_chp.o | 6 | sclp_info.o sclp_config.o sclp_chp.o |
7 | 7 | ||
8 | obj-$(CONFIG_TN3270) += raw3270.o | 8 | obj-$(CONFIG_TN3270) += raw3270.o |
9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index e03dcf4c5fca..87ac4a3ad49d 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #define EVTYP_CNTLPROGIDENT 0x0B | 27 | #define EVTYP_CNTLPROGIDENT 0x0B |
28 | #define EVTYP_SIGQUIESCE 0x1D | 28 | #define EVTYP_SIGQUIESCE 0x1D |
29 | #define EVTYP_VT220MSG 0x1A | 29 | #define EVTYP_VT220MSG 0x1A |
30 | #define EVTYP_CONFMGMDATA 0x04 | ||
30 | #define EVTYP_SDIAS 0x1C | 31 | #define EVTYP_SDIAS 0x1C |
31 | 32 | ||
32 | #define EVTYP_OPCMD_MASK 0x80000000 | 33 | #define EVTYP_OPCMD_MASK 0x80000000 |
@@ -37,6 +38,7 @@ | |||
37 | #define EVTYP_CTLPROGIDENT_MASK 0x00200000 | 38 | #define EVTYP_CTLPROGIDENT_MASK 0x00200000 |
38 | #define EVTYP_SIGQUIESCE_MASK 0x00000008 | 39 | #define EVTYP_SIGQUIESCE_MASK 0x00000008 |
39 | #define EVTYP_VT220MSG_MASK 0x00000040 | 40 | #define EVTYP_VT220MSG_MASK 0x00000040 |
41 | #define EVTYP_CONFMGMDATA_MASK 0x10000000 | ||
40 | #define EVTYP_SDIAS_MASK 0x00000010 | 42 | #define EVTYP_SDIAS_MASK 0x00000010 |
41 | 43 | ||
42 | #define GNRLMSGFLGS_DOM 0x8000 | 44 | #define GNRLMSGFLGS_DOM 0x8000 |
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c new file mode 100644 index 000000000000..5322e5e54a98 --- /dev/null +++ b/drivers/s390/char/sclp_config.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * drivers/s390/char/sclp_config.c | ||
3 | * | ||
4 | * Copyright IBM Corp. 2007 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/errno.h> | ||
10 | #include <linux/cpu.h> | ||
11 | #include <linux/sysdev.h> | ||
12 | #include <linux/workqueue.h> | ||
13 | #include "sclp.h" | ||
14 | |||
15 | #define TAG "sclp_config: " | ||
16 | |||
17 | struct conf_mgm_data { | ||
18 | u8 reserved; | ||
19 | u8 ev_qualifier; | ||
20 | } __attribute__((packed)); | ||
21 | |||
22 | #define EV_QUAL_CAP_CHANGE 3 | ||
23 | |||
24 | static struct work_struct sclp_cpu_capability_work; | ||
25 | |||
26 | static void sclp_cpu_capability_notify(struct work_struct *work) | ||
27 | { | ||
28 | int cpu; | ||
29 | struct sys_device *sysdev; | ||
30 | |||
31 | printk(KERN_WARNING TAG "cpu capability changed.\n"); | ||
32 | lock_cpu_hotplug(); | ||
33 | for_each_online_cpu(cpu) { | ||
34 | sysdev = get_cpu_sysdev(cpu); | ||
35 | kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); | ||
36 | } | ||
37 | unlock_cpu_hotplug(); | ||
38 | } | ||
39 | |||
40 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) | ||
41 | { | ||
42 | struct conf_mgm_data *cdata; | ||
43 | |||
44 | cdata = (struct conf_mgm_data *)(evbuf + 1); | ||
45 | if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE) | ||
46 | schedule_work(&sclp_cpu_capability_work); | ||
47 | } | ||
48 | |||
49 | static struct sclp_register sclp_conf_register = | ||
50 | { | ||
51 | .receive_mask = EVTYP_CONFMGMDATA_MASK, | ||
52 | .receiver_fn = sclp_conf_receiver_fn, | ||
53 | }; | ||
54 | |||
55 | static int __init sclp_conf_init(void) | ||
56 | { | ||
57 | int rc; | ||
58 | |||
59 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); | ||
60 | |||
61 | rc = sclp_register(&sclp_conf_register); | ||
62 | if (rc) { | ||
63 | printk(KERN_ERR TAG "failed to register (%d).\n", rc); | ||
64 | return rc; | ||
65 | } | ||
66 | |||
67 | if (!(sclp_conf_register.sclp_receive_mask & EVTYP_CONFMGMDATA_MASK)) { | ||
68 | printk(KERN_WARNING TAG "no configuration management.\n"); | ||
69 | sclp_unregister(&sclp_conf_register); | ||
70 | rc = -ENOSYS; | ||
71 | } | ||
72 | return rc; | ||
73 | } | ||
74 | |||
75 | __initcall(sclp_conf_init); | ||
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 090743d2f914..19343f9675c3 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c | |||
@@ -357,6 +357,24 @@ static __init int create_proc_sysinfo(void) | |||
357 | 357 | ||
358 | __initcall(create_proc_sysinfo); | 358 | __initcall(create_proc_sysinfo); |
359 | 359 | ||
360 | int get_cpu_capability(unsigned int *capability) | ||
361 | { | ||
362 | struct sysinfo_1_2_2 *info; | ||
363 | int rc; | ||
364 | |||
365 | info = (void *) get_zeroed_page(GFP_KERNEL); | ||
366 | if (!info) | ||
367 | return -ENOMEM; | ||
368 | rc = stsi(info, 1, 2, 2); | ||
369 | if (rc == -ENOSYS) | ||
370 | goto out; | ||
371 | rc = 0; | ||
372 | *capability = info->capability; | ||
373 | out: | ||
374 | free_page((unsigned long) info); | ||
375 | return rc; | ||
376 | } | ||
377 | |||
360 | /* | 378 | /* |
361 | * CPU capability might have changed. Therefore recalculate loops_per_jiffy. | 379 | * CPU capability might have changed. Therefore recalculate loops_per_jiffy. |
362 | */ | 380 | */ |
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 96a6f80953a9..e0fcea8c64c3 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h | |||
@@ -57,6 +57,7 @@ struct cpuinfo_S390 | |||
57 | 57 | ||
58 | extern void s390_adjust_jiffies(void); | 58 | extern void s390_adjust_jiffies(void); |
59 | extern void print_cpu_info(struct cpuinfo_S390 *); | 59 | extern void print_cpu_info(struct cpuinfo_S390 *); |
60 | extern int get_cpu_capability(unsigned int *); | ||
60 | 61 | ||
61 | /* Lazy FPU handling on uni-processor */ | 62 | /* Lazy FPU handling on uni-processor */ |
62 | extern struct task_struct *last_task_used_math; | 63 | extern struct task_struct *last_task_used_math; |