Merge tag 'powerpc-5.4-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Nov 2019 18:08:19 +0000 (11:08 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Nov 2019 18:08:19 +0000 (11:08 -0700)
Pull powerpc fixes from Michael Ellerman:
 "Our recent cleanup of EEH led to an oops on bare metal machines when
  the cxl (CAPI) driver creates virtual devices for an attached FPGA
  accelerator.

  The "secure virtual machine" support we added in v5.4 had a bug if the
  kernel was relocated (moved during boot), in those cases the signature
  of the kernel text wouldn't verify and the Ultravisor would refuse to
  run the VM.

  A recent change to disable interrupts before calling
  arch_cpu_idle_dead() caused a WARN_ON() in our bare metal CPU offline
  code to always trigger.

  The KUAP (SMAP) support we added for 32-bit Book3S had a bug if the
  address range crossed a segment (256MB) boundary which could lead to
  spurious faults.

  Thanks to: Christophe Leroy, Frederic Barrat, Michael Anderson,
  Nicholas Piggin, Sam Bobroff, Thiago Jung Bauermann"

* tag 'powerpc-5.4-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/powernv: Fix CPU idle to be called with IRQs disabled
  powerpc/prom_init: Undo relocation before entering secure mode
  powerpc/powernv/eeh: Fix oops when probing cxl devices
  powerpc/32s: fix allow/prevent_user_access() when crossing segment boundaries.

arch/powerpc/include/asm/book3s/32/kup.h
arch/powerpc/include/asm/elf.h
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_init_check.sh
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/smp.c

index 677e9ba..f9dc597 100644 (file)
@@ -91,6 +91,7 @@
 
 static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
 {
+       addr &= 0xf0000000;     /* align addr to start of segment */
        barrier();      /* make sure thread.kuap is updated before playing with SRs */
        while (addr < end) {
                mtsrin(sr, addr);
index 409c9bf..57c229a 100644 (file)
@@ -175,4 +175,7 @@ do {                                                                        \
        ARCH_DLINFO_CACHE_GEOMETRY;                                     \
 } while (0)
 
+/* Relocate the kernel image to @final_address */
+void relocate(unsigned long final_address);
+
 #endif /* _ASM_POWERPC_ELF_H */
index a4e7762..100f1b5 100644 (file)
@@ -3249,7 +3249,20 @@ static void setup_secure_guest(unsigned long kbase, unsigned long fdt)
        /* Switch to secure mode. */
        prom_printf("Switching to secure mode.\n");
 
+       /*
+        * The ultravisor will do an integrity check of the kernel image but we
+        * relocated it so the check will fail. Restore the original image by
+        * relocating it back to the kernel virtual base address.
+        */
+       if (IS_ENABLED(CONFIG_RELOCATABLE))
+               relocate(KERNELBASE);
+
        ret = enter_secure_mode(kbase, fdt);
+
+       /* Relocate the kernel again. */
+       if (IS_ENABLED(CONFIG_RELOCATABLE))
+               relocate(kbase);
+
        if (ret != U_SUCCESS) {
                prom_printf("Returned %d from switching to secure mode.\n", ret);
                prom_rtas_os_term("Switch to secure mode failed.\n");
index 78bab17..b183ab9 100644 (file)
@@ -26,7 +26,8 @@ _end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
 __secondary_hold_acknowledge __secondary_hold_spinloop __start
 logo_linux_clut224 btext_prepare_BAT
 reloc_got2 kernstart_addr memstart_addr linux_banner _stext
-__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."
+__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC.
+relocate"
 
 NM="$1"
 OBJ="$2"
index 6bc24a4..6f300ab 100644 (file)
@@ -42,7 +42,7 @@ void pnv_pcibios_bus_add_device(struct pci_dev *pdev)
 {
        struct pci_dn *pdn = pci_get_pdn(pdev);
 
-       if (eeh_has_flag(EEH_FORCE_DISABLED))
+       if (!pdn || eeh_has_flag(EEH_FORCE_DISABLED))
                return;
 
        dev_dbg(&pdev->dev, "EEH: Setting up device\n");
index fbd6e6b..13e2516 100644 (file)
@@ -146,20 +146,25 @@ static int pnv_smp_cpu_disable(void)
        return 0;
 }
 
+static void pnv_flush_interrupts(void)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
+               if (xive_enabled())
+                       xive_flush_interrupt();
+               else
+                       icp_opal_flush_interrupt();
+       } else {
+               icp_native_flush_interrupt();
+       }
+}
+
 static void pnv_smp_cpu_kill_self(void)
 {
+       unsigned long srr1, unexpected_mask, wmask;
        unsigned int cpu;
-       unsigned long srr1, wmask;
        u64 lpcr_val;
 
        /* Standard hot unplug procedure */
-       /*
-        * This hard disables local interurpts, ensuring we have no lazy
-        * irqs pending.
-        */
-       WARN_ON(irqs_disabled());
-       hard_irq_disable();
-       WARN_ON(lazy_irq_pending());
 
        idle_task_exit();
        current->active_mm = NULL; /* for sanity */
@@ -173,6 +178,27 @@ static void pnv_smp_cpu_kill_self(void)
                wmask = SRR1_WAKEMASK_P8;
 
        /*
+        * This turns the irq soft-disabled state we're called with, into a
+        * hard-disabled state with pending irq_happened interrupts cleared.
+        *
+        * PACA_IRQ_DEC   - Decrementer should be ignored.
+        * PACA_IRQ_HMI   - Can be ignored, processing is done in real mode.
+        * PACA_IRQ_DBELL, EE, PMI - Unexpected.
+        */
+       hard_irq_disable();
+       if (generic_check_cpu_restart(cpu))
+               goto out;
+
+       unexpected_mask = ~(PACA_IRQ_DEC | PACA_IRQ_HMI | PACA_IRQ_HARD_DIS);
+       if (local_paca->irq_happened & unexpected_mask) {
+               if (local_paca->irq_happened & PACA_IRQ_EE)
+                       pnv_flush_interrupts();
+               DBG("CPU%d Unexpected exit while offline irq_happened=%lx!\n",
+                               cpu, local_paca->irq_happened);
+       }
+       local_paca->irq_happened = PACA_IRQ_HARD_DIS;
+
+       /*
         * We don't want to take decrementer interrupts while we are
         * offline, so clear LPCR:PECE1. We keep PECE2 (and
         * LPCR_PECE_HVEE on P9) enabled so as to let IPIs in.
@@ -197,6 +223,7 @@ static void pnv_smp_cpu_kill_self(void)
 
                srr1 = pnv_cpu_offline(cpu);
 
+               WARN_ON_ONCE(!irqs_disabled());
                WARN_ON(lazy_irq_pending());
 
                /*
@@ -212,13 +239,7 @@ static void pnv_smp_cpu_kill_self(void)
                 */
                if (((srr1 & wmask) == SRR1_WAKEEE) ||
                    ((srr1 & wmask) == SRR1_WAKEHVI)) {
-                       if (cpu_has_feature(CPU_FTR_ARCH_300)) {
-                               if (xive_enabled())
-                                       xive_flush_interrupt();
-                               else
-                                       icp_opal_flush_interrupt();
-                       } else
-                               icp_native_flush_interrupt();
+                       pnv_flush_interrupts();
                } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
                        unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
                        asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
@@ -266,7 +287,7 @@ static void pnv_smp_cpu_kill_self(void)
         */
        lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1;
        pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
-
+out:
        DBG("CPU%d coming online...\n", cpu);
 }