Merge tag 'powerpc-5.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / irq.c
index cc7a6271b6b4ec5408bfd2ed07a41432f0cc5a37..086b0a74332903c0defecd9c902444b610aca6b9 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/pgtable.h>
 
 #include <linux/uaccess.h>
+#include <asm/interrupt.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/cache.h>
@@ -269,6 +270,31 @@ again:
        }
 }
 
+#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_PPC_KUAP)
+static inline void replay_soft_interrupts_irqrestore(void)
+{
+       unsigned long kuap_state = get_kuap();
+
+       /*
+        * Check if anything calls local_irq_enable/restore() when KUAP is
+        * disabled (user access enabled). We handle that case here by saving
+        * and re-locking AMR but we shouldn't get here in the first place,
+        * hence the warning.
+        */
+       kuap_check_amr();
+
+       if (kuap_state != AMR_KUAP_BLOCKED)
+               set_kuap(AMR_KUAP_BLOCKED);
+
+       replay_soft_interrupts();
+
+       if (kuap_state != AMR_KUAP_BLOCKED)
+               set_kuap(kuap_state);
+}
+#else
+#define replay_soft_interrupts_irqrestore() replay_soft_interrupts()
+#endif
+
 notrace void arch_local_irq_restore(unsigned long mask)
 {
        unsigned char irq_happened;
@@ -332,7 +358,7 @@ notrace void arch_local_irq_restore(unsigned long mask)
        irq_soft_mask_set(IRQS_ALL_DISABLED);
        trace_hardirqs_off();
 
-       replay_soft_interrupts();
+       replay_soft_interrupts_irqrestore();
        local_paca->irq_happened = 0;
 
        trace_hardirqs_on();
@@ -644,8 +670,6 @@ void __do_irq(struct pt_regs *regs)
 {
        unsigned int irq;
 
-       irq_enter();
-
        trace_irq_entry(regs);
 
        /*
@@ -665,11 +689,9 @@ void __do_irq(struct pt_regs *regs)
                generic_handle_irq(irq);
 
        trace_irq_exit(regs);
-
-       irq_exit();
 }
 
-void do_IRQ(struct pt_regs *regs)
+DEFINE_INTERRUPT_HANDLER_ASYNC(do_IRQ)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
        void *cursp, *irqsp, *sirqsp;