|
@@ -319,15 +319,23 @@ static void pseries_lpar_idle(void)
|
|
|
* to ever be a problem in practice we can move this into a kernel thread to
|
|
|
* finish off the process later in boot.
|
|
|
*/
|
|
|
-long pSeries_enable_reloc_on_exc(void)
|
|
|
+void pseries_enable_reloc_on_exc(void)
|
|
|
{
|
|
|
long rc;
|
|
|
unsigned int delay, total_delay = 0;
|
|
|
|
|
|
while (1) {
|
|
|
rc = enable_reloc_on_exceptions();
|
|
|
- if (!H_IS_LONG_BUSY(rc))
|
|
|
- return rc;
|
|
|
+ if (!H_IS_LONG_BUSY(rc)) {
|
|
|
+ if (rc == H_P2) {
|
|
|
+ pr_info("Relocation on exceptions not"
|
|
|
+ " supported\n");
|
|
|
+ } else if (rc != H_SUCCESS) {
|
|
|
+ pr_warn("Unable to enable relocation"
|
|
|
+ " on exceptions: %ld\n", rc);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
delay = get_longbusy_msecs(rc);
|
|
|
total_delay += delay;
|
|
@@ -335,66 +343,81 @@ long pSeries_enable_reloc_on_exc(void)
|
|
|
pr_warn("Warning: Giving up waiting to enable "
|
|
|
"relocation on exceptions (%u msec)!\n",
|
|
|
total_delay);
|
|
|
- return rc;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
mdelay(delay);
|
|
|
}
|
|
|
}
|
|
|
-EXPORT_SYMBOL(pSeries_enable_reloc_on_exc);
|
|
|
+EXPORT_SYMBOL(pseries_enable_reloc_on_exc);
|
|
|
|
|
|
-long pSeries_disable_reloc_on_exc(void)
|
|
|
+void pseries_disable_reloc_on_exc(void)
|
|
|
{
|
|
|
long rc;
|
|
|
|
|
|
while (1) {
|
|
|
rc = disable_reloc_on_exceptions();
|
|
|
if (!H_IS_LONG_BUSY(rc))
|
|
|
- return rc;
|
|
|
+ break;
|
|
|
mdelay(get_longbusy_msecs(rc));
|
|
|
}
|
|
|
+ if (rc != H_SUCCESS)
|
|
|
+ pr_warning("Warning: Failed to disable relocation on "
|
|
|
+ "exceptions: %ld\n", rc);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(pSeries_disable_reloc_on_exc);
|
|
|
+EXPORT_SYMBOL(pseries_disable_reloc_on_exc);
|
|
|
|
|
|
#ifdef CONFIG_KEXEC
|
|
|
static void pSeries_machine_kexec(struct kimage *image)
|
|
|
{
|
|
|
- long rc;
|
|
|
-
|
|
|
- if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
|
|
|
- rc = pSeries_disable_reloc_on_exc();
|
|
|
- if (rc != H_SUCCESS)
|
|
|
- pr_warning("Warning: Failed to disable relocation on "
|
|
|
- "exceptions: %ld\n", rc);
|
|
|
- }
|
|
|
+ if (firmware_has_feature(FW_FEATURE_SET_MODE))
|
|
|
+ pseries_disable_reloc_on_exc();
|
|
|
|
|
|
default_machine_kexec(image);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
#ifdef __LITTLE_ENDIAN__
|
|
|
-long pseries_big_endian_exceptions(void)
|
|
|
+void pseries_big_endian_exceptions(void)
|
|
|
{
|
|
|
long rc;
|
|
|
|
|
|
while (1) {
|
|
|
rc = enable_big_endian_exceptions();
|
|
|
if (!H_IS_LONG_BUSY(rc))
|
|
|
- return rc;
|
|
|
+ break;
|
|
|
mdelay(get_longbusy_msecs(rc));
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * At this point it is unlikely panic() will get anything
|
|
|
+ * out to the user, since this is called very late in kexec
|
|
|
+ * but at least this will stop us from continuing on further
|
|
|
+ * and creating an even more difficult to debug situation.
|
|
|
+ *
|
|
|
+ * There is a known problem when kdump'ing, if cpus are offline
|
|
|
+ * the above call will fail. Rather than panicking again, keep
|
|
|
+ * going and hope the kdump kernel is also little endian, which
|
|
|
+ * it usually is.
|
|
|
+ */
|
|
|
+ if (rc && !kdump_in_progress())
|
|
|
+ panic("Could not enable big endian exceptions");
|
|
|
}
|
|
|
|
|
|
-static long pseries_little_endian_exceptions(void)
|
|
|
+void pseries_little_endian_exceptions(void)
|
|
|
{
|
|
|
long rc;
|
|
|
|
|
|
while (1) {
|
|
|
rc = enable_little_endian_exceptions();
|
|
|
if (!H_IS_LONG_BUSY(rc))
|
|
|
- return rc;
|
|
|
+ break;
|
|
|
mdelay(get_longbusy_msecs(rc));
|
|
|
}
|
|
|
+ if (rc) {
|
|
|
+ ppc_md.progress("H_SET_MODE LE exception fail", 0);
|
|
|
+ panic("Could not enable little endian exceptions");
|
|
|
+ }
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -464,18 +487,6 @@ static void __init pSeries_setup_arch(void)
|
|
|
}
|
|
|
|
|
|
ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
|
|
|
-
|
|
|
- if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
|
|
|
- long rc;
|
|
|
-
|
|
|
- rc = pSeries_enable_reloc_on_exc();
|
|
|
- if (rc == H_P2) {
|
|
|
- pr_info("Relocation on exceptions not supported\n");
|
|
|
- } else if (rc != H_SUCCESS) {
|
|
|
- pr_warn("Unable to enable relocation on exceptions: "
|
|
|
- "%ld\n", rc);
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
static int __init pSeries_init_panel(void)
|
|
@@ -678,23 +689,6 @@ static int __init pSeries_probe(void)
|
|
|
|
|
|
pr_debug("pSeries detected, looking for LPAR capability...\n");
|
|
|
|
|
|
-
|
|
|
-#ifdef __LITTLE_ENDIAN__
|
|
|
- if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
|
|
|
- long rc;
|
|
|
- /*
|
|
|
- * Tell the hypervisor that we want our exceptions to
|
|
|
- * be taken in little endian mode. If this fails we don't
|
|
|
- * want to use BUG() because it will trigger an exception.
|
|
|
- */
|
|
|
- rc = pseries_little_endian_exceptions();
|
|
|
- if (rc) {
|
|
|
- ppc_md.progress("H_SET_MODE LE exception fail", 0);
|
|
|
- panic("Could not enable little endian exceptions");
|
|
|
- }
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
if (firmware_has_feature(FW_FEATURE_LPAR))
|
|
|
hpte_init_lpar();
|
|
|
else
|