@@ -16,11 +16,36 @@
#include <linux/bug.h>
#include <linux/efi.h>
+#include <linux/irqflags.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
+#include <linux/stringify.h>
#include <asm/efi.h>
/*
+ * Temporary scaffolding until all users provide ARCH_EFI_IRQ_FLAGS_MASK.
+ */
+#ifdef ARCH_EFI_IRQ_FLAGS_MASK
+static void efi_call_virt_check_flags(unsigned long flags, const char *call)
+{
+ unsigned long cur_flags, mismatch;
+
+ local_save_flags(cur_flags);
+
+ mismatch = flags ^ cur_flags;
+ if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK))
+ return;
+
+ add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
+ pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
+ flags, cur_flags, call);
+ local_irq_restore(flags);
+}
+#else /* ARCH_EFI_IRQ_FLAGS_MASK */
+static inline void efi_call_virt_check_flags(unsigned long flags, const char *call) {}
+#endif /* ARCH_EFI_IRQ_FLAGS_MASK */
+
+/*
* Arch code can implement the following three template macros, avoiding
* reptition for the void/non-void return cases of {__,}efi_call_virt:
*
@@ -43,16 +68,22 @@
#define efi_call_virt(f, args...) \
({ \
efi_status_t __s; \
+ unsigned long flags; \
arch_efi_call_virt_setup(); \
+ local_save_flags(flags); \
__s = arch_efi_call_virt(f, args); \
+ efi_call_virt_check_flags(flags, __stringify(f)); \
arch_efi_call_virt_teardown(); \
__s; \
})
#define __efi_call_virt(f, args...) \
({ \
+ unsigned long flags; \
arch_efi_call_virt_setup(); \
+ local_save_flags(flags); \
arch_efi_call_virt(f, args); \
+ efi_call_virt_check_flags(flags, __stringify(f)); \
arch_efi_call_virt_teardown(); \
})