Skip to content

Commit bded070

Browse files
npigginmpe
authored andcommitted
powerpc/pseries/le: Work around a firmware quirk
Some PowerVM firmware when delivering a system reset interrupt to a little endian OS will mess up SRR registers. They are byteswapped, and SRR1 is incorrect. An example from a crash: NIP: 14dd0900000000c0 MSR: 1000000200000080 It's possible to detect this pattern in SRR1 (that would never happen in normal operation), and at least fix the NIP. After this patch, the same interrupt reports NIP properly: NIP [c00000000009dd14] plpar_hcall_norets+0x1c/0x28 Signed-off-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent a3b2cb3 commit bded070

File tree

1 file changed

+15
-0
lines changed
  • arch/powerpc/platforms/pseries

1 file changed

+15
-0
lines changed

arch/powerpc/platforms/pseries/ras.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,21 @@ static void fwnmi_release_errinfo(void)
379379

380380
int pSeries_system_reset_exception(struct pt_regs *regs)
381381
{
382+
#ifdef __LITTLE_ENDIAN__
383+
/*
384+
* Some firmware byteswaps SRR registers and gives incorrect SRR1. Try
385+
* to detect the bad SRR1 pattern here. Flip the NIP back to correct
386+
* endian for reporting purposes. Unfortunately the MSR can't be fixed,
387+
* so clear it. It will be missing MSR_RI so we won't try to recover.
388+
*/
389+
if ((be64_to_cpu(regs->msr) &
390+
(MSR_LE|MSR_RI|MSR_DR|MSR_IR|MSR_ME|MSR_PR|
391+
MSR_ILE|MSR_HV|MSR_SF)) == (MSR_DR|MSR_SF)) {
392+
regs->nip = be64_to_cpu((__be64)regs->nip);
393+
regs->msr = 0;
394+
}
395+
#endif
396+
382397
if (fwnmi_active) {
383398
struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
384399
if (errhdr) {

0 commit comments

Comments
 (0)