aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/smp.h12
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/ipl.c31
-rw-r--r--arch/s390/kernel/machine_kexec.c10
-rw-r--r--arch/s390/kernel/smp.c36
-rw-r--r--arch/s390/kernel/switch_cpu.S59
-rw-r--r--arch/s390/kernel/switch_cpu64.S52
7 files changed, 191 insertions, 11 deletions
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h
index 9d2acb0b4847..c2d0e638f892 100644
--- a/arch/s390/include/asm/smp.h
+++ b/arch/s390/include/asm/smp.h
@@ -31,6 +31,18 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
31 31
32extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; 32extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1];
33 33
34extern void smp_switch_to_ipl_cpu(void (*func)(void *), void *);
35extern void smp_switch_to_cpu(void (*)(void *), void *, unsigned long sp,
36 int from, int to);
37extern void smp_restart_cpu(void);
38
39#else /* CONFIG_SMP */
40
41static inline void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
42{
43 func(data);
44}
45
34#endif /* CONFIG_SMP */ 46#endif /* CONFIG_SMP */
35 47
36#ifdef CONFIG_HOTPLUG_CPU 48#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 683f6381cc59..20f861256774 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -32,6 +32,8 @@ extra-y += head.o init_task.o vmlinux.lds
32 32
33obj-$(CONFIG_MODULES) += s390_ksyms.o module.o 33obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
34obj-$(CONFIG_SMP) += smp.o topology.o 34obj-$(CONFIG_SMP) += smp.o topology.o
35obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \
36 switch_cpu.o)
35obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o 37obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o
36obj-$(CONFIG_AUDIT) += audit.o 38obj-$(CONFIG_AUDIT) += audit.o
37compat-obj-$(CONFIG_AUDIT) += compat_audit.o 39compat-obj-$(CONFIG_AUDIT) += compat_audit.o
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 4d73296fed74..0a7c39dee6b7 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -553,7 +553,7 @@ out:
553 return rc; 553 return rc;
554} 554}
555 555
556static void ipl_run(struct shutdown_trigger *trigger) 556static void __ipl_run(void *unused)
557{ 557{
558 diag308(DIAG308_IPL, NULL); 558 diag308(DIAG308_IPL, NULL);
559 if (MACHINE_IS_VM) 559 if (MACHINE_IS_VM)
@@ -562,6 +562,11 @@ static void ipl_run(struct shutdown_trigger *trigger)
562 reipl_ccw_dev(&ipl_info.data.ccw.dev_id); 562 reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
563} 563}
564 564
565static void ipl_run(struct shutdown_trigger *trigger)
566{
567 smp_switch_to_ipl_cpu(__ipl_run, NULL);
568}
569
565static int __init ipl_init(void) 570static int __init ipl_init(void)
566{ 571{
567 int rc; 572 int rc;
@@ -1039,7 +1044,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb,
1039 sprintf(dst + pos, " PARM %s", vmparm); 1044 sprintf(dst + pos, " PARM %s", vmparm);
1040} 1045}
1041 1046
1042static void reipl_run(struct shutdown_trigger *trigger) 1047static void __reipl_run(void *unused)
1043{ 1048{
1044 struct ccw_dev_id devid; 1049 struct ccw_dev_id devid;
1045 static char buf[128]; 1050 static char buf[128];
@@ -1087,6 +1092,11 @@ static void reipl_run(struct shutdown_trigger *trigger)
1087 disabled_wait((unsigned long) __builtin_return_address(0)); 1092 disabled_wait((unsigned long) __builtin_return_address(0));
1088} 1093}
1089 1094
1095static void reipl_run(struct shutdown_trigger *trigger)
1096{
1097 smp_switch_to_ipl_cpu(__reipl_run, NULL);
1098}
1099
1090static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) 1100static void reipl_block_ccw_init(struct ipl_parameter_block *ipb)
1091{ 1101{
1092 ipb->hdr.len = IPL_PARM_BLK_CCW_LEN; 1102 ipb->hdr.len = IPL_PARM_BLK_CCW_LEN;
@@ -1369,20 +1379,18 @@ static struct kobj_attribute dump_type_attr =
1369 1379
1370static struct kset *dump_kset; 1380static struct kset *dump_kset;
1371 1381
1372static void dump_run(struct shutdown_trigger *trigger) 1382static void __dump_run(void *unused)
1373{ 1383{
1374 struct ccw_dev_id devid; 1384 struct ccw_dev_id devid;
1375 static char buf[100]; 1385 static char buf[100];
1376 1386
1377 switch (dump_method) { 1387 switch (dump_method) {
1378 case DUMP_METHOD_CCW_CIO: 1388 case DUMP_METHOD_CCW_CIO:
1379 smp_send_stop();
1380 devid.devno = dump_block_ccw->ipl_info.ccw.devno; 1389 devid.devno = dump_block_ccw->ipl_info.ccw.devno;
1381 devid.ssid = 0; 1390 devid.ssid = 0;
1382 reipl_ccw_dev(&devid); 1391 reipl_ccw_dev(&devid);
1383 break; 1392 break;
1384 case DUMP_METHOD_CCW_VM: 1393 case DUMP_METHOD_CCW_VM:
1385 smp_send_stop();
1386 sprintf(buf, "STORE STATUS"); 1394 sprintf(buf, "STORE STATUS");
1387 __cpcmd(buf, NULL, 0, NULL); 1395 __cpcmd(buf, NULL, 0, NULL);
1388 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); 1396 sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
@@ -1396,10 +1404,17 @@ static void dump_run(struct shutdown_trigger *trigger)
1396 diag308(DIAG308_SET, dump_block_fcp); 1404 diag308(DIAG308_SET, dump_block_fcp);
1397 diag308(DIAG308_DUMP, NULL); 1405 diag308(DIAG308_DUMP, NULL);
1398 break; 1406 break;
1399 case DUMP_METHOD_NONE: 1407 default:
1400 return; 1408 break;
1401 } 1409 }
1402 printk(KERN_EMERG "Dump failed!\n"); 1410}
1411
1412static void dump_run(struct shutdown_trigger *trigger)
1413{
1414 if (dump_method == DUMP_METHOD_NONE)
1415 return;
1416 smp_send_stop();
1417 smp_switch_to_ipl_cpu(__dump_run, NULL);
1403} 1418}
1404 1419
1405static int __init dump_ccw_init(void) 1420static int __init dump_ccw_init(void)
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index 131d7ee8b416..a922d51df6bf 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -54,11 +54,11 @@ void machine_shutdown(void)
54{ 54{
55} 55}
56 56
57void machine_kexec(struct kimage *image) 57static void __machine_kexec(void *data)
58{ 58{
59 relocate_kernel_t data_mover; 59 relocate_kernel_t data_mover;
60 struct kimage *image = data;
60 61
61 smp_send_stop();
62 pfault_fini(); 62 pfault_fini();
63 s390_reset_system(); 63 s390_reset_system();
64 64
@@ -68,3 +68,9 @@ void machine_kexec(struct kimage *image)
68 (*data_mover)(&image->head, image->start); 68 (*data_mover)(&image->head, image->start);
69 for (;;); 69 for (;;);
70} 70}
71
72void machine_kexec(struct kimage *image)
73{
74 smp_send_stop();
75 smp_switch_to_ipl_cpu(__machine_kexec, image);
76}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 384a6846a65e..b39f596d71bd 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -90,6 +90,39 @@ static int cpu_stopped(int cpu)
90 return 0; 90 return 0;
91} 91}
92 92
93void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
94{
95 struct _lowcore *lc, *current_lc;
96 struct stack_frame *sf;
97 struct pt_regs *regs;
98 unsigned long sp;
99
100 if (smp_processor_id() == 0)
101 func(data);
102 __load_psw_mask(PSW_BASE_BITS | PSW_DEFAULT_KEY);
103 /* Disable lowcore protection */
104 __ctl_clear_bit(0, 28);
105 current_lc = lowcore_ptr[smp_processor_id()];
106 lc = lowcore_ptr[0];
107 if (!lc)
108 lc = current_lc;
109 lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
110 lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu;
111 if (!cpu_online(0))
112 smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]);
113 while (signal_processor(0, sigp_stop_and_store_status) == sigp_busy)
114 cpu_relax();
115 sp = lc->panic_stack;
116 sp -= sizeof(struct pt_regs);
117 regs = (struct pt_regs *) sp;
118 memcpy(&regs->gprs, &current_lc->gpregs_save_area, sizeof(regs->gprs));
119 memcpy(&regs->psw, &current_lc->st_status_fixed_logout, sizeof(psw_t));
120 sp -= STACK_FRAME_OVERHEAD;
121 sf = (struct stack_frame *) sp;
122 sf->back_chain = regs->gprs[15];
123 smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]);
124}
125
93void smp_send_stop(void) 126void smp_send_stop(void)
94{ 127{
95 int cpu, rc; 128 int cpu, rc;
@@ -752,7 +785,8 @@ static ssize_t cpu_configure_store(struct sys_device *dev,
752 get_online_cpus(); 785 get_online_cpus();
753 mutex_lock(&smp_cpu_state_mutex); 786 mutex_lock(&smp_cpu_state_mutex);
754 rc = -EBUSY; 787 rc = -EBUSY;
755 if (cpu_online(cpu)) 788 /* disallow configuration changes of online cpus and cpu 0 */
789 if (cpu_online(cpu) || cpu == 0)
756 goto out; 790 goto out;
757 rc = 0; 791 rc = 0;
758 switch (val) { 792 switch (val) {
diff --git a/arch/s390/kernel/switch_cpu.S b/arch/s390/kernel/switch_cpu.S
new file mode 100644
index 000000000000..c05ee6c221d8
--- /dev/null
+++ b/arch/s390/kernel/switch_cpu.S
@@ -0,0 +1,59 @@
1/*
2 * 31-bit switch cpu code
3 *
4 * Copyright IBM Corp. 2009
5 *
6 */
7
8#include <asm/asm-offsets.h>
9#include <asm/lowcore.h>
10#include <asm/ptrace.h>
11
12# smp_switch_to_cpu switches to destination cpu and executes the passed function
13# Parameter: %r2 - function to call
14# %r3 - function parameter
15# %r4 - stack poiner
16# %r5 - current cpu
17# %r6 - destination cpu
18
19 .section .text
20 .align 4
21 .globl smp_switch_to_cpu
22smp_switch_to_cpu:
23 stm %r6,%r15,__SF_GPRS(%r15)
24 lr %r1,%r15
25 ahi %r15,-STACK_FRAME_OVERHEAD
26 st %r1,__SF_BACKCHAIN(%r15)
27 basr %r13,0
280: la %r1,.gprregs_addr-0b(%r13)
29 l %r1,0(%r1)
30 stm %r0,%r15,0(%r1)
311: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */
32 brc 2,1b /* busy, try again */
332: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */
34 brc 2,2b /* busy, try again */
353: j 3b
36
37 .globl smp_restart_cpu
38smp_restart_cpu:
39 basr %r13,0
400: la %r1,.gprregs_addr-0b(%r13)
41 l %r1,0(%r1)
42 lm %r0,%r15,0(%r1)
431: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */
44 brc 10,1b /* busy, accepted (status 0), running */
45 tmll %r0,0x40 /* Test if calling CPU is stopped */
46 jz 1b
47 ltr %r4,%r4 /* New stack ? */
48 jz 1f
49 lr %r15,%r4
501: basr %r14,%r2
51
52.gprregs_addr:
53 .long .gprregs
54
55 .section .data,"aw",@progbits
56.gprregs:
57 .rept 16
58 .long 0
59 .endr
diff --git a/arch/s390/kernel/switch_cpu64.S b/arch/s390/kernel/switch_cpu64.S
new file mode 100644
index 000000000000..c73ede3c1d68
--- /dev/null
+++ b/arch/s390/kernel/switch_cpu64.S
@@ -0,0 +1,52 @@
1/*
2 * 64-bit switch cpu code
3 *
4 * Copyright IBM Corp. 2009
5 *
6 */
7
8#include <asm/asm-offsets.h>
9#include <asm/lowcore.h>
10#include <asm/ptrace.h>
11
12# smp_switch_to_cpu switches to destination cpu and executes the passed function
13# Parameter: %r2 - function to call
14# %r3 - function parameter
15# %r4 - stack poiner
16# %r5 - current cpu
17# %r6 - destination cpu
18
19 .section .text
20 .align 4
21 .globl smp_switch_to_cpu
22smp_switch_to_cpu:
23 stmg %r6,%r15,__SF_GPRS(%r15)
24 lgr %r1,%r15
25 aghi %r15,-STACK_FRAME_OVERHEAD
26 stg %r1,__SF_BACKCHAIN(%r15)
27 larl %r1,.gprregs
28 stmg %r0,%r15,0(%r1)
291: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */
30 brc 2,1b /* busy, try again */
312: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */
32 brc 2,2b /* busy, try again */
333: j 3b
34
35 .globl smp_restart_cpu
36smp_restart_cpu:
37 larl %r1,.gprregs
38 lmg %r0,%r15,0(%r1)
391: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */
40 brc 10,1b /* busy, accepted (status 0), running */
41 tmll %r0,0x40 /* Test if calling CPU is stopped */
42 jz 1b
43 ltgr %r4,%r4 /* New stack ? */
44 jz 1f
45 lgr %r15,%r4
461: basr %r14,%r2
47
48 .section .data,"aw",@progbits
49.gprregs:
50 .rept 16
51 .quad 0
52 .endr