parisc: Fix IVT checksum calculation wrt HPMC

On my C8000 a HPMC was triggered, but the HPMC handler wasn't called.
I got the following chassis codes:

<Cpu2> e800009802e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu3> e800009803e00000  00000000001b28a3  CC_ERR_CHECK_HPMC
<Cpu2> 37000f7302e00000  8400000000800000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu3> 37000f7303e00000  8400000000800000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu2> f600105e02e00000  fffffff0f0c00000  CC_MC_HPMC_MONARCH_SELECTED
<Cpu3> 5600100b03e00000  00000000000001a0  CC_MC_OS_HPMC_LEN_ERR
<Cpu2> 140003b202e00000  000000000000000b  CC_ERR_HPMC_STATE_ENTRY
<Cpu3> 5600106403e00000  fffffff0f043ad20  CC_MC_BR_TO_OS_HPMC_FAILED
<Cpu3> 160012cf03e00000  030001001e000007  CC_MPS_CPU_WAITING
<Cpu2> 5600100b02e00000  00000000000001a0  CC_MC_OS_HPMC_LEN_ERR
<Cpu2> 5600106402e00000  fffffff0f0438e70  CC_MC_BR_TO_OS_HPMC_FAILED
<Cpu2> e800009802e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu2> 37000f7302e00000  8400000000800000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu2> 4000109f02e00000  0000000000000000  CC_MC_HPMC_INITIATED
<Cpu2> 4000101902e00000  0000000000000000  CC_MC_MULTIPLE_HPMCS
<Cpu2> 030010d502e00000  0000000000000000  CC_CPU_STOP

C8000 PDC is complaining about our HPMC handler length, which is 1a0 (second
part of the chassis code). Changing that to 0 makes the error go away:

<Cpu0> e800009800e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu3> e800009803e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu1> e800009801e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu2> e800009802e00000  0000000000000000  CC_ERR_CHECK_HPMC
<Cpu0> 37000f7300e00000  8060004000000000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu3> 37000f7303e00000  8060004000000000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu1> 37000f7301e00000  8060004000000000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu2> 37000f7302e00000  8060004000000000  CC_ERR_CPU_CHECK_SUMMARY
<Cpu0> f600105e00e00000  fffffff0f0c00000  CC_MC_HPMC_MONARCH_SELECTED
<Cpu3> 5600109b03e00000  00000000001eb024  CC_MC_BR_TO_OS_HPMC
<Cpu1> 5600109b01e00000  00000000001eb024  CC_MC_BR_TO_OS_HPMC
<Cpu2> 5600109b02e00000  00000000001eb024  CC_MC_BR_TO_OS_HPMC
<Cpu0> 140003b200e00000  000000000000000b  CC_ERR_HPMC_STATE_ENTRY
<Cpu3> 0000000003000000  0000000000000000
<Cpu1> 0000000001000000  0000000000000000
<Cpu2> 0000000002000000  0000000000000000
<Cpu0> 5600109b00e00000  00000000001eb024  CC_MC_BR_TO_OS_HPMC
<Cpu0> 0000000000000000  0000000000000000

So at least the HPMC handler is now called, but it hangs. Which isn't really
suprising, as the code has at least one comment saying it can't handle multiple
CPUs, and here the handler is called on all CPUs. And i'm not sure whether it
can handle 64 Bit.

So despite what the PDC spec says, C8000 and RP34xx/RP44xx don't want the
OS_HPMC length in the vector set, which is odd. I disassembled the firmware and
it actually looks like a Bug in PDC.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
Sven Schnelle 2020-10-02 20:07:20 +02:00 committed by Helge Deller
parent 61c439439c
commit c70919bd9d
2 changed files with 2 additions and 17 deletions

View File

@ -289,13 +289,3 @@ os_hpmc_6:
b . b .
nop nop
.align 16 /* make function length multiple of 16 bytes */ .align 16 /* make function length multiple of 16 bytes */
.os_hpmc_end:
__INITRODATA
.globl os_hpmc_size
.align 4
.type os_hpmc_size, @object
.size os_hpmc_size, 4
os_hpmc_size:
.word .os_hpmc_end-.os_hpmc

View File

@ -798,14 +798,13 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
void __init initialize_ivt(const void *iva) void __init initialize_ivt(const void *iva)
{ {
extern u32 os_hpmc_size;
extern const u32 os_hpmc[]; extern const u32 os_hpmc[];
int i; int i;
u32 check = 0; u32 check = 0;
u32 *ivap; u32 *ivap;
u32 *hpmcp; u32 *hpmcp;
u32 length, instr; u32 instr;
if (strcmp((const char *)iva, "cows can fly")) if (strcmp((const char *)iva, "cows can fly"))
panic("IVT invalid"); panic("IVT invalid");
@ -836,18 +835,14 @@ void __init initialize_ivt(const void *iva)
/* Setup IVA and compute checksum for HPMC handler */ /* Setup IVA and compute checksum for HPMC handler */
ivap[6] = (u32)__pa(os_hpmc); ivap[6] = (u32)__pa(os_hpmc);
length = os_hpmc_size;
ivap[7] = length;
hpmcp = (u32 *)os_hpmc; hpmcp = (u32 *)os_hpmc;
for (i=0; i<length/4; i++)
check += *hpmcp++;
for (i=0; i<8; i++) for (i=0; i<8; i++)
check += ivap[i]; check += ivap[i];
ivap[5] = -check; ivap[5] = -check;
pr_debug("initialize_ivt: IVA[6] = 0x%08x\n", ivap[6]);
} }