/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* HPMC (High Priority Machine Check) handler.3*4* Copyright (C) 1999 Philipp Rumpf <[email protected]>5* Copyright (C) 1999 Hewlett-Packard (Frank Rowand)6* Copyright (C) 2000 Hewlett-Packard (John Marvin)7*/8910/*11* This HPMC handler retrieves the HPMC pim data, resets IO and12* returns to the default trap handler with code set to 1 (HPMC).13* The default trap handler calls handle interruption, which14* does a stack and register dump. This at least allows kernel15* developers to get back to C code in virtual mode, where they16* have the option to examine and print values from memory that17* would help in debugging an HPMC caused by a software bug.18*19* There is more to do here:20*21* 1) On MP systems we need to synchronize processors22* before calling pdc/iodc.23* 2) We should be checking the system state and not24* returning to the fault handler if things are really25* bad.26*27*/2829.level 1.13031#include <asm/assembly.h>32#include <asm/pdc.h>33#include <asm/psw.h>3435#include <linux/linkage.h>36#include <linux/init.h>3738/*39* stack for os_hpmc, the HPMC handler.40* buffer for IODC procedures (for the HPMC handler).41*42* IODC requires 7K byte stack. That leaves 1K byte for os_hpmc.43*/4445.import toc_stack,data46#define hpmc_stack toc_stack /* re-use the TOC stack */4748#define HPMC_IODC_BUF_SIZE 0x80004950__PAGE_ALIGNED_BSS51.align 409652hpmc_iodc_buf:53.block HPMC_IODC_BUF_SIZE5455.section .bss56.align 857hpmc_raddr:58.block 1285960#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */6162.section .bss63.align 864ENTRY(hpmc_pim_data)65.block HPMC_PIM_DATA_SIZE66END(hpmc_pim_data)6768.text6970.import intr_save, code71.align 1672ENTRY(os_hpmc)73.os_hpmc:7475/*76* registers modified:77*78* Using callee saves registers without saving them. The79* original values are in the pim dump if we need them.80*81* r2 (rp) return pointer82* r3 address of PDCE_PROC83* r4 scratch84* r5 scratch85* r23 (arg3) procedure arg86* r24 (arg2) procedure arg87* r25 (arg1) procedure arg88* r26 (arg0) procedure arg89* r30 (sp) stack pointer90*91* registers read:92*93* r26 contains address of PDCE_PROC on entry94* r28 (ret0) return value from procedure95*/9697copy arg0, %r3 /* save address of PDCE_PROC */9899/*100* disable nested HPMCs101*102* Increment os_hpmc checksum to invalidate it.103* Do this before turning the PSW M bit off.104*/105106mfctl %cr14, %r4107ldw 52(%r4),%r5108addi 1,%r5,%r5109stw %r5,52(%r4)110111/* MP_FIXME: synchronize all processors. */112113/* Setup stack pointer. */114115load32 PA(hpmc_stack),sp116117ldo 128(sp),sp /* leave room for arguments */118119/*120* Most PDC routines require that the M bit be off.121* So turn on the Q bit and turn off the M bit.122*/123124ldi PSW_SM_Q,%r4 /* PSW Q on, PSW M off */125mtctl %r4,ipsw126mtctl %r0,pcsq127mtctl %r0,pcsq128load32 PA(os_hpmc_1),%r4129mtctl %r4,pcoq130ldo 4(%r4),%r4131mtctl %r4,pcoq132rfi133nop134135os_hpmc_1:136137/* Call PDC_PIM to get HPMC pim info */138139/*140* Note that on some newer boxes, PDC_PIM must be called141* before PDC_IO if you want IO to be reset. PDC_PIM sets142* a flag that PDC_IO examines.143*/144145ldo PDC_PIM(%r0), arg0146ldo PDC_PIM_HPMC(%r0),arg1 /* Transfer HPMC data */147load32 PA(hpmc_raddr),arg2148load32 PA(hpmc_pim_data),arg3149load32 HPMC_PIM_DATA_SIZE,%r4150stw %r4,-52(sp)151152ldil L%PA(os_hpmc_2), rp153bv (r3) /* call pdce_proc */154ldo R%PA(os_hpmc_2)(rp), rp155156os_hpmc_2:157comib,<> 0,ret0, os_hpmc_fail158159/* Reset IO by calling the hversion dependent PDC_IO routine */160161ldo PDC_IO(%r0),arg0162ldo 0(%r0),arg1 /* log IO errors */163ldo 0(%r0),arg2 /* reserved */164ldo 0(%r0),arg3 /* reserved */165stw %r0,-52(sp) /* reserved */166167ldil L%PA(os_hpmc_3),rp168bv (%r3) /* call pdce_proc */169ldo R%PA(os_hpmc_3)(rp),rp170171os_hpmc_3:172173/* FIXME? Check for errors from PDC_IO (-1 might be OK) */174175/*176* Initialize the IODC console device (HPA,SPA, path etc.177* are stored on page 0.178*/179180/*181* Load IODC into hpmc_iodc_buf by calling PDC_IODC.182* Note that PDC_IODC handles flushing the appropriate183* data and instruction cache lines.184*/185186ldo PDC_IODC(%r0),arg0187ldo PDC_IODC_READ(%r0),arg1188load32 PA(hpmc_raddr),arg2189ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */190ldo PDC_IODC_RI_INIT(%r0),%r4191stw %r4,-52(sp)192load32 PA(hpmc_iodc_buf),%r4193stw %r4,-56(sp)194load32 HPMC_IODC_BUF_SIZE,%r4195stw %r4,-60(sp)196197ldil L%PA(os_hpmc_4),rp198bv (%r3) /* call pdce_proc */199ldo R%PA(os_hpmc_4)(rp),rp200201os_hpmc_4:202comib,<> 0,ret0,os_hpmc_fail203204/* Call the entry init (just loaded by PDC_IODC) */205206ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg0 /* console hpa */207ldo ENTRY_INIT_MOD_DEV(%r0), arg1208ldw BOOT_CONSOLE_SPA_OFFSET(%r0),arg2 /* console spa */209depi 0,31,11,arg2 /* clear bits 21-31 */210ldo BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */211load32 PA(hpmc_raddr),%r4212stw %r4, -52(sp)213stw %r0, -56(sp) /* HV */214stw %r0, -60(sp) /* HV */215stw %r0, -64(sp) /* HV */216stw %r0, -68(sp) /* lang, must be zero */217218load32 PA(hpmc_iodc_buf),%r5219ldil L%PA(os_hpmc_5),rp220bv (%r5)221ldo R%PA(os_hpmc_5)(rp),rp222223os_hpmc_5:224comib,<> 0,ret0,os_hpmc_fail225226/* Prepare to call intr_save */227228/*229* Load kernel page directory (load into user also, since230* we don't intend to ever return to user land anyway)231*/232233load32 PA(swapper_pg_dir),%r4234mtctl %r4,%cr24 /* Initialize kernel root pointer */235mtctl %r4,%cr25 /* Initialize user root pointer */236237/* Clear sr4-sr7 */238239mtsp %r0, %sr4240mtsp %r0, %sr5241mtsp %r0, %sr6242mtsp %r0, %sr7243244tovirt_r1 %r30 /* make sp virtual */245246rsm PSW_SM_Q,%r0 /* Clear Q bit */247ldi 1,%r8 /* Set trap code to "1" for HPMC */248load32 PA(intr_save),%r1249be 0(%sr7,%r1)250nop251252os_hpmc_fail:253254/*255* Reset the system256*257* Some systems may lockup from a broadcast reset, so try the258* hversion PDC_BROADCAST_RESET() first.259* MP_FIXME: reset all processors if more than one central bus.260*/261262/* PDC_BROADCAST_RESET() */263264ldo PDC_BROADCAST_RESET(%r0),arg0265ldo 0(%r0),arg1 /* do reset */266267ldil L%PA(os_hpmc_6),rp268bv (%r3) /* call pdce_proc */269ldo R%PA(os_hpmc_6)(rp),rp270271os_hpmc_6:272273/*274* possible return values:275* -1 non-existent procedure276* -2 non-existent option277* -16 unaligned stack278*279* If call returned, do a broadcast reset.280*/281282ldil L%0xfffc0000,%r4 /* IO_BROADCAST */283ldo 5(%r0),%r5284stw %r5,48(%r4) /* CMD_RESET to IO_COMMAND offset */285286b .287nop288.align 16 /* make function length multiple of 16 bytes */289290291