diff options
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r-- | arch/s390/kernel/ipl.c | 99 |
1 files changed, 58 insertions, 41 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index affa8e68124a..8342e65a140d 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * arch/s390/kernel/ipl.c | 2 | * arch/s390/kernel/ipl.c |
3 | * ipl/reipl/dump support for Linux on s390. | 3 | * ipl/reipl/dump support for Linux on s390. |
4 | * | 4 | * |
5 | * Copyright IBM Corp. 2005,2007 | 5 | * Copyright IBM Corp. 2005,2012 |
6 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> | 6 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> |
7 | * Heiko Carstens <heiko.carstens@de.ibm.com> | 7 | * Heiko Carstens <heiko.carstens@de.ibm.com> |
8 | * Volker Sameske <sameske@de.ibm.com> | 8 | * Volker Sameske <sameske@de.ibm.com> |
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/gfp.h> | 18 | #include <linux/gfp.h> |
19 | #include <linux/crash_dump.h> | 19 | #include <linux/crash_dump.h> |
20 | #include <linux/debug_locks.h> | ||
20 | #include <asm/ipl.h> | 21 | #include <asm/ipl.h> |
21 | #include <asm/smp.h> | 22 | #include <asm/smp.h> |
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
@@ -25,8 +26,9 @@ | |||
25 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
26 | #include <asm/reset.h> | 27 | #include <asm/reset.h> |
27 | #include <asm/sclp.h> | 28 | #include <asm/sclp.h> |
28 | #include <asm/sigp.h> | ||
29 | #include <asm/checksum.h> | 29 | #include <asm/checksum.h> |
30 | #include <asm/debug.h> | ||
31 | #include <asm/os_info.h> | ||
30 | #include "entry.h" | 32 | #include "entry.h" |
31 | 33 | ||
32 | #define IPL_PARM_BLOCK_VERSION 0 | 34 | #define IPL_PARM_BLOCK_VERSION 0 |
@@ -571,7 +573,7 @@ static void __ipl_run(void *unused) | |||
571 | 573 | ||
572 | static void ipl_run(struct shutdown_trigger *trigger) | 574 | static void ipl_run(struct shutdown_trigger *trigger) |
573 | { | 575 | { |
574 | smp_switch_to_ipl_cpu(__ipl_run, NULL); | 576 | smp_call_ipl_cpu(__ipl_run, NULL); |
575 | } | 577 | } |
576 | 578 | ||
577 | static int __init ipl_init(void) | 579 | static int __init ipl_init(void) |
@@ -950,6 +952,13 @@ static struct attribute_group reipl_nss_attr_group = { | |||
950 | .attrs = reipl_nss_attrs, | 952 | .attrs = reipl_nss_attrs, |
951 | }; | 953 | }; |
952 | 954 | ||
955 | static void set_reipl_block_actual(struct ipl_parameter_block *reipl_block) | ||
956 | { | ||
957 | reipl_block_actual = reipl_block; | ||
958 | os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual, | ||
959 | reipl_block->hdr.len); | ||
960 | } | ||
961 | |||
953 | /* reipl type */ | 962 | /* reipl type */ |
954 | 963 | ||
955 | static int reipl_set_type(enum ipl_type type) | 964 | static int reipl_set_type(enum ipl_type type) |
@@ -965,7 +974,7 @@ static int reipl_set_type(enum ipl_type type) | |||
965 | reipl_method = REIPL_METHOD_CCW_VM; | 974 | reipl_method = REIPL_METHOD_CCW_VM; |
966 | else | 975 | else |
967 | reipl_method = REIPL_METHOD_CCW_CIO; | 976 | reipl_method = REIPL_METHOD_CCW_CIO; |
968 | reipl_block_actual = reipl_block_ccw; | 977 | set_reipl_block_actual(reipl_block_ccw); |
969 | break; | 978 | break; |
970 | case IPL_TYPE_FCP: | 979 | case IPL_TYPE_FCP: |
971 | if (diag308_set_works) | 980 | if (diag308_set_works) |
@@ -974,7 +983,7 @@ static int reipl_set_type(enum ipl_type type) | |||
974 | reipl_method = REIPL_METHOD_FCP_RO_VM; | 983 | reipl_method = REIPL_METHOD_FCP_RO_VM; |
975 | else | 984 | else |
976 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; | 985 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; |
977 | reipl_block_actual = reipl_block_fcp; | 986 | set_reipl_block_actual(reipl_block_fcp); |
978 | break; | 987 | break; |
979 | case IPL_TYPE_FCP_DUMP: | 988 | case IPL_TYPE_FCP_DUMP: |
980 | reipl_method = REIPL_METHOD_FCP_DUMP; | 989 | reipl_method = REIPL_METHOD_FCP_DUMP; |
@@ -984,7 +993,7 @@ static int reipl_set_type(enum ipl_type type) | |||
984 | reipl_method = REIPL_METHOD_NSS_DIAG; | 993 | reipl_method = REIPL_METHOD_NSS_DIAG; |
985 | else | 994 | else |
986 | reipl_method = REIPL_METHOD_NSS; | 995 | reipl_method = REIPL_METHOD_NSS; |
987 | reipl_block_actual = reipl_block_nss; | 996 | set_reipl_block_actual(reipl_block_nss); |
988 | break; | 997 | break; |
989 | case IPL_TYPE_UNKNOWN: | 998 | case IPL_TYPE_UNKNOWN: |
990 | reipl_method = REIPL_METHOD_DEFAULT; | 999 | reipl_method = REIPL_METHOD_DEFAULT; |
@@ -1101,7 +1110,7 @@ static void __reipl_run(void *unused) | |||
1101 | 1110 | ||
1102 | static void reipl_run(struct shutdown_trigger *trigger) | 1111 | static void reipl_run(struct shutdown_trigger *trigger) |
1103 | { | 1112 | { |
1104 | smp_switch_to_ipl_cpu(__reipl_run, NULL); | 1113 | smp_call_ipl_cpu(__reipl_run, NULL); |
1105 | } | 1114 | } |
1106 | 1115 | ||
1107 | static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) | 1116 | static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) |
@@ -1256,6 +1265,29 @@ static int __init reipl_fcp_init(void) | |||
1256 | return 0; | 1265 | return 0; |
1257 | } | 1266 | } |
1258 | 1267 | ||
1268 | static int __init reipl_type_init(void) | ||
1269 | { | ||
1270 | enum ipl_type reipl_type = ipl_info.type; | ||
1271 | struct ipl_parameter_block *reipl_block; | ||
1272 | unsigned long size; | ||
1273 | |||
1274 | reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size); | ||
1275 | if (!reipl_block) | ||
1276 | goto out; | ||
1277 | /* | ||
1278 | * If we have an OS info reipl block, this will be used | ||
1279 | */ | ||
1280 | if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) { | ||
1281 | memcpy(reipl_block_fcp, reipl_block, size); | ||
1282 | reipl_type = IPL_TYPE_FCP; | ||
1283 | } else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) { | ||
1284 | memcpy(reipl_block_ccw, reipl_block, size); | ||
1285 | reipl_type = IPL_TYPE_CCW; | ||
1286 | } | ||
1287 | out: | ||
1288 | return reipl_set_type(reipl_type); | ||
1289 | } | ||
1290 | |||
1259 | static int __init reipl_init(void) | 1291 | static int __init reipl_init(void) |
1260 | { | 1292 | { |
1261 | int rc; | 1293 | int rc; |
@@ -1277,10 +1309,7 @@ static int __init reipl_init(void) | |||
1277 | rc = reipl_nss_init(); | 1309 | rc = reipl_nss_init(); |
1278 | if (rc) | 1310 | if (rc) |
1279 | return rc; | 1311 | return rc; |
1280 | rc = reipl_set_type(ipl_info.type); | 1312 | return reipl_type_init(); |
1281 | if (rc) | ||
1282 | return rc; | ||
1283 | return 0; | ||
1284 | } | 1313 | } |
1285 | 1314 | ||
1286 | static struct shutdown_action __refdata reipl_action = { | 1315 | static struct shutdown_action __refdata reipl_action = { |
@@ -1421,7 +1450,7 @@ static void dump_run(struct shutdown_trigger *trigger) | |||
1421 | if (dump_method == DUMP_METHOD_NONE) | 1450 | if (dump_method == DUMP_METHOD_NONE) |
1422 | return; | 1451 | return; |
1423 | smp_send_stop(); | 1452 | smp_send_stop(); |
1424 | smp_switch_to_ipl_cpu(__dump_run, NULL); | 1453 | smp_call_ipl_cpu(__dump_run, NULL); |
1425 | } | 1454 | } |
1426 | 1455 | ||
1427 | static int __init dump_ccw_init(void) | 1456 | static int __init dump_ccw_init(void) |
@@ -1499,30 +1528,12 @@ static struct shutdown_action __refdata dump_action = { | |||
1499 | 1528 | ||
1500 | static void dump_reipl_run(struct shutdown_trigger *trigger) | 1529 | static void dump_reipl_run(struct shutdown_trigger *trigger) |
1501 | { | 1530 | { |
1502 | preempt_disable(); | 1531 | u32 csum; |
1503 | /* | 1532 | |
1504 | * Bypass dynamic address translation (DAT) when storing IPL parameter | 1533 | csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); |
1505 | * information block address and checksum into the prefix area | 1534 | copy_to_absolute_zero(&S390_lowcore.ipib_checksum, &csum, sizeof(csum)); |
1506 | * (corresponding to absolute addresses 0-8191). | 1535 | copy_to_absolute_zero(&S390_lowcore.ipib, &reipl_block_actual, |
1507 | * When enhanced DAT applies and the STE format control in one, | 1536 | sizeof(reipl_block_actual)); |
1508 | * the absolute address is formed without prefixing. In this case a | ||
1509 | * normal store (stg/st) into the prefix area would no more match to | ||
1510 | * absolute addresses 0-8191. | ||
1511 | */ | ||
1512 | #ifdef CONFIG_64BIT | ||
1513 | asm volatile("sturg %0,%1" | ||
1514 | :: "a" ((unsigned long) reipl_block_actual), | ||
1515 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1516 | #else | ||
1517 | asm volatile("stura %0,%1" | ||
1518 | :: "a" ((unsigned long) reipl_block_actual), | ||
1519 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
1520 | #endif | ||
1521 | asm volatile("stura %0,%1" | ||
1522 | :: "a" (csum_partial(reipl_block_actual, | ||
1523 | reipl_block_actual->hdr.len, 0)), | ||
1524 | "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); | ||
1525 | preempt_enable(); | ||
1526 | dump_run(trigger); | 1537 | dump_run(trigger); |
1527 | } | 1538 | } |
1528 | 1539 | ||
@@ -1623,9 +1634,7 @@ static void stop_run(struct shutdown_trigger *trigger) | |||
1623 | if (strcmp(trigger->name, ON_PANIC_STR) == 0 || | 1634 | if (strcmp(trigger->name, ON_PANIC_STR) == 0 || |
1624 | strcmp(trigger->name, ON_RESTART_STR) == 0) | 1635 | strcmp(trigger->name, ON_RESTART_STR) == 0) |
1625 | disabled_wait((unsigned long) __builtin_return_address(0)); | 1636 | disabled_wait((unsigned long) __builtin_return_address(0)); |
1626 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) | 1637 | smp_stop_cpu(); |
1627 | cpu_relax(); | ||
1628 | for (;;); | ||
1629 | } | 1638 | } |
1630 | 1639 | ||
1631 | static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, | 1640 | static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, |
@@ -1713,6 +1722,7 @@ static struct kobj_attribute on_panic_attr = | |||
1713 | 1722 | ||
1714 | static void do_panic(void) | 1723 | static void do_panic(void) |
1715 | { | 1724 | { |
1725 | lgr_info_log(); | ||
1716 | on_panic_trigger.action->fn(&on_panic_trigger); | 1726 | on_panic_trigger.action->fn(&on_panic_trigger); |
1717 | stop_run(&on_panic_trigger); | 1727 | stop_run(&on_panic_trigger); |
1718 | } | 1728 | } |
@@ -1738,9 +1748,8 @@ static ssize_t on_restart_store(struct kobject *kobj, | |||
1738 | static struct kobj_attribute on_restart_attr = | 1748 | static struct kobj_attribute on_restart_attr = |
1739 | __ATTR(on_restart, 0644, on_restart_show, on_restart_store); | 1749 | __ATTR(on_restart, 0644, on_restart_show, on_restart_store); |
1740 | 1750 | ||
1741 | void do_restart(void) | 1751 | static void __do_restart(void *ignore) |
1742 | { | 1752 | { |
1743 | smp_restart_with_online_cpu(); | ||
1744 | smp_send_stop(); | 1753 | smp_send_stop(); |
1745 | #ifdef CONFIG_CRASH_DUMP | 1754 | #ifdef CONFIG_CRASH_DUMP |
1746 | crash_kexec(NULL); | 1755 | crash_kexec(NULL); |
@@ -1749,6 +1758,14 @@ void do_restart(void) | |||
1749 | stop_run(&on_restart_trigger); | 1758 | stop_run(&on_restart_trigger); |
1750 | } | 1759 | } |
1751 | 1760 | ||
1761 | void do_restart(void) | ||
1762 | { | ||
1763 | tracing_off(); | ||
1764 | debug_locks_off(); | ||
1765 | lgr_info_log(); | ||
1766 | smp_call_online_cpu(__do_restart, NULL); | ||
1767 | } | ||
1768 | |||
1752 | /* on halt */ | 1769 | /* on halt */ |
1753 | 1770 | ||
1754 | static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; | 1771 | static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; |