diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2006-12-04 09:40:30 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-12-04 09:40:30 -0500 |
commit | 740b5706b9c4b3767f597b3ea76654c6f2a800b2 (patch) | |
tree | 370dc09ec8f3abaecc742003ed9d28eecf636c3b /arch/s390 | |
parent | a1a392f0b4f27604811bf8aa8d7636b3b4bc3803 (diff) |
[S390] cpcmd <-> __cpcmd calling issues
In case of reipl cpcmd gets called when all other cpus are not running
anymore. To prevent deadlocks change __cpcmd so that it doesn't take
any locks and call cpcmd or __cpcmd, whatever is correct in the current
context.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/cpcmd.c | 18 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 10 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 10 |
3 files changed, 21 insertions, 17 deletions
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 1eae74e72f95..a5972f1541fe 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
@@ -21,14 +21,15 @@ static DEFINE_SPINLOCK(cpcmd_lock); | |||
21 | static char cpcmd_buf[241]; | 21 | static char cpcmd_buf[241]; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * the caller of __cpcmd has to ensure that the response buffer is below 2 GB | 24 | * __cpcmd has some restrictions over cpcmd |
25 | * - the response buffer must reside below 2GB (if any) | ||
26 | * - __cpcmd is unlocked and therefore not SMP-safe | ||
25 | */ | 27 | */ |
26 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 28 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
27 | { | 29 | { |
28 | unsigned long flags, cmdlen; | 30 | unsigned cmdlen; |
29 | int return_code, return_len; | 31 | int return_code, return_len; |
30 | 32 | ||
31 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
32 | cmdlen = strlen(cmd); | 33 | cmdlen = strlen(cmd); |
33 | BUG_ON(cmdlen > 240); | 34 | BUG_ON(cmdlen > 240); |
34 | memcpy(cpcmd_buf, cmd, cmdlen); | 35 | memcpy(cpcmd_buf, cmd, cmdlen); |
@@ -74,7 +75,6 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
74 | : "+d" (reg3) : "d" (reg2) : "cc"); | 75 | : "+d" (reg3) : "d" (reg2) : "cc"); |
75 | return_code = (int) reg3; | 76 | return_code = (int) reg3; |
76 | } | 77 | } |
77 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
78 | if (response_code != NULL) | 78 | if (response_code != NULL) |
79 | *response_code = return_code; | 79 | *response_code = return_code; |
80 | return return_len; | 80 | return return_len; |
@@ -82,15 +82,18 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
82 | 82 | ||
83 | EXPORT_SYMBOL(__cpcmd); | 83 | EXPORT_SYMBOL(__cpcmd); |
84 | 84 | ||
85 | #ifdef CONFIG_64BIT | ||
86 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 85 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
87 | { | 86 | { |
88 | char *lowbuf; | 87 | char *lowbuf; |
89 | int len; | 88 | int len; |
89 | unsigned long flags; | ||
90 | 90 | ||
91 | if ((rlen == 0) || (response == NULL) | 91 | if ((rlen == 0) || (response == NULL) |
92 | || !((unsigned long)response >> 31)) | 92 | || !((unsigned long)response >> 31)) { |
93 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
93 | len = __cpcmd(cmd, response, rlen, response_code); | 94 | len = __cpcmd(cmd, response, rlen, response_code); |
95 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
96 | } | ||
94 | else { | 97 | else { |
95 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | 98 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); |
96 | if (!lowbuf) { | 99 | if (!lowbuf) { |
@@ -98,7 +101,9 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
98 | "cpcmd: could not allocate response buffer\n"); | 101 | "cpcmd: could not allocate response buffer\n"); |
99 | return -ENOMEM; | 102 | return -ENOMEM; |
100 | } | 103 | } |
104 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
101 | len = __cpcmd(cmd, lowbuf, rlen, response_code); | 105 | len = __cpcmd(cmd, lowbuf, rlen, response_code); |
106 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
102 | memcpy(response, lowbuf, rlen); | 107 | memcpy(response, lowbuf, rlen); |
103 | kfree(lowbuf); | 108 | kfree(lowbuf); |
104 | } | 109 | } |
@@ -106,4 +111,3 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
106 | } | 111 | } |
107 | 112 | ||
108 | EXPORT_SYMBOL(cpcmd); | 113 | EXPORT_SYMBOL(cpcmd); |
109 | #endif /* CONFIG_64BIT */ | ||
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 77f4aff630fe..101b003cfabf 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -677,7 +677,7 @@ void do_reipl(void) | |||
677 | else | 677 | else |
678 | sprintf(buf, "IPL %X LOADPARM '%s'", | 678 | sprintf(buf, "IPL %X LOADPARM '%s'", |
679 | reipl_block_ccw->ipl_info.ccw.devno, loadparm); | 679 | reipl_block_ccw->ipl_info.ccw.devno, loadparm); |
680 | cpcmd(buf, NULL, 0, NULL); | 680 | __cpcmd(buf, NULL, 0, NULL); |
681 | break; | 681 | break; |
682 | case IPL_METHOD_CCW_DIAG: | 682 | case IPL_METHOD_CCW_DIAG: |
683 | diag308(DIAG308_SET, reipl_block_ccw); | 683 | diag308(DIAG308_SET, reipl_block_ccw); |
@@ -691,12 +691,12 @@ void do_reipl(void) | |||
691 | diag308(DIAG308_IPL, NULL); | 691 | diag308(DIAG308_IPL, NULL); |
692 | break; | 692 | break; |
693 | case IPL_METHOD_FCP_RO_VM: | 693 | case IPL_METHOD_FCP_RO_VM: |
694 | cpcmd("IPL", NULL, 0, NULL); | 694 | __cpcmd("IPL", NULL, 0, NULL); |
695 | break; | 695 | break; |
696 | case IPL_METHOD_NONE: | 696 | case IPL_METHOD_NONE: |
697 | default: | 697 | default: |
698 | if (MACHINE_IS_VM) | 698 | if (MACHINE_IS_VM) |
699 | cpcmd("IPL", NULL, 0, NULL); | 699 | __cpcmd("IPL", NULL, 0, NULL); |
700 | diag308(DIAG308_IPL, NULL); | 700 | diag308(DIAG308_IPL, NULL); |
701 | break; | 701 | break; |
702 | } | 702 | } |
@@ -732,9 +732,9 @@ static void do_dump(void) | |||
732 | case IPL_METHOD_CCW_VM: | 732 | case IPL_METHOD_CCW_VM: |
733 | dump_smp_stop_all(); | 733 | dump_smp_stop_all(); |
734 | sprintf(buf, "STORE STATUS"); | 734 | sprintf(buf, "STORE STATUS"); |
735 | cpcmd(buf, NULL, 0, NULL); | 735 | __cpcmd(buf, NULL, 0, NULL); |
736 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); | 736 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); |
737 | cpcmd(buf, NULL, 0, NULL); | 737 | __cpcmd(buf, NULL, 0, NULL); |
738 | break; | 738 | break; |
739 | case IPL_METHOD_CCW_DIAG: | 739 | case IPL_METHOD_CCW_DIAG: |
740 | diag308(DIAG308_SET, dump_block_ccw); | 740 | diag308(DIAG308_SET, dump_block_ccw); |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2aa13e8e000a..9bbef0c65584 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -229,11 +229,11 @@ static void __init conmode_default(void) | |||
229 | char *ptr; | 229 | char *ptr; |
230 | 230 | ||
231 | if (MACHINE_IS_VM) { | 231 | if (MACHINE_IS_VM) { |
232 | __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); | 232 | cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); |
233 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); | 233 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); |
234 | ptr = strstr(query_buffer, "SUBCHANNEL ="); | 234 | ptr = strstr(query_buffer, "SUBCHANNEL ="); |
235 | console_irq = simple_strtoul(ptr + 13, NULL, 16); | 235 | console_irq = simple_strtoul(ptr + 13, NULL, 16); |
236 | __cpcmd("QUERY TERM", query_buffer, 1024, NULL); | 236 | cpcmd("QUERY TERM", query_buffer, 1024, NULL); |
237 | ptr = strstr(query_buffer, "CONMODE"); | 237 | ptr = strstr(query_buffer, "CONMODE"); |
238 | /* | 238 | /* |
239 | * Set the conmode to 3215 so that the device recognition | 239 | * Set the conmode to 3215 so that the device recognition |
@@ -242,7 +242,7 @@ static void __init conmode_default(void) | |||
242 | * 3215 and the 3270 driver will try to access the console | 242 | * 3215 and the 3270 driver will try to access the console |
243 | * device (3215 as console and 3270 as normal tty). | 243 | * device (3215 as console and 3270 as normal tty). |
244 | */ | 244 | */ |
245 | __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); | 245 | cpcmd("TERM CONMODE 3215", NULL, 0, NULL); |
246 | if (ptr == NULL) { | 246 | if (ptr == NULL) { |
247 | #if defined(CONFIG_SCLP_CONSOLE) | 247 | #if defined(CONFIG_SCLP_CONSOLE) |
248 | SET_CONSOLE_SCLP; | 248 | SET_CONSOLE_SCLP; |
@@ -299,14 +299,14 @@ static void do_machine_restart_nonsmp(char * __unused) | |||
299 | static void do_machine_halt_nonsmp(void) | 299 | static void do_machine_halt_nonsmp(void) |
300 | { | 300 | { |
301 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) | 301 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) |
302 | cpcmd(vmhalt_cmd, NULL, 0, NULL); | 302 | __cpcmd(vmhalt_cmd, NULL, 0, NULL); |
303 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 303 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
304 | } | 304 | } |
305 | 305 | ||
306 | static void do_machine_power_off_nonsmp(void) | 306 | static void do_machine_power_off_nonsmp(void) |
307 | { | 307 | { |
308 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | 308 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) |
309 | cpcmd(vmpoff_cmd, NULL, 0, NULL); | 309 | __cpcmd(vmpoff_cmd, NULL, 0, NULL); |
310 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 310 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
311 | } | 311 | } |
312 | 312 | ||