diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 19:04:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-26 19:04:22 -0400 |
| commit | 21cdbc1378e8aa96e1ed4a606dce1a8e7daf7fdf (patch) | |
| tree | 55b6c294b912ccdc3eede15960b0ece53a69d902 /arch/s390/kernel/ipl.c | |
| parent | 86d9c070175de65890794fa227b68297da6206d8 (diff) | |
| parent | ef3500b2b2955af4fa6b0564b51c0c604e38c571 (diff) | |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (81 commits)
[S390] remove duplicated #includes
[S390] cpumask: use mm_cpumask() wrapper
[S390] cpumask: Use accessors code.
[S390] cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits.
[S390] cpumask: remove cpu_coregroup_map
[S390] fix clock comparator save area usage
[S390] Add hwcap flag for the etf3 enhancement facility
[S390] Ensure that ipl panic notifier is called late.
[S390] fix dfp elf hwcap/facility bit detection
[S390] smp: perform initial cpu reset before starting a cpu
[S390] smp: fix memory leak on __cpu_up
[S390] ipl: Improve checking logic and remove switch defaults.
[S390] s390dbf: Remove needless check for NULL pointer.
[S390] s390dbf: Remove redundant initilizations.
[S390] use kzfree()
[S390] BUG to BUG_ON changes
[S390] zfcpdump: Prevent zcore from beeing built as a kernel module.
[S390] Use csum_partial in checksum.h
[S390] cleanup lowcore.h
[S390] eliminate ipl_device from lowcore
...
Diffstat (limited to 'arch/s390/kernel/ipl.c')
| -rw-r--r-- | arch/s390/kernel/ipl.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2dcf590faba6..6f3711a0eaaa 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <asm/ebcdic.h> | 23 | #include <asm/ebcdic.h> |
| 24 | #include <asm/reset.h> | 24 | #include <asm/reset.h> |
| 25 | #include <asm/sclp.h> | 25 | #include <asm/sclp.h> |
| 26 | #include <asm/setup.h> | 26 | #include <asm/checksum.h> |
| 27 | 27 | ||
| 28 | #define IPL_PARM_BLOCK_VERSION 0 | 28 | #define IPL_PARM_BLOCK_VERSION 0 |
| 29 | 29 | ||
| @@ -56,13 +56,14 @@ struct shutdown_trigger { | |||
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | /* | 58 | /* |
| 59 | * Five shutdown action types are supported: | 59 | * The following shutdown action types are supported: |
| 60 | */ | 60 | */ |
| 61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" | 61 | #define SHUTDOWN_ACTION_IPL_STR "ipl" |
| 62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" | 62 | #define SHUTDOWN_ACTION_REIPL_STR "reipl" |
| 63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" | 63 | #define SHUTDOWN_ACTION_DUMP_STR "dump" |
| 64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" | 64 | #define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" |
| 65 | #define SHUTDOWN_ACTION_STOP_STR "stop" | 65 | #define SHUTDOWN_ACTION_STOP_STR "stop" |
| 66 | #define SHUTDOWN_ACTION_DUMP_REIPL_STR "dump_reipl" | ||
| 66 | 67 | ||
| 67 | struct shutdown_action { | 68 | struct shutdown_action { |
| 68 | char *name; | 69 | char *name; |
| @@ -146,6 +147,7 @@ static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; | |||
| 146 | static struct ipl_parameter_block *reipl_block_fcp; | 147 | static struct ipl_parameter_block *reipl_block_fcp; |
| 147 | static struct ipl_parameter_block *reipl_block_ccw; | 148 | static struct ipl_parameter_block *reipl_block_ccw; |
| 148 | static struct ipl_parameter_block *reipl_block_nss; | 149 | static struct ipl_parameter_block *reipl_block_nss; |
| 150 | static struct ipl_parameter_block *reipl_block_actual; | ||
| 149 | 151 | ||
| 150 | static int dump_capabilities = DUMP_TYPE_NONE; | 152 | static int dump_capabilities = DUMP_TYPE_NONE; |
| 151 | static enum dump_type dump_type = DUMP_TYPE_NONE; | 153 | static enum dump_type dump_type = DUMP_TYPE_NONE; |
| @@ -835,6 +837,7 @@ static int reipl_set_type(enum ipl_type type) | |||
| 835 | reipl_method = REIPL_METHOD_CCW_VM; | 837 | reipl_method = REIPL_METHOD_CCW_VM; |
| 836 | else | 838 | else |
| 837 | reipl_method = REIPL_METHOD_CCW_CIO; | 839 | reipl_method = REIPL_METHOD_CCW_CIO; |
| 840 | reipl_block_actual = reipl_block_ccw; | ||
| 838 | break; | 841 | break; |
| 839 | case IPL_TYPE_FCP: | 842 | case IPL_TYPE_FCP: |
| 840 | if (diag308_set_works) | 843 | if (diag308_set_works) |
| @@ -843,6 +846,7 @@ static int reipl_set_type(enum ipl_type type) | |||
| 843 | reipl_method = REIPL_METHOD_FCP_RO_VM; | 846 | reipl_method = REIPL_METHOD_FCP_RO_VM; |
| 844 | else | 847 | else |
| 845 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; | 848 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; |
| 849 | reipl_block_actual = reipl_block_fcp; | ||
| 846 | break; | 850 | break; |
| 847 | case IPL_TYPE_FCP_DUMP: | 851 | case IPL_TYPE_FCP_DUMP: |
| 848 | reipl_method = REIPL_METHOD_FCP_DUMP; | 852 | reipl_method = REIPL_METHOD_FCP_DUMP; |
| @@ -852,6 +856,7 @@ static int reipl_set_type(enum ipl_type type) | |||
| 852 | reipl_method = REIPL_METHOD_NSS_DIAG; | 856 | reipl_method = REIPL_METHOD_NSS_DIAG; |
| 853 | else | 857 | else |
| 854 | reipl_method = REIPL_METHOD_NSS; | 858 | reipl_method = REIPL_METHOD_NSS; |
| 859 | reipl_block_actual = reipl_block_nss; | ||
| 855 | break; | 860 | break; |
| 856 | case IPL_TYPE_UNKNOWN: | 861 | case IPL_TYPE_UNKNOWN: |
| 857 | reipl_method = REIPL_METHOD_DEFAULT; | 862 | reipl_method = REIPL_METHOD_DEFAULT; |
| @@ -960,7 +965,6 @@ static void reipl_run(struct shutdown_trigger *trigger) | |||
| 960 | diag308(DIAG308_IPL, NULL); | 965 | diag308(DIAG308_IPL, NULL); |
| 961 | break; | 966 | break; |
| 962 | case REIPL_METHOD_FCP_DUMP: | 967 | case REIPL_METHOD_FCP_DUMP: |
| 963 | default: | ||
| 964 | break; | 968 | break; |
| 965 | } | 969 | } |
| 966 | disabled_wait((unsigned long) __builtin_return_address(0)); | 970 | disabled_wait((unsigned long) __builtin_return_address(0)); |
| @@ -1069,10 +1073,12 @@ static int __init reipl_fcp_init(void) | |||
| 1069 | { | 1073 | { |
| 1070 | int rc; | 1074 | int rc; |
| 1071 | 1075 | ||
| 1072 | if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP)) | 1076 | if (!diag308_set_works) { |
| 1073 | return 0; | 1077 | if (ipl_info.type == IPL_TYPE_FCP) |
| 1074 | if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP)) | 1078 | make_attrs_ro(reipl_fcp_attrs); |
| 1075 | make_attrs_ro(reipl_fcp_attrs); | 1079 | else |
| 1080 | return 0; | ||
| 1081 | } | ||
| 1076 | 1082 | ||
| 1077 | reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); | 1083 | reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); |
| 1078 | if (!reipl_block_fcp) | 1084 | if (!reipl_block_fcp) |
| @@ -1253,7 +1259,6 @@ static void dump_run(struct shutdown_trigger *trigger) | |||
| 1253 | diag308(DIAG308_DUMP, NULL); | 1259 | diag308(DIAG308_DUMP, NULL); |
| 1254 | break; | 1260 | break; |
| 1255 | case DUMP_METHOD_NONE: | 1261 | case DUMP_METHOD_NONE: |
| 1256 | default: | ||
| 1257 | return; | 1262 | return; |
| 1258 | } | 1263 | } |
| 1259 | printk(KERN_EMERG "Dump failed!\n"); | 1264 | printk(KERN_EMERG "Dump failed!\n"); |
| @@ -1332,6 +1337,49 @@ static struct shutdown_action __refdata dump_action = { | |||
| 1332 | .init = dump_init, | 1337 | .init = dump_init, |
| 1333 | }; | 1338 | }; |
| 1334 | 1339 | ||
| 1340 | static void dump_reipl_run(struct shutdown_trigger *trigger) | ||
| 1341 | { | ||
| 1342 | preempt_disable(); | ||
| 1343 | /* | ||
| 1344 | * Bypass dynamic address translation (DAT) when storing IPL parameter | ||
| 1345 | * information block address and checksum into the prefix area | ||
| 1346 | * (corresponding to absolute addresses 0-8191). | ||
| 1347 | * When enhanced DAT applies and the STE format control in one, | ||
| 1348 | * the absolute address is formed without prefixing. In this case a | ||
| 1349 | * normal store (stg/st) into the prefix area would no more match to | ||
| 1350 | * absolute addresses 0-8191. | ||
| 1351 | */ | ||
| 1352 | #ifdef CONFIG_64BIT | ||
| 1353 | asm volatile("sturg %0,%1" | ||
| 1354 | :: "a" ((unsigned long) reipl_block_actual), | ||
| 1355 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
| 1356 | #else | ||
| 1357 | asm volatile("stura %0,%1" | ||
| 1358 | :: "a" ((unsigned long) reipl_block_actual), | ||
| 1359 | "a" (&lowcore_ptr[smp_processor_id()]->ipib)); | ||
| 1360 | #endif | ||
| 1361 | asm volatile("stura %0,%1" | ||
| 1362 | :: "a" (csum_partial(reipl_block_actual, | ||
| 1363 | reipl_block_actual->hdr.len, 0)), | ||
| 1364 | "a" (&lowcore_ptr[smp_processor_id()]->ipib_checksum)); | ||
| 1365 | preempt_enable(); | ||
| 1366 | dump_run(trigger); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | static int __init dump_reipl_init(void) | ||
| 1370 | { | ||
| 1371 | if (!diag308_set_works) | ||
| 1372 | return -EOPNOTSUPP; | ||
| 1373 | else | ||
| 1374 | return 0; | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | static struct shutdown_action __refdata dump_reipl_action = { | ||
| 1378 | .name = SHUTDOWN_ACTION_DUMP_REIPL_STR, | ||
| 1379 | .fn = dump_reipl_run, | ||
| 1380 | .init = dump_reipl_init, | ||
| 1381 | }; | ||
| 1382 | |||
| 1335 | /* | 1383 | /* |
| 1336 | * vmcmd shutdown action: Trigger vm command on shutdown. | 1384 | * vmcmd shutdown action: Trigger vm command on shutdown. |
| 1337 | */ | 1385 | */ |
| @@ -1421,7 +1469,8 @@ static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR, | |||
| 1421 | /* action list */ | 1469 | /* action list */ |
| 1422 | 1470 | ||
| 1423 | static struct shutdown_action *shutdown_actions_list[] = { | 1471 | static struct shutdown_action *shutdown_actions_list[] = { |
| 1424 | &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; | 1472 | &ipl_action, &reipl_action, &dump_reipl_action, &dump_action, |
| 1473 | &vmcmd_action, &stop_action}; | ||
| 1425 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) | 1474 | #define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) |
| 1426 | 1475 | ||
| 1427 | /* | 1476 | /* |
| @@ -1434,11 +1483,11 @@ static int set_trigger(const char *buf, struct shutdown_trigger *trigger, | |||
| 1434 | size_t len) | 1483 | size_t len) |
| 1435 | { | 1484 | { |
| 1436 | int i; | 1485 | int i; |
| 1486 | |||
| 1437 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { | 1487 | for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) { |
| 1438 | if (!shutdown_actions_list[i]) | 1488 | if (!shutdown_actions_list[i]) |
| 1439 | continue; | 1489 | continue; |
| 1440 | if (strncmp(buf, shutdown_actions_list[i]->name, | 1490 | if (sysfs_streq(buf, shutdown_actions_list[i]->name)) { |
| 1441 | strlen(shutdown_actions_list[i]->name)) == 0) { | ||
| 1442 | trigger->action = shutdown_actions_list[i]; | 1491 | trigger->action = shutdown_actions_list[i]; |
| 1443 | return len; | 1492 | return len; |
| 1444 | } | 1493 | } |
| @@ -1672,7 +1721,7 @@ static int on_panic_notify(struct notifier_block *self, | |||
| 1672 | 1721 | ||
| 1673 | static struct notifier_block on_panic_nb = { | 1722 | static struct notifier_block on_panic_nb = { |
| 1674 | .notifier_call = on_panic_notify, | 1723 | .notifier_call = on_panic_notify, |
| 1675 | .priority = 0, | 1724 | .priority = INT_MIN, |
| 1676 | }; | 1725 | }; |
| 1677 | 1726 | ||
| 1678 | void __init setup_ipl(void) | 1727 | void __init setup_ipl(void) |
| @@ -1696,7 +1745,6 @@ void __init setup_ipl(void) | |||
| 1696 | sizeof(ipl_info.data.nss.name)); | 1745 | sizeof(ipl_info.data.nss.name)); |
| 1697 | break; | 1746 | break; |
| 1698 | case IPL_TYPE_UNKNOWN: | 1747 | case IPL_TYPE_UNKNOWN: |
| 1699 | default: | ||
| 1700 | /* We have no info to copy */ | 1748 | /* We have no info to copy */ |
| 1701 | break; | 1749 | break; |
| 1702 | } | 1750 | } |
