diff options
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r-- | arch/s390/kernel/smp.c | 132 |
1 files changed, 82 insertions, 50 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 93e52039321b..e4d98de83dd8 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/cpu.h> | 36 | #include <linux/cpu.h> |
37 | #include <linux/timex.h> | 37 | #include <linux/timex.h> |
38 | #include <linux/bootmem.h> | 38 | #include <linux/bootmem.h> |
39 | #include <linux/slab.h> | ||
40 | #include <asm/asm-offsets.h> | ||
39 | #include <asm/ipl.h> | 41 | #include <asm/ipl.h> |
40 | #include <asm/setup.h> | 42 | #include <asm/setup.h> |
41 | #include <asm/sigp.h> | 43 | #include <asm/sigp.h> |
@@ -52,6 +54,9 @@ | |||
52 | #include <asm/cpu.h> | 54 | #include <asm/cpu.h> |
53 | #include "entry.h" | 55 | #include "entry.h" |
54 | 56 | ||
57 | /* logical cpu to cpu address */ | ||
58 | unsigned short __cpu_logical_map[NR_CPUS]; | ||
59 | |||
55 | static struct task_struct *current_set[NR_CPUS]; | 60 | static struct task_struct *current_set[NR_CPUS]; |
56 | 61 | ||
57 | static u8 smp_cpu_type; | 62 | static u8 smp_cpu_type; |
@@ -69,13 +74,13 @@ static int cpu_management; | |||
69 | 74 | ||
70 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 75 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
71 | 76 | ||
72 | static void smp_ext_bitcall(int, ec_bit_sig); | 77 | static void smp_ext_bitcall(int, int); |
73 | 78 | ||
74 | static int cpu_stopped(int cpu) | 79 | static int raw_cpu_stopped(int cpu) |
75 | { | 80 | { |
76 | __u32 status; | 81 | u32 status; |
77 | 82 | ||
78 | switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) { | 83 | switch (raw_sigp_ps(&status, 0, cpu, sigp_sense)) { |
79 | case sigp_status_stored: | 84 | case sigp_status_stored: |
80 | /* Check for stopped and check stop state */ | 85 | /* Check for stopped and check stop state */ |
81 | if (status & 0x50) | 86 | if (status & 0x50) |
@@ -87,6 +92,44 @@ static int cpu_stopped(int cpu) | |||
87 | return 0; | 92 | return 0; |
88 | } | 93 | } |
89 | 94 | ||
95 | static inline int cpu_stopped(int cpu) | ||
96 | { | ||
97 | return raw_cpu_stopped(cpu_logical_map(cpu)); | ||
98 | } | ||
99 | |||
100 | void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) | ||
101 | { | ||
102 | struct _lowcore *lc, *current_lc; | ||
103 | struct stack_frame *sf; | ||
104 | struct pt_regs *regs; | ||
105 | unsigned long sp; | ||
106 | |||
107 | if (smp_processor_id() == 0) | ||
108 | func(data); | ||
109 | __load_psw_mask(PSW_BASE_BITS | PSW_DEFAULT_KEY); | ||
110 | /* Disable lowcore protection */ | ||
111 | __ctl_clear_bit(0, 28); | ||
112 | current_lc = lowcore_ptr[smp_processor_id()]; | ||
113 | lc = lowcore_ptr[0]; | ||
114 | if (!lc) | ||
115 | lc = current_lc; | ||
116 | lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; | ||
117 | lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu; | ||
118 | if (!cpu_online(0)) | ||
119 | smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]); | ||
120 | while (sigp(0, sigp_stop_and_store_status) == sigp_busy) | ||
121 | cpu_relax(); | ||
122 | sp = lc->panic_stack; | ||
123 | sp -= sizeof(struct pt_regs); | ||
124 | regs = (struct pt_regs *) sp; | ||
125 | memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); | ||
126 | regs->psw = lc->psw_save_area; | ||
127 | sp -= STACK_FRAME_OVERHEAD; | ||
128 | sf = (struct stack_frame *) sp; | ||
129 | sf->back_chain = regs->gprs[15]; | ||
130 | smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); | ||
131 | } | ||
132 | |||
90 | void smp_send_stop(void) | 133 | void smp_send_stop(void) |
91 | { | 134 | { |
92 | int cpu, rc; | 135 | int cpu, rc; |
@@ -100,7 +143,7 @@ void smp_send_stop(void) | |||
100 | if (cpu == smp_processor_id()) | 143 | if (cpu == smp_processor_id()) |
101 | continue; | 144 | continue; |
102 | do { | 145 | do { |
103 | rc = signal_processor(cpu, sigp_stop); | 146 | rc = sigp(cpu, sigp_stop); |
104 | } while (rc == sigp_busy); | 147 | } while (rc == sigp_busy); |
105 | 148 | ||
106 | while (!cpu_stopped(cpu)) | 149 | while (!cpu_stopped(cpu)) |
@@ -136,13 +179,13 @@ static void do_ext_call_interrupt(__u16 code) | |||
136 | * Send an external call sigp to another cpu and return without waiting | 179 | * Send an external call sigp to another cpu and return without waiting |
137 | * for its completion. | 180 | * for its completion. |
138 | */ | 181 | */ |
139 | static void smp_ext_bitcall(int cpu, ec_bit_sig sig) | 182 | static void smp_ext_bitcall(int cpu, int sig) |
140 | { | 183 | { |
141 | /* | 184 | /* |
142 | * Set signaling bit in lowcore of target cpu and kick it | 185 | * Set signaling bit in lowcore of target cpu and kick it |
143 | */ | 186 | */ |
144 | set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); | 187 | set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); |
145 | while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy) | 188 | while (sigp(cpu, sigp_emergency_signal) == sigp_busy) |
146 | udelay(10); | 189 | udelay(10); |
147 | } | 190 | } |
148 | 191 | ||
@@ -236,24 +279,8 @@ void smp_ctl_clear_bit(int cr, int bit) | |||
236 | } | 279 | } |
237 | EXPORT_SYMBOL(smp_ctl_clear_bit); | 280 | EXPORT_SYMBOL(smp_ctl_clear_bit); |
238 | 281 | ||
239 | /* | ||
240 | * In early ipl state a temp. logically cpu number is needed, so the sigp | ||
241 | * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on | ||
242 | * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1. | ||
243 | */ | ||
244 | #define CPU_INIT_NO 1 | ||
245 | |||
246 | #ifdef CONFIG_ZFCPDUMP | 282 | #ifdef CONFIG_ZFCPDUMP |
247 | 283 | ||
248 | /* | ||
249 | * zfcpdump_prefix_array holds prefix registers for the following scenario: | ||
250 | * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to | ||
251 | * save its prefix registers, since they get lost, when switching from 31 bit | ||
252 | * to 64 bit. | ||
253 | */ | ||
254 | unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \ | ||
255 | __attribute__((__section__(".data"))); | ||
256 | |||
257 | static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) | 284 | static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) |
258 | { | 285 | { |
259 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) | 286 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) |
@@ -263,21 +290,15 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) | |||
263 | "the dump\n", cpu, NR_CPUS - 1); | 290 | "the dump\n", cpu, NR_CPUS - 1); |
264 | return; | 291 | return; |
265 | } | 292 | } |
266 | zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL); | 293 | zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL); |
267 | __cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu; | 294 | while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) |
268 | while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) == | ||
269 | sigp_busy) | ||
270 | cpu_relax(); | 295 | cpu_relax(); |
271 | memcpy(zfcpdump_save_areas[cpu], | 296 | memcpy_real(zfcpdump_save_areas[cpu], |
272 | (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, | 297 | (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, |
273 | SAVE_AREA_SIZE); | 298 | sizeof(struct save_area)); |
274 | #ifdef CONFIG_64BIT | ||
275 | /* copy original prefix register */ | ||
276 | zfcpdump_save_areas[cpu]->s390x.pref_reg = zfcpdump_prefix_array[cpu]; | ||
277 | #endif | ||
278 | } | 299 | } |
279 | 300 | ||
280 | union save_area *zfcpdump_save_areas[NR_CPUS + 1]; | 301 | struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; |
281 | EXPORT_SYMBOL_GPL(zfcpdump_save_areas); | 302 | EXPORT_SYMBOL_GPL(zfcpdump_save_areas); |
282 | 303 | ||
283 | #else | 304 | #else |
@@ -386,8 +407,7 @@ static void __init smp_detect_cpus(void) | |||
386 | for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) { | 407 | for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) { |
387 | if (cpu == boot_cpu_addr) | 408 | if (cpu == boot_cpu_addr) |
388 | continue; | 409 | continue; |
389 | __cpu_logical_map[CPU_INIT_NO] = cpu; | 410 | if (!raw_cpu_stopped(cpu)) |
390 | if (!cpu_stopped(CPU_INIT_NO)) | ||
391 | continue; | 411 | continue; |
392 | smp_get_save_area(c_cpus, cpu); | 412 | smp_get_save_area(c_cpus, cpu); |
393 | c_cpus++; | 413 | c_cpus++; |
@@ -410,8 +430,7 @@ static void __init smp_detect_cpus(void) | |||
410 | cpu_addr = info->cpu[cpu].address; | 430 | cpu_addr = info->cpu[cpu].address; |
411 | if (cpu_addr == boot_cpu_addr) | 431 | if (cpu_addr == boot_cpu_addr) |
412 | continue; | 432 | continue; |
413 | __cpu_logical_map[CPU_INIT_NO] = cpu_addr; | 433 | if (!raw_cpu_stopped(cpu_addr)) { |
414 | if (!cpu_stopped(CPU_INIT_NO)) { | ||
415 | s_cpus++; | 434 | s_cpus++; |
416 | continue; | 435 | continue; |
417 | } | 436 | } |
@@ -530,18 +549,18 @@ static void smp_free_lowcore(int cpu) | |||
530 | /* Upping and downing of CPUs */ | 549 | /* Upping and downing of CPUs */ |
531 | int __cpuinit __cpu_up(unsigned int cpu) | 550 | int __cpuinit __cpu_up(unsigned int cpu) |
532 | { | 551 | { |
533 | struct task_struct *idle; | ||
534 | struct _lowcore *cpu_lowcore; | 552 | struct _lowcore *cpu_lowcore; |
553 | struct task_struct *idle; | ||
535 | struct stack_frame *sf; | 554 | struct stack_frame *sf; |
536 | sigp_ccode ccode; | ||
537 | u32 lowcore; | 555 | u32 lowcore; |
556 | int ccode; | ||
538 | 557 | ||
539 | if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED) | 558 | if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED) |
540 | return -EIO; | 559 | return -EIO; |
541 | if (smp_alloc_lowcore(cpu)) | 560 | if (smp_alloc_lowcore(cpu)) |
542 | return -ENOMEM; | 561 | return -ENOMEM; |
543 | do { | 562 | do { |
544 | ccode = signal_processor(cpu, sigp_initial_cpu_reset); | 563 | ccode = sigp(cpu, sigp_initial_cpu_reset); |
545 | if (ccode == sigp_busy) | 564 | if (ccode == sigp_busy) |
546 | udelay(10); | 565 | udelay(10); |
547 | if (ccode == sigp_not_operational) | 566 | if (ccode == sigp_not_operational) |
@@ -549,7 +568,7 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
549 | } while (ccode == sigp_busy); | 568 | } while (ccode == sigp_busy); |
550 | 569 | ||
551 | lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; | 570 | lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; |
552 | while (signal_processor_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) | 571 | while (sigp_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) |
553 | udelay(10); | 572 | udelay(10); |
554 | 573 | ||
555 | idle = current_set[cpu]; | 574 | idle = current_set[cpu]; |
@@ -575,7 +594,7 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
575 | cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func; | 594 | cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func; |
576 | eieio(); | 595 | eieio(); |
577 | 596 | ||
578 | while (signal_processor(cpu, sigp_restart) == sigp_busy) | 597 | while (sigp(cpu, sigp_restart) == sigp_busy) |
579 | udelay(10); | 598 | udelay(10); |
580 | 599 | ||
581 | while (!cpu_online(cpu)) | 600 | while (!cpu_online(cpu)) |
@@ -637,7 +656,7 @@ void __cpu_die(unsigned int cpu) | |||
637 | /* Wait until target cpu is down */ | 656 | /* Wait until target cpu is down */ |
638 | while (!cpu_stopped(cpu)) | 657 | while (!cpu_stopped(cpu)) |
639 | cpu_relax(); | 658 | cpu_relax(); |
640 | while (signal_processor_p(0, cpu, sigp_set_prefix) == sigp_busy) | 659 | while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy) |
641 | udelay(10); | 660 | udelay(10); |
642 | smp_free_lowcore(cpu); | 661 | smp_free_lowcore(cpu); |
643 | pr_info("Processor %d stopped\n", cpu); | 662 | pr_info("Processor %d stopped\n", cpu); |
@@ -646,7 +665,7 @@ void __cpu_die(unsigned int cpu) | |||
646 | void cpu_die(void) | 665 | void cpu_die(void) |
647 | { | 666 | { |
648 | idle_task_exit(); | 667 | idle_task_exit(); |
649 | while (signal_processor(smp_processor_id(), sigp_stop) == sigp_busy) | 668 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) |
650 | cpu_relax(); | 669 | cpu_relax(); |
651 | for (;;); | 670 | for (;;); |
652 | } | 671 | } |
@@ -717,6 +736,12 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
717 | { | 736 | { |
718 | } | 737 | } |
719 | 738 | ||
739 | void __init smp_setup_processor_id(void) | ||
740 | { | ||
741 | S390_lowcore.cpu_nr = 0; | ||
742 | __cpu_logical_map[0] = stap(); | ||
743 | } | ||
744 | |||
720 | /* | 745 | /* |
721 | * the frequency of the profiling timer can be changed | 746 | * the frequency of the profiling timer can be changed |
722 | * by writing a multiplier value into /proc/profile. | 747 | * by writing a multiplier value into /proc/profile. |
@@ -756,7 +781,8 @@ static ssize_t cpu_configure_store(struct sys_device *dev, | |||
756 | get_online_cpus(); | 781 | get_online_cpus(); |
757 | mutex_lock(&smp_cpu_state_mutex); | 782 | mutex_lock(&smp_cpu_state_mutex); |
758 | rc = -EBUSY; | 783 | rc = -EBUSY; |
759 | if (cpu_online(cpu)) | 784 | /* disallow configuration changes of online cpus and cpu 0 */ |
785 | if (cpu_online(cpu) || cpu == 0) | ||
760 | goto out; | 786 | goto out; |
761 | rc = 0; | 787 | rc = 0; |
762 | switch (val) { | 788 | switch (val) { |
@@ -995,7 +1021,9 @@ out: | |||
995 | return rc; | 1021 | return rc; |
996 | } | 1022 | } |
997 | 1023 | ||
998 | static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf, | 1024 | static ssize_t __ref rescan_store(struct sysdev_class *class, |
1025 | struct sysdev_class_attribute *attr, | ||
1026 | const char *buf, | ||
999 | size_t count) | 1027 | size_t count) |
1000 | { | 1028 | { |
1001 | int rc; | 1029 | int rc; |
@@ -1006,7 +1034,9 @@ static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf, | |||
1006 | static SYSDEV_CLASS_ATTR(rescan, 0200, NULL, rescan_store); | 1034 | static SYSDEV_CLASS_ATTR(rescan, 0200, NULL, rescan_store); |
1007 | #endif /* CONFIG_HOTPLUG_CPU */ | 1035 | #endif /* CONFIG_HOTPLUG_CPU */ |
1008 | 1036 | ||
1009 | static ssize_t dispatching_show(struct sysdev_class *class, char *buf) | 1037 | static ssize_t dispatching_show(struct sysdev_class *class, |
1038 | struct sysdev_class_attribute *attr, | ||
1039 | char *buf) | ||
1010 | { | 1040 | { |
1011 | ssize_t count; | 1041 | ssize_t count; |
1012 | 1042 | ||
@@ -1016,7 +1046,9 @@ static ssize_t dispatching_show(struct sysdev_class *class, char *buf) | |||
1016 | return count; | 1046 | return count; |
1017 | } | 1047 | } |
1018 | 1048 | ||
1019 | static ssize_t dispatching_store(struct sysdev_class *dev, const char *buf, | 1049 | static ssize_t dispatching_store(struct sysdev_class *dev, |
1050 | struct sysdev_class_attribute *attr, | ||
1051 | const char *buf, | ||
1020 | size_t count) | 1052 | size_t count) |
1021 | { | 1053 | { |
1022 | int val, rc; | 1054 | int val, rc; |