summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/pseries/setup.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-07-05 15:03:49 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2016-07-21 18:56:31 +1000
commitd3cbff1b5a90afe6cb201aa2187c9609e21f92ad (patch)
treef0ced407effcad48705b598ed5618c222d82983a /arch/powerpc/platforms/pseries/setup.c
parent3808a88985b4f5f5e947c364debce4441a380fb8 (diff)
powerpc: Put exception configuration in a common place
The various calls to establish exception endianness and AIL are now done from a single point using already established CPU and FW feature bits to decide what to do. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'arch/powerpc/platforms/pseries/setup.c')
-rw-r--r--arch/powerpc/platforms/pseries/setup.c92
1 files changed, 43 insertions, 49 deletions
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 9cc9b88fce79..ba7dc126b5e5 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -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