[RFC PATCH 03/10] powerpc/powernv: Use OPAL_REPORT_TRAP to cope with trap interrupts from OPAL

Nicholas Piggin npiggin at gmail.com
Sat May 2 21:19:07 AEST 2020


This isn't used yet, because OPAL is nice enough not to cause unexpected
program check interrupts to the OS. A future patch will allow OPAL to
start using traps. Like so.

  [OPAL] < assert failed at core/opal.c:814 >
  [OPAL]     .
  [OPAL]      .
  [OPAL]       .
  [OPAL]         OO__)
  [OPAL]        <"__/
  [OPAL]         ^ ^
   cpu 0x0: Vector: 700 (Program Check) at [c000000080287770]
       pc: 000000003002f360: opal_poll_events+0x54/0x174 [OPAL]
       lr: 000000003002f344: opal_poll_events+0x38/0x174 [OPAL]
       sp: c000000080287a00
      msr: 9000000000021033
     current = 0xc0000000016fa100
     paca    = 0xc0000000012c0000^I irqmask: 0x03^I irq_happened: 0x01
       pid   = 19, comm = kopald
   Linux version 5.7.0-rc3-00053-g2d9c3c965178-dirty
   enter ? for help
   [c000000080287a80] 000000003002e6b8 opal_v4_le_entry+0x224/0x29c [OPAL]
   [c000000080287b50] c000000000096ce8 opal_call+0x1c8/0x580
   [c000000080287c90] c000000000097448 opal_poll_events+0x28/0x40
   [c000000080287d00] c0000000000a26e0 opal_handle_events+0x70/0x140
   [c000000080287d50] c00000000009a198 kopald+0x98/0x140
   [c000000080287db0] c00000000012139c kthread+0x18c/0x1a0
   [c000000080287e20] c00000000000cc28 ret_from_kernel_thread+0x5c/0x74

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 arch/powerpc/include/asm/opal-api.h        |  7 +++-
 arch/powerpc/include/asm/opal.h            |  2 ++
 arch/powerpc/kernel/traps.c                | 39 ++++++++++++++++------
 arch/powerpc/platforms/powernv/opal-call.c |  1 +
 4 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 8eb31b9aeb27..018d4734c323 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -216,7 +216,8 @@
 #define OPAL_SECVAR_ENQUEUE_UPDATE		178
 #define OPAL_ADDR_TO_SYM			181
 #define OPAL_SYM_TO_ADDR			182
-#define OPAL_LAST				182
+#define OPAL_REPORT_TRAP			183
+#define OPAL_LAST				183
 
 #define QUIESCE_HOLD			1 /* Spin all calls at entry */
 #define QUIESCE_REJECT			2 /* Fail all calls with OPAL_BUSY */
@@ -1184,6 +1185,10 @@ struct opal_mpipl_fadump {
 	struct	opal_mpipl_region region[];
 } __packed;
 
+#define OPAL_TRAP_FATAL	1
+#define OPAL_TRAP_WARN	2
+#define OPAL_TRAP_PANIC	3
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_API_H */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 56b6994aefb7..dc77c2d5e036 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -314,6 +314,8 @@ s64 opal_quiesce(u64 shutdown_type, s32 cpu);
 
 int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen);
 int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize);
+int64_t opal_report_trap(uint64_t nip);
+
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 3fca22276bb1..0274ae7b8a03 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -52,6 +52,7 @@
 #endif
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
+#include <asm/opal.h>
 #include <asm/processor.h>
 #include <asm/tm.h>
 #endif
@@ -1471,7 +1472,6 @@ void program_check_exception(struct pt_regs *regs)
 		goto bail;
 	}
 	if (reason & REASON_TRAP) {
-		unsigned long bugaddr;
 		/* Debugger is first in line to stop recursive faults in
 		 * rcu_lock, notify_die, or atomic_notifier_call_chain */
 		if (debugger_bpt(regs))
@@ -1485,18 +1485,35 @@ void program_check_exception(struct pt_regs *regs)
 				== NOTIFY_STOP)
 			goto bail;
 
-		bugaddr = regs->nip;
-		/*
-		 * Fixup bugaddr for BUG_ON() in real mode
-		 */
-		if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR))
-			bugaddr += PAGE_OFFSET;
+		if (!(regs->msr & MSR_PR)) { /* not user-mode */
+			unsigned long bugaddr;
+			enum bug_trap_type t;
+
+			/*
+			 * Fixup bugaddr for BUG_ON() in real mode
+			 */
+			bugaddr = regs->nip;
+			if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR))
+				bugaddr += PAGE_OFFSET;
+			t = report_bug(bugaddr, regs);
+			if (t == BUG_TRAP_TYPE_WARN) {
+				regs->nip += 4;
+				goto bail;
+			}
+			if (t == BUG_TRAP_TYPE_BUG)
+				goto bug;
 
-		if (!(regs->msr & MSR_PR) &&  /* not user-mode */
-		    report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) {
-			regs->nip += 4;
-			goto bail;
+			if (firmware_has_feature(FW_FEATURE_OPAL)) {
+				int64_t ret;
+
+				ret = opal_report_trap(regs->nip);
+				if (ret == OPAL_TRAP_WARN) {
+					regs->nip += 4;
+					goto bail;
+				}
+			}
 		}
+bug:
 		_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
 		goto bail;
 	}
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index 2233a58924cb..506b1798081a 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -295,3 +295,4 @@ OPAL_CALL(opal_secvar_get_next,			OPAL_SECVAR_GET_NEXT);
 OPAL_CALL(opal_secvar_enqueue_update,		OPAL_SECVAR_ENQUEUE_UPDATE);
 OPAL_CALL(opal_addr_to_sym,			OPAL_ADDR_TO_SYM);
 OPAL_CALL(opal_sym_to_addr,			OPAL_SYM_TO_ADDR);
+OPAL_CALL(opal_report_trap,			OPAL_REPORT_TRAP);
-- 
2.23.0



More information about the Linuxppc-dev mailing list