Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * Copyright (C) 2001,2002,2003 Broadcom Corporation
0004  */
0005 
0006 #include <asm/asm.h>
0007 #include <asm/regdef.h>
0008 #include <asm/mipsregs.h>
0009 #include <asm/stackframe.h>
0010 #include <asm/cacheops.h>
0011 #include <asm/sibyte/board.h>
0012 
0013 #define C0_ERRCTL     $26         /* CP0: Error info */
0014 #define C0_CERR_I     $27         /* CP0: Icache error */
0015 #define C0_CERR_D     $27,1       /* CP0: Dcache error */
0016 
0017     /*
0018      * Based on SiByte sample software cache-err/cerr.S
0019      * CVS revision 1.8.  Only the 'unrecoverable' case
0020      * is changed.
0021      */
0022 
0023     .set    mips64
0024     .set    noreorder
0025     .set    noat
0026 
0027     /*
0028      * sb1_cerr_vec: code to be copied to the Cache Error
0029      * Exception vector.  The code must be pushed out to memory
0030      * (either by copying to Kseg0 and Kseg1 both, or by flushing
0031      * the L1 and L2) since it is fetched as 0xa0000100.
0032      *
0033      * NOTE: Be sure this handler is at most 28 instructions long
0034      * since the final 16 bytes of the exception vector memory
0035      * (0x170-0x17f) are used to preserve k0, k1, and ra.
0036      */
0037 
0038 LEAF(except_vec2_sb1)
0039     /*
0040      * If this error is recoverable, we need to exit the handler
0041      * without having dirtied any registers.  To do this,
0042      * save/restore k0 and k1 from low memory (Useg is direct
0043      * mapped while ERL=1). Note that we can't save to a
0044      * CPU-specific location without ruining a register in the
0045      * process.  This means we are vulnerable to data corruption
0046      * whenever the handler is reentered by a second CPU.
0047      */
0048     sd  k0,0x170($0)
0049     sd  k1,0x178($0)
0050 
0051 #ifdef CONFIG_SB1_CEX_ALWAYS_FATAL
0052     j   handle_vec2_sb1
0053      nop
0054 #else
0055     /*
0056      * M_ERRCTL_RECOVERABLE is bit 31, which makes it easy to tell
0057      * if we can fast-path out of here for a h/w-recovered error.
0058      */
0059     mfc0    k1,C0_ERRCTL
0060     bgtz    k1,attempt_recovery
0061      sll    k0,k1,1
0062 
0063 recovered_dcache:
0064     /*
0065      * Unlock CacheErr-D (which in turn unlocks CacheErr-DPA).
0066      * Ought to log the occurrence of this recovered dcache error.
0067      */
0068     b   recovered
0069      mtc0   $0,C0_CERR_D
0070 
0071 attempt_recovery:
0072     /*
0073      * k0 has C0_ERRCTL << 1, which puts 'DC' at bit 31.  Any
0074      * Dcache errors we can recover from will take more extensive
0075      * processing.  For now, they are considered "unrecoverable".
0076      * Note that 'DC' becoming set (outside of ERL mode) will
0077      * cause 'IC' to clear; so if there's an Icache error, we'll
0078      * only find out about it if we recover from this error and
0079      * continue executing.
0080      */
0081     bltz    k0,unrecoverable
0082      sll    k0,1
0083 
0084     /*
0085      * k0 has C0_ERRCTL << 2, which puts 'IC' at bit 31.  If an
0086      * Icache error isn't indicated, I'm not sure why we got here.
0087      * Consider that case "unrecoverable" for now.
0088      */
0089     bgez    k0,unrecoverable
0090 
0091 attempt_icache_recovery:
0092     /*
0093      * External icache errors are due to uncorrectable ECC errors
0094      * in the L2 cache or Memory Controller and cannot be
0095      * recovered here.
0096      */
0097      mfc0   k0,C0_CERR_I        /* delay slot */
0098     li  k1,1 << 26      /* ICACHE_EXTERNAL */
0099     and k1,k0
0100     bnez    k1,unrecoverable
0101      andi   k0,0x1fe0
0102 
0103     /*
0104      * Since the error is internal, the 'IDX' field from
0105      * CacheErr-I is valid and we can just invalidate all blocks
0106      * in that set.
0107      */
0108     cache   Index_Invalidate_I,(0<<13)(k0)
0109     cache   Index_Invalidate_I,(1<<13)(k0)
0110     cache   Index_Invalidate_I,(2<<13)(k0)
0111     cache   Index_Invalidate_I,(3<<13)(k0)
0112 
0113     /* Ought to log this recovered icache error */
0114 
0115 recovered:
0116     /* Restore the saved registers */
0117     ld  k0,0x170($0)
0118     ld  k1,0x178($0)
0119     eret
0120 
0121 unrecoverable:
0122     /* Unrecoverable Icache or Dcache error; log it and/or fail */
0123     j   handle_vec2_sb1
0124      nop
0125 #endif
0126 
0127 END(except_vec2_sb1)
0128 
0129     LEAF(handle_vec2_sb1)
0130     mfc0    k0,CP0_CONFIG
0131     li  k1,~CONF_CM_CMASK
0132     and k0,k0,k1
0133     ori k0,k0,CONF_CM_UNCACHED
0134     mtc0    k0,CP0_CONFIG
0135 
0136     SSNOP
0137     SSNOP
0138     SSNOP
0139     SSNOP
0140     bnezl   $0, 1f
0141 1:
0142     mfc0    k0, CP0_STATUS
0143     sll k0, k0, 3           # check CU0 (kernel?)
0144     bltz    k0, 2f
0145      nop
0146 
0147     /* Get a valid Kseg0 stack pointer.  Any task's stack pointer
0148      * will do, although if we ever want to resume execution we
0149      * better not have corrupted any state. */
0150     get_saved_sp
0151     move    sp, k1
0152 
0153 2:
0154     j   sb1_cache_error
0155      nop
0156 
0157     END(handle_vec2_sb1)