1*1a59d1b8SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * Copyright (C) 2001,2002,2003 Broadcom Corporation 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds#include <asm/asm.h> 71da177e4SLinus Torvalds#include <asm/regdef.h> 81da177e4SLinus Torvalds#include <asm/mipsregs.h> 91da177e4SLinus Torvalds#include <asm/stackframe.h> 101da177e4SLinus Torvalds#include <asm/cacheops.h> 111da177e4SLinus Torvalds#include <asm/sibyte/board.h> 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds#define C0_ERRCTL $26 /* CP0: Error info */ 141da177e4SLinus Torvalds#define C0_CERR_I $27 /* CP0: Icache error */ 151da177e4SLinus Torvalds#define C0_CERR_D $27,1 /* CP0: Dcache error */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds /* 181da177e4SLinus Torvalds * Based on SiByte sample software cache-err/cerr.S 191da177e4SLinus Torvalds * CVS revision 1.8. Only the 'unrecoverable' case 201da177e4SLinus Torvalds * is changed. 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds .set mips64 241da177e4SLinus Torvalds .set noreorder 251da177e4SLinus Torvalds .set noat 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 281da177e4SLinus Torvalds * sb1_cerr_vec: code to be copied to the Cache Error 291da177e4SLinus Torvalds * Exception vector. The code must be pushed out to memory 301da177e4SLinus Torvalds * (either by copying to Kseg0 and Kseg1 both, or by flushing 311da177e4SLinus Torvalds * the L1 and L2) since it is fetched as 0xa0000100. 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * NOTE: Be sure this handler is at most 28 instructions long 341da177e4SLinus Torvalds * since the final 16 bytes of the exception vector memory 351da177e4SLinus Torvalds * (0x170-0x17f) are used to preserve k0, k1, and ra. 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds 381da177e4SLinus TorvaldsLEAF(except_vec2_sb1) 391da177e4SLinus Torvalds /* 401da177e4SLinus Torvalds * If this error is recoverable, we need to exit the handler 411da177e4SLinus Torvalds * without having dirtied any registers. To do this, 421da177e4SLinus Torvalds * save/restore k0 and k1 from low memory (Useg is direct 431da177e4SLinus Torvalds * mapped while ERL=1). Note that we can't save to a 441da177e4SLinus Torvalds * CPU-specific location without ruining a register in the 451da177e4SLinus Torvalds * process. This means we are vulnerable to data corruption 461da177e4SLinus Torvalds * whenever the handler is reentered by a second CPU. 471da177e4SLinus Torvalds */ 481da177e4SLinus Torvalds sd k0,0x170($0) 491da177e4SLinus Torvalds sd k1,0x178($0) 501da177e4SLinus Torvalds 5151939fbbSRalf Baechle#ifdef CONFIG_SB1_CEX_ALWAYS_FATAL 52a4b5bd9aSAndrew Isaacson j handle_vec2_sb1 53a4b5bd9aSAndrew Isaacson nop 54a4b5bd9aSAndrew Isaacson#else 551da177e4SLinus Torvalds /* 561da177e4SLinus Torvalds * M_ERRCTL_RECOVERABLE is bit 31, which makes it easy to tell 571da177e4SLinus Torvalds * if we can fast-path out of here for a h/w-recovered error. 581da177e4SLinus Torvalds */ 591da177e4SLinus Torvalds mfc0 k1,C0_ERRCTL 601da177e4SLinus Torvalds bgtz k1,attempt_recovery 611da177e4SLinus Torvalds sll k0,k1,1 621da177e4SLinus Torvalds 631da177e4SLinus Torvaldsrecovered_dcache: 641da177e4SLinus Torvalds /* 651da177e4SLinus Torvalds * Unlock CacheErr-D (which in turn unlocks CacheErr-DPA). 6625985edcSLucas De Marchi * Ought to log the occurrence of this recovered dcache error. 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds b recovered 691da177e4SLinus Torvalds mtc0 $0,C0_CERR_D 701da177e4SLinus Torvalds 711da177e4SLinus Torvaldsattempt_recovery: 721da177e4SLinus Torvalds /* 731da177e4SLinus Torvalds * k0 has C0_ERRCTL << 1, which puts 'DC' at bit 31. Any 741da177e4SLinus Torvalds * Dcache errors we can recover from will take more extensive 751da177e4SLinus Torvalds * processing. For now, they are considered "unrecoverable". 761da177e4SLinus Torvalds * Note that 'DC' becoming set (outside of ERL mode) will 771da177e4SLinus Torvalds * cause 'IC' to clear; so if there's an Icache error, we'll 781da177e4SLinus Torvalds * only find out about it if we recover from this error and 791da177e4SLinus Torvalds * continue executing. 801da177e4SLinus Torvalds */ 811da177e4SLinus Torvalds bltz k0,unrecoverable 821da177e4SLinus Torvalds sll k0,1 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* 851da177e4SLinus Torvalds * k0 has C0_ERRCTL << 2, which puts 'IC' at bit 31. If an 861da177e4SLinus Torvalds * Icache error isn't indicated, I'm not sure why we got here. 871da177e4SLinus Torvalds * Consider that case "unrecoverable" for now. 881da177e4SLinus Torvalds */ 891da177e4SLinus Torvalds bgez k0,unrecoverable 901da177e4SLinus Torvalds 911da177e4SLinus Torvaldsattempt_icache_recovery: 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * External icache errors are due to uncorrectable ECC errors 941da177e4SLinus Torvalds * in the L2 cache or Memory Controller and cannot be 951da177e4SLinus Torvalds * recovered here. 961da177e4SLinus Torvalds */ 971da177e4SLinus Torvalds mfc0 k0,C0_CERR_I /* delay slot */ 981da177e4SLinus Torvalds li k1,1 << 26 /* ICACHE_EXTERNAL */ 991da177e4SLinus Torvalds and k1,k0 1001da177e4SLinus Torvalds bnez k1,unrecoverable 1011da177e4SLinus Torvalds andi k0,0x1fe0 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* 1041da177e4SLinus Torvalds * Since the error is internal, the 'IDX' field from 1051da177e4SLinus Torvalds * CacheErr-I is valid and we can just invalidate all blocks 1061da177e4SLinus Torvalds * in that set. 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds cache Index_Invalidate_I,(0<<13)(k0) 1091da177e4SLinus Torvalds cache Index_Invalidate_I,(1<<13)(k0) 1101da177e4SLinus Torvalds cache Index_Invalidate_I,(2<<13)(k0) 1111da177e4SLinus Torvalds cache Index_Invalidate_I,(3<<13)(k0) 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /* Ought to log this recovered icache error */ 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvaldsrecovered: 1161da177e4SLinus Torvalds /* Restore the saved registers */ 1171da177e4SLinus Torvalds ld k0,0x170($0) 1181da177e4SLinus Torvalds ld k1,0x178($0) 1191da177e4SLinus Torvalds eret 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvaldsunrecoverable: 1221da177e4SLinus Torvalds /* Unrecoverable Icache or Dcache error; log it and/or fail */ 1231da177e4SLinus Torvalds j handle_vec2_sb1 1241da177e4SLinus Torvalds nop 125a4b5bd9aSAndrew Isaacson#endif 1261da177e4SLinus Torvalds 1271da177e4SLinus TorvaldsEND(except_vec2_sb1) 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds LEAF(handle_vec2_sb1) 1301da177e4SLinus Torvalds mfc0 k0,CP0_CONFIG 1311da177e4SLinus Torvalds li k1,~CONF_CM_CMASK 1321da177e4SLinus Torvalds and k0,k0,k1 1331da177e4SLinus Torvalds ori k0,k0,CONF_CM_UNCACHED 1341da177e4SLinus Torvalds mtc0 k0,CP0_CONFIG 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds SSNOP 1371da177e4SLinus Torvalds SSNOP 1381da177e4SLinus Torvalds SSNOP 1391da177e4SLinus Torvalds SSNOP 1401da177e4SLinus Torvalds bnezl $0, 1f 1411da177e4SLinus Torvalds1: 1421da177e4SLinus Torvalds mfc0 k0, CP0_STATUS 1431da177e4SLinus Torvalds sll k0, k0, 3 # check CU0 (kernel?) 1441da177e4SLinus Torvalds bltz k0, 2f 1451da177e4SLinus Torvalds nop 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds /* Get a valid Kseg0 stack pointer. Any task's stack pointer 1481da177e4SLinus Torvalds * will do, although if we ever want to resume execution we 1491da177e4SLinus Torvalds * better not have corrupted any state. */ 1501da177e4SLinus Torvalds get_saved_sp 1511da177e4SLinus Torvalds move sp, k1 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds2: 1541da177e4SLinus Torvalds j sb1_cache_error 1551da177e4SLinus Torvalds nop 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds END(handle_vec2_sb1) 158