powerpc/powernv: Add calls to support little endian host
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 20 May 2014 01:01:28 +0000 (11:01 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 5 Jun 2014 03:19:59 +0000 (13:19 +1000)
When running as a powernv "host" system on P8, we need to switch
the endianness of interrupt handlers. This does it via the appropriate
call to the OPAL firmware which may result in just switching HID0:HILE
but depending on the processor version might need to do a few more
things. This call must be done early before any other processor has
been brought out of firmware.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/opal.h
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c

index 81720ff59a106e599a15f5f535f6b4d08fd4e7fa..ea8bba7b66bd223044827797504e6563e1918a7a 100644 (file)
@@ -154,6 +154,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_LPC_READ                          67
 #define OPAL_LPC_WRITE                         68
 #define OPAL_RETURN_CPU                                69
+#define OPAL_REINIT_CPUS                       70
 #define OPAL_ELOG_READ                         71
 #define OPAL_ELOG_WRITE                                72
 #define OPAL_ELOG_ACK                          73
@@ -725,6 +726,11 @@ struct OpalIoPhb3ErrorData {
        uint64_t pestB[OPAL_PHB3_NUM_PEST_REGS];
 };
 
+enum {
+       OPAL_REINIT_CPUS_HILE_BE        = (1 << 0),
+       OPAL_REINIT_CPUS_HILE_LE        = (1 << 1),
+};
+
 typedef struct oppanel_line {
        const char *    line;
        uint64_t        line_len;
@@ -849,6 +855,7 @@ int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
                            uint16_t *pci_error_type, uint16_t *severity);
 int64_t opal_pci_poll(uint64_t phb_id);
 int64_t opal_return_cpu(void);
+int64_t opal_reinit_cpus(uint64_t flags);
 
 int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
 int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
index b5ebc545a373c93c09a21265de03f237833bfaf5..4abbff22a61f0a6165b3d475156c32bb633d6538 100644 (file)
@@ -124,6 +124,7 @@ OPAL_CALL(opal_xscom_write,                 OPAL_XSCOM_WRITE);
 OPAL_CALL(opal_lpc_read,                       OPAL_LPC_READ);
 OPAL_CALL(opal_lpc_write,                      OPAL_LPC_WRITE);
 OPAL_CALL(opal_return_cpu,                     OPAL_RETURN_CPU);
+OPAL_CALL(opal_reinit_cpus,                    OPAL_REINIT_CPUS);
 OPAL_CALL(opal_read_elog,                      OPAL_ELOG_READ);
 OPAL_CALL(opal_send_ack_elog,                  OPAL_ELOG_ACK);
 OPAL_CALL(opal_get_elog_size,                  OPAL_ELOG_SIZE);
index 360ad80c754ce3c97ad9b9fead5ad4806e5f6666..539243e9dc23bb7a03b1725b2f1b377a5051ecda 100644 (file)
@@ -57,6 +57,21 @@ static DEFINE_SPINLOCK(opal_notifier_lock);
 static uint64_t last_notified_mask = 0x0ul;
 static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
 
+static void opal_reinit_cores(void)
+{
+       /* Do the actual re-init, This will clobber all FPRs, VRs, etc...
+        *
+        * It will preserve non volatile GPRs and HSPRG0/1. It will
+        * also restore HIDs and other SPRs to their original value
+        * but it might clobber a bunch.
+        */
+#ifdef __BIG_ENDIAN__
+       opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_BE);
+#else
+       opal_reinit_cpus(OPAL_REINIT_CPUS_HILE_LE);
+#endif
+}
+
 int __init early_init_dt_scan_opal(unsigned long node,
                                   const char *uname, int depth, void *data)
 {
@@ -96,6 +111,13 @@ int __init early_init_dt_scan_opal(unsigned long node,
                printk("OPAL V1 detected !\n");
        }
 
+       /* Reinit all cores with the right endian */
+       opal_reinit_cores();
+
+       /* Restore some bits */
+       if (cur_cpu_spec->cpu_restore)
+               cur_cpu_spec->cpu_restore();
+
        return 1;
 }