linux/arch/parisc/kernel/hpmc.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/* 
   3 * HPMC (High Priority Machine Check) handler.
   4 *
   5 * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
   6 * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
   7 * Copyright (C) 2000 Hewlett-Packard (John Marvin)
   8 */
   9
  10
  11/*
  12 * This HPMC handler retrieves the HPMC pim data, resets IO and
  13 * returns to the default trap handler with code set to 1 (HPMC).
  14 * The default trap handler calls handle interruption, which
  15 * does a stack and register dump. This at least allows kernel
  16 * developers to get back to C code in virtual mode, where they
  17 * have the option to examine and print values from memory that
  18 * would help in debugging an HPMC caused by a software bug.
  19 *
  20 * There is more to do here:
  21 *
  22 *      1) On MP systems we need to synchronize processors
  23 *         before calling pdc/iodc.
  24 *      2) We should be checking the system state and not
  25 *         returning to the fault handler if things are really
  26 *         bad.
  27 *
  28 */
  29
  30        .level          1.1
  31
  32#include <asm/assembly.h>
  33#include <asm/pdc.h>
  34#include <asm/psw.h>
  35
  36#include <linux/linkage.h>
  37#include <linux/init.h>
  38
  39        /*
  40         * stack for os_hpmc, the HPMC handler.
  41         * buffer for IODC procedures (for the HPMC handler).
  42         *
  43         * IODC requires 7K byte stack.  That leaves 1K byte for os_hpmc.
  44         */
  45
  46        __PAGE_ALIGNED_BSS
  47        .align 4096
  48hpmc_stack:
  49        .block 16384
  50
  51#define HPMC_IODC_BUF_SIZE 0x8000
  52
  53        __PAGE_ALIGNED_BSS
  54        .align 4096
  55hpmc_iodc_buf:
  56        .block HPMC_IODC_BUF_SIZE
  57
  58        .section .bss
  59        .align 8
  60hpmc_raddr:
  61        .block 128
  62
  63#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
  64
  65        .section .bss
  66        .align 8
  67ENTRY(hpmc_pim_data)
  68        .block HPMC_PIM_DATA_SIZE
  69END(hpmc_pim_data)
  70
  71        .text
  72
  73        .import intr_save, code
  74        .align 16
  75ENTRY(os_hpmc)
  76.os_hpmc:
  77
  78        /*
  79         * registers modified:
  80         *
  81         *   Using callee saves registers without saving them.  The
  82         *   original values are in the pim dump if we need them.
  83         *
  84         *   r2   (rp)  return pointer
  85         *   r3   address of PDCE_PROC
  86         *   r4   scratch
  87         *   r5   scratch
  88         *   r23  (arg3) procedure arg
  89         *   r24  (arg2) procedure arg
  90         *   r25  (arg1) procedure arg
  91         *   r26  (arg0) procedure arg
  92         *   r30  (sp)   stack pointer
  93         *
  94         * registers read:
  95         *
  96         *   r26  contains address of PDCE_PROC on entry
  97         *   r28  (ret0) return value from procedure
  98         */
  99
 100        copy    arg0, %r3       /* save address of PDCE_PROC */
 101
 102        /*
 103         *  disable nested HPMCs
 104         *
 105         * Increment os_hpmc checksum to invalidate it.
 106         * Do this before turning the PSW M bit off.
 107         */
 108
 109        mfctl   %cr14, %r4
 110        ldw     52(%r4),%r5
 111        addi    1,%r5,%r5
 112        stw     %r5,52(%r4)
 113
 114        /* MP_FIXME: synchronize all processors. */
 115
 116        /* Setup stack pointer. */
 117
 118        load32  PA(hpmc_stack),sp
 119        
 120        ldo     128(sp),sp /* leave room for arguments */
 121
 122        /*
 123         * Most PDC routines require that the M bit be off.
 124         * So turn on the Q bit and turn off the M bit.
 125         */
 126
 127        ldi     PSW_SM_Q,%r4                   /* PSW Q on, PSW M off */
 128        mtctl   %r4,ipsw
 129        mtctl   %r0,pcsq
 130        mtctl   %r0,pcsq
 131        load32  PA(os_hpmc_1),%r4
 132        mtctl   %r4,pcoq
 133        ldo     4(%r4),%r4
 134        mtctl   %r4,pcoq
 135        rfi
 136        nop
 137
 138os_hpmc_1:
 139
 140        /* Call PDC_PIM to get HPMC pim info */
 141
 142        /*
 143         * Note that on some newer boxes, PDC_PIM must be called
 144         * before PDC_IO if you want IO to be reset. PDC_PIM sets
 145         * a flag that PDC_IO examines.
 146         */
 147
 148        ldo     PDC_PIM(%r0), arg0
 149        ldo     PDC_PIM_HPMC(%r0),arg1          /* Transfer HPMC data */
 150        load32  PA(hpmc_raddr),arg2
 151        load32  PA(hpmc_pim_data),arg3
 152        load32  HPMC_PIM_DATA_SIZE,%r4
 153        stw     %r4,-52(sp)
 154
 155        ldil    L%PA(os_hpmc_2), rp
 156        bv      (r3)                            /* call pdce_proc */
 157        ldo     R%PA(os_hpmc_2)(rp), rp
 158
 159os_hpmc_2:
 160        comib,<>  0,ret0, os_hpmc_fail
 161
 162        /* Reset IO by calling the hversion dependent PDC_IO routine */
 163
 164        ldo     PDC_IO(%r0),arg0
 165        ldo     0(%r0),arg1                     /* log IO errors */
 166        ldo     0(%r0),arg2                     /* reserved */
 167        ldo     0(%r0),arg3                     /* reserved */
 168        stw     %r0,-52(sp)                     /* reserved */
 169
 170        ldil    L%PA(os_hpmc_3),rp
 171        bv      (%r3)                           /* call pdce_proc */
 172        ldo     R%PA(os_hpmc_3)(rp),rp
 173
 174os_hpmc_3:
 175
 176        /* FIXME? Check for errors from PDC_IO (-1 might be OK) */
 177
 178        /*
 179         * Initialize the IODC console device (HPA,SPA, path etc.
 180         * are stored on page 0.
 181         */
 182
 183        /*
 184         * Load IODC into hpmc_iodc_buf by calling PDC_IODC.
 185         * Note that PDC_IODC handles flushing the appropriate
 186         * data and instruction cache lines.
 187         */
 188
 189        ldo     PDC_IODC(%r0),arg0
 190        ldo     PDC_IODC_READ(%r0),arg1
 191        load32  PA(hpmc_raddr),arg2
 192        ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
 193        ldo     PDC_IODC_RI_INIT(%r0),%r4
 194        stw     %r4,-52(sp)
 195        load32  PA(hpmc_iodc_buf),%r4
 196        stw     %r4,-56(sp)
 197        load32  HPMC_IODC_BUF_SIZE,%r4
 198        stw     %r4,-60(sp)
 199
 200        ldil    L%PA(os_hpmc_4),rp
 201        bv      (%r3)                            /* call pdce_proc */
 202        ldo     R%PA(os_hpmc_4)(rp),rp
 203
 204os_hpmc_4:
 205        comib,<>  0,ret0,os_hpmc_fail
 206
 207        /* Call the entry init (just loaded by PDC_IODC) */
 208
 209        ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg0  /* console hpa */
 210        ldo     ENTRY_INIT_MOD_DEV(%r0), arg1
 211        ldw     BOOT_CONSOLE_SPA_OFFSET(%r0),arg2  /* console spa */
 212        depi    0,31,11,arg2                       /* clear bits 21-31    */
 213        ldo     BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
 214        load32  PA(hpmc_raddr),%r4
 215        stw     %r4, -52(sp)
 216        stw     %r0, -56(sp)                    /* HV                  */
 217        stw     %r0, -60(sp)                    /* HV                  */
 218        stw     %r0, -64(sp)                    /* HV                  */
 219        stw     %r0, -68(sp)                    /* lang, must be zero  */
 220
 221        load32  PA(hpmc_iodc_buf),%r5
 222        ldil    L%PA(os_hpmc_5),rp
 223        bv      (%r5)
 224        ldo     R%PA(os_hpmc_5)(rp),rp
 225
 226os_hpmc_5:
 227        comib,<>  0,ret0,os_hpmc_fail
 228
 229        /* Prepare to call intr_save */
 230
 231        /*
 232         * Load kernel page directory (load into user also, since
 233         * we don't intend to ever return to user land anyway)
 234         */
 235
 236        load32          PA(swapper_pg_dir),%r4
 237        mtctl           %r4,%cr24       /* Initialize kernel root pointer */
 238        mtctl           %r4,%cr25       /* Initialize user root pointer */
 239
 240        /* Clear sr4-sr7 */
 241
 242        mtsp    %r0, %sr4
 243        mtsp    %r0, %sr5
 244        mtsp    %r0, %sr6
 245        mtsp    %r0, %sr7
 246
 247        tovirt_r1 %r30      /* make sp virtual */
 248
 249        rsm     PSW_SM_Q,%r0           /* Clear Q bit */
 250        ldi     1,%r8       /* Set trap code to "1" for HPMC */
 251        load32  PA(intr_save),%r1
 252        be      0(%sr7,%r1)
 253        nop
 254
 255os_hpmc_fail:
 256
 257        /*
 258         * Reset the system
 259         *
 260         * Some systems may lockup from a broadcast reset, so try the
 261         * hversion PDC_BROADCAST_RESET() first.
 262         * MP_FIXME: reset all processors if more than one central bus.
 263         */
 264
 265        /* PDC_BROADCAST_RESET() */
 266
 267        ldo     PDC_BROADCAST_RESET(%r0),arg0
 268        ldo     0(%r0),arg1                     /* do reset */
 269
 270        ldil    L%PA(os_hpmc_6),rp
 271        bv      (%r3)                           /* call pdce_proc */
 272        ldo     R%PA(os_hpmc_6)(rp),rp
 273
 274os_hpmc_6:
 275
 276        /*
 277         * possible return values:
 278         *  -1  non-existent procedure
 279         *  -2  non-existent option
 280         *  -16 unaligned stack
 281         *
 282         * If call returned, do a broadcast reset.
 283         */
 284
 285        ldil    L%0xfffc0000,%r4        /* IO_BROADCAST */
 286        ldo     5(%r0),%r5
 287        stw     %r5,48(%r4)             /*  CMD_RESET to IO_COMMAND offset */
 288
 289        b .
 290        nop
 291        .align 16       /* make function length multiple of 16 bytes */
 292.os_hpmc_end:
 293
 294
 295        __INITRODATA
 296.globl os_hpmc_size
 297        .align 4
 298        .type   os_hpmc_size, @object
 299        .size   os_hpmc_size, 4
 300os_hpmc_size:
 301        .word .os_hpmc_end-.os_hpmc
 302