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 #include <linux/sched.h>
0006 #include <asm/mipsregs.h>
0007 #include <asm/sibyte/sb1250.h>
0008 #include <asm/sibyte/sb1250_regs.h>
0009 
0010 #if !defined(CONFIG_SIBYTE_BUS_WATCHER) || defined(CONFIG_SIBYTE_BW_TRACE)
0011 #include <asm/io.h>
0012 #include <asm/sibyte/sb1250_scd.h>
0013 #endif
0014 
0015 /*
0016  * We'd like to dump the L2_ECC_TAG register on errors, but errata make
0017  * that unsafe... So for now we don't.  (BCM1250/BCM112x erratum SOC-48.)
0018  */
0019 #undef DUMP_L2_ECC_TAG_ON_ERROR
0020 
0021 /* SB1 definitions */
0022 
0023 /* XXX should come from config1 XXX */
0024 #define SB1_CACHE_INDEX_MASK   0x1fe0
0025 
0026 #define CP0_ERRCTL_RECOVERABLE (1 << 31)
0027 #define CP0_ERRCTL_DCACHE      (1 << 30)
0028 #define CP0_ERRCTL_ICACHE      (1 << 29)
0029 #define CP0_ERRCTL_MULTIBUS    (1 << 23)
0030 #define CP0_ERRCTL_MC_TLB      (1 << 15)
0031 #define CP0_ERRCTL_MC_TIMEOUT  (1 << 14)
0032 
0033 #define CP0_CERRI_TAG_PARITY   (1 << 29)
0034 #define CP0_CERRI_DATA_PARITY  (1 << 28)
0035 #define CP0_CERRI_EXTERNAL     (1 << 26)
0036 
0037 #define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL))
0038 #define CP0_CERRI_DATA         (CP0_CERRI_DATA_PARITY)
0039 
0040 #define CP0_CERRD_MULTIPLE     (1 << 31)
0041 #define CP0_CERRD_TAG_STATE    (1 << 30)
0042 #define CP0_CERRD_TAG_ADDRESS  (1 << 29)
0043 #define CP0_CERRD_DATA_SBE     (1 << 28)
0044 #define CP0_CERRD_DATA_DBE     (1 << 27)
0045 #define CP0_CERRD_EXTERNAL     (1 << 26)
0046 #define CP0_CERRD_LOAD         (1 << 25)
0047 #define CP0_CERRD_STORE        (1 << 24)
0048 #define CP0_CERRD_FILLWB       (1 << 23)
0049 #define CP0_CERRD_COHERENCY    (1 << 22)
0050 #define CP0_CERRD_DUPTAG       (1 << 21)
0051 
0052 #define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL))
0053 #define CP0_CERRD_IDX_VALID(c) \
0054    (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0)
0055 #define CP0_CERRD_CAUSES \
0056    (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG)
0057 #define CP0_CERRD_TYPES \
0058    (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL)
0059 #define CP0_CERRD_DATA         (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
0060 
0061 static uint32_t extract_ic(unsigned short addr, int data);
0062 static uint32_t extract_dc(unsigned short addr, int data);
0063 
0064 static inline void breakout_errctl(unsigned int val)
0065 {
0066     if (val & CP0_ERRCTL_RECOVERABLE)
0067         printk(" recoverable");
0068     if (val & CP0_ERRCTL_DCACHE)
0069         printk(" dcache");
0070     if (val & CP0_ERRCTL_ICACHE)
0071         printk(" icache");
0072     if (val & CP0_ERRCTL_MULTIBUS)
0073         printk(" multiple-buserr");
0074     printk("\n");
0075 }
0076 
0077 static inline void breakout_cerri(unsigned int val)
0078 {
0079     if (val & CP0_CERRI_TAG_PARITY)
0080         printk(" tag-parity");
0081     if (val & CP0_CERRI_DATA_PARITY)
0082         printk(" data-parity");
0083     if (val & CP0_CERRI_EXTERNAL)
0084         printk(" external");
0085     printk("\n");
0086 }
0087 
0088 static inline void breakout_cerrd(unsigned int val)
0089 {
0090     switch (val & CP0_CERRD_CAUSES) {
0091     case CP0_CERRD_LOAD:
0092         printk(" load,");
0093         break;
0094     case CP0_CERRD_STORE:
0095         printk(" store,");
0096         break;
0097     case CP0_CERRD_FILLWB:
0098         printk(" fill/wb,");
0099         break;
0100     case CP0_CERRD_COHERENCY:
0101         printk(" coherency,");
0102         break;
0103     case CP0_CERRD_DUPTAG:
0104         printk(" duptags,");
0105         break;
0106     default:
0107         printk(" NO CAUSE,");
0108         break;
0109     }
0110     if (!(val & CP0_CERRD_TYPES))
0111         printk(" NO TYPE");
0112     else {
0113         if (val & CP0_CERRD_MULTIPLE)
0114             printk(" multi-err");
0115         if (val & CP0_CERRD_TAG_STATE)
0116             printk(" tag-state");
0117         if (val & CP0_CERRD_TAG_ADDRESS)
0118             printk(" tag-address");
0119         if (val & CP0_CERRD_DATA_SBE)
0120             printk(" data-SBE");
0121         if (val & CP0_CERRD_DATA_DBE)
0122             printk(" data-DBE");
0123         if (val & CP0_CERRD_EXTERNAL)
0124             printk(" external");
0125     }
0126     printk("\n");
0127 }
0128 
0129 #ifndef CONFIG_SIBYTE_BUS_WATCHER
0130 
0131 static void check_bus_watcher(void)
0132 {
0133     uint32_t status, l2_err, memio_err;
0134 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0135     uint64_t l2_tag;
0136 #endif
0137 
0138     /* Destructive read, clears register and interrupt */
0139     status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
0140     /* Bit 31 is always on, but there's no #define for that */
0141     if (status & ~(1UL << 31)) {
0142         l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
0143 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0144         l2_tag = in64(IOADDR(A_L2_ECC_TAG));
0145 #endif
0146         memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
0147         printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
0148         printk("\nLast recorded signature:\n");
0149         printk("Request %02x from %d, answered by %d with Dcode %d\n",
0150                (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
0151                (int)(G_SCD_BERR_TID(status) >> 6),
0152                (int)G_SCD_BERR_RID(status),
0153                (int)G_SCD_BERR_DCODE(status));
0154 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0155         printk("Last L2 tag w/ bad ECC: %016llx\n", l2_tag);
0156 #endif
0157     } else {
0158         printk("Bus watcher indicates no error\n");
0159     }
0160 }
0161 #else
0162 extern void check_bus_watcher(void);
0163 #endif
0164 
0165 asmlinkage void sb1_cache_error(void)
0166 {
0167     uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
0168     unsigned long long cerr_dpa;
0169 
0170 #ifdef CONFIG_SIBYTE_BW_TRACE
0171     /* Freeze the trace buffer now */
0172     csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
0173     printk("Trace buffer frozen\n");
0174 #endif
0175 
0176     printk("Cache error exception on CPU %x:\n",
0177            (read_c0_prid() >> 25) & 0x7);
0178 
0179     __asm__ __volatile__ (
0180     "   .set    push\n\t"
0181     "   .set    mips64\n\t"
0182     "   .set    noat\n\t"
0183     "   mfc0    %0, $26\n\t"
0184     "   mfc0    %1, $27\n\t"
0185     "   mfc0    %2, $27, 1\n\t"
0186     "   dmfc0   $1, $27, 3\n\t"
0187     "   dsrl32  %3, $1, 0 \n\t"
0188     "   sll %4, $1, 0 \n\t"
0189     "   mfc0    %5, $30\n\t"
0190     "   .set    pop"
0191     : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
0192       "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
0193 
0194     cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
0195     printk(" c0_errorepc ==   %08x\n", eepc);
0196     printk(" c0_errctl   ==   %08x", errctl);
0197     breakout_errctl(errctl);
0198     if (errctl & CP0_ERRCTL_ICACHE) {
0199         printk(" c0_cerr_i   ==   %08x", cerr_i);
0200         breakout_cerri(cerr_i);
0201         if (CP0_CERRI_IDX_VALID(cerr_i)) {
0202             /* Check index of EPC, allowing for delay slot */
0203             if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) &&
0204                 ((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4)))
0205                 printk(" cerr_i idx doesn't match eepc\n");
0206             else {
0207                 res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
0208                          (cerr_i & CP0_CERRI_DATA) != 0);
0209                 if (!(res & cerr_i))
0210                     printk("...didn't see indicated icache problem\n");
0211             }
0212         }
0213     }
0214     if (errctl & CP0_ERRCTL_DCACHE) {
0215         printk(" c0_cerr_d   ==   %08x", cerr_d);
0216         breakout_cerrd(cerr_d);
0217         if (CP0_CERRD_DPA_VALID(cerr_d)) {
0218             printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
0219             if (!CP0_CERRD_IDX_VALID(cerr_d)) {
0220                 res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
0221                          (cerr_d & CP0_CERRD_DATA) != 0);
0222                 if (!(res & cerr_d))
0223                     printk("...didn't see indicated dcache problem\n");
0224             } else {
0225                 if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
0226                     printk(" cerr_d idx doesn't match cerr_dpa\n");
0227                 else {
0228                     res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
0229                              (cerr_d & CP0_CERRD_DATA) != 0);
0230                     if (!(res & cerr_d))
0231                         printk("...didn't see indicated problem\n");
0232                 }
0233             }
0234         }
0235     }
0236 
0237     check_bus_watcher();
0238 
0239     /*
0240      * Calling panic() when a fatal cache error occurs scrambles the
0241      * state of the system (and the cache), making it difficult to
0242      * investigate after the fact.  However, if you just stall the CPU,
0243      * the other CPU may keep on running, which is typically very
0244      * undesirable.
0245      */
0246 #ifdef CONFIG_SB1_CERR_STALL
0247     while (1)
0248         ;
0249 #else
0250     panic("unhandled cache error");
0251 #endif
0252 }
0253 
0254 
0255 /* Parity lookup table. */
0256 static const uint8_t parity[256] = {
0257     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0258     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0259     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0260     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0261     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0262     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0263     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0264     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0265     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0266     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0267     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0268     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0269     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0270     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0271     1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0272     0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
0273 };
0274 
0275 /* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
0276 static const uint64_t mask_72_64[8] = {
0277     0x0738C808099264FFULL,
0278     0x38C808099264FF07ULL,
0279     0xC808099264FF0738ULL,
0280     0x08099264FF0738C8ULL,
0281     0x099264FF0738C808ULL,
0282     0x9264FF0738C80809ULL,
0283     0x64FF0738C8080992ULL,
0284     0xFF0738C808099264ULL
0285 };
0286 
0287 /* Calculate the parity on a range of bits */
0288 static char range_parity(uint64_t dword, int max, int min)
0289 {
0290     char parity = 0;
0291     int i;
0292     dword >>= min;
0293     for (i=max-min; i>=0; i--) {
0294         if (dword & 0x1)
0295             parity = !parity;
0296         dword >>= 1;
0297     }
0298     return parity;
0299 }
0300 
0301 /* Calculate the 4-bit even byte-parity for an instruction */
0302 static unsigned char inst_parity(uint32_t word)
0303 {
0304     int i, j;
0305     char parity = 0;
0306     for (j=0; j<4; j++) {
0307         char byte_parity = 0;
0308         for (i=0; i<8; i++) {
0309             if (word & 0x80000000)
0310                 byte_parity = !byte_parity;
0311             word <<= 1;
0312         }
0313         parity <<= 1;
0314         parity |= byte_parity;
0315     }
0316     return parity;
0317 }
0318 
0319 static uint32_t extract_ic(unsigned short addr, int data)
0320 {
0321     unsigned short way;
0322     int valid;
0323     uint32_t taghi, taglolo, taglohi;
0324     unsigned long long taglo, va;
0325     uint64_t tlo_tmp;
0326     uint8_t lru;
0327     int res = 0;
0328 
0329     printk("Icache index 0x%04x  ", addr);
0330     for (way = 0; way < 4; way++) {
0331         /* Index-load-tag-I */
0332         __asm__ __volatile__ (
0333         "   .set    push        \n\t"
0334         "   .set    noreorder   \n\t"
0335         "   .set    mips64      \n\t"
0336         "   .set    noat        \n\t"
0337         "   cache   4, 0(%3)    \n\t"
0338         "   mfc0    %0, $29     \n\t"
0339         "   dmfc0   $1, $28     \n\t"
0340         "   dsrl32  %1, $1, 0   \n\t"
0341         "   sll %2, $1, 0   \n\t"
0342         "   .set    pop"
0343         : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
0344         : "r" ((way << 13) | addr));
0345 
0346         taglo = ((unsigned long long)taglohi << 32) | taglolo;
0347         if (way == 0) {
0348             lru = (taghi >> 14) & 0xff;
0349             printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
0350                     ((addr >> 5) & 0x3), /* bank */
0351                     ((addr >> 7) & 0x3f), /* index */
0352                     (lru & 0x3),
0353                     ((lru >> 2) & 0x3),
0354                     ((lru >> 4) & 0x3),
0355                     ((lru >> 6) & 0x3));
0356         }
0357         va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
0358         if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
0359             va |= 0x3FFFF00000000000ULL;
0360         valid = ((taghi >> 29) & 1);
0361         if (valid) {
0362             tlo_tmp = taglo & 0xfff3ff;
0363             if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
0364                 printk("   ** bad parity in VTag0/G/ASID\n");
0365                 res |= CP0_CERRI_TAG_PARITY;
0366             }
0367             if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
0368                 printk("   ** bad parity in R/VTag1\n");
0369                 res |= CP0_CERRI_TAG_PARITY;
0370             }
0371         }
0372         if (valid ^ ((taghi >> 27) & 1)) {
0373             printk("   ** bad parity for valid bit\n");
0374             res |= CP0_CERRI_TAG_PARITY;
0375         }
0376         printk(" %d  [VA %016llx]  [Vld? %d]  raw tags: %08X-%016llX\n",
0377                 way, va, valid, taghi, taglo);
0378 
0379         if (data) {
0380             uint32_t datahi, insta, instb;
0381             uint8_t predecode;
0382             int offset;
0383 
0384             /* (hit all banks and ways) */
0385             for (offset = 0; offset < 4; offset++) {
0386                 /* Index-load-data-I */
0387                 __asm__ __volatile__ (
0388                 "   .set    push\n\t"
0389                 "   .set    noreorder\n\t"
0390                 "   .set    mips64\n\t"
0391                 "   .set    noat\n\t"
0392                 "   cache   6, 0(%3)  \n\t"
0393                 "   mfc0    %0, $29, 1\n\t"
0394                 "   dmfc0  $1, $28, 1\n\t"
0395                 "   dsrl32 %1, $1, 0 \n\t"
0396                 "   sll    %2, $1, 0 \n\t"
0397                 "   .set    pop     \n"
0398                 : "=r" (datahi), "=r" (insta), "=r" (instb)
0399                 : "r" ((way << 13) | addr | (offset << 3)));
0400                 predecode = (datahi >> 8) & 0xff;
0401                 if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
0402                     printk("   ** bad parity in predecode\n");
0403                     res |= CP0_CERRI_DATA_PARITY;
0404                 }
0405                 /* XXXKW should/could check predecode bits themselves */
0406                 if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
0407                     printk("   ** bad parity in instruction a\n");
0408                     res |= CP0_CERRI_DATA_PARITY;
0409                 }
0410                 if ((datahi & 0xf) ^ inst_parity(instb)) {
0411                     printk("   ** bad parity in instruction b\n");
0412                     res |= CP0_CERRI_DATA_PARITY;
0413                 }
0414                 printk("  %05X-%08X%08X", datahi, insta, instb);
0415             }
0416             printk("\n");
0417         }
0418     }
0419     return res;
0420 }
0421 
0422 /* Compute the ECC for a data doubleword */
0423 static uint8_t dc_ecc(uint64_t dword)
0424 {
0425     uint64_t t;
0426     uint32_t w;
0427     uint8_t  p;
0428     int  i;
0429 
0430     p = 0;
0431     for (i = 7; i >= 0; i--)
0432     {
0433         p <<= 1;
0434         t = dword & mask_72_64[i];
0435         w = (uint32_t)(t >> 32);
0436         p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
0437               ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
0438         w = (uint32_t)(t & 0xFFFFFFFF);
0439         p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
0440               ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
0441     }
0442     return p;
0443 }
0444 
0445 struct dc_state {
0446     unsigned char val;
0447     char *name;
0448 };
0449 
0450 static struct dc_state dc_states[] = {
0451     { 0x00, "INVALID" },
0452     { 0x0f, "COH-SHD" },
0453     { 0x13, "NCO-E-C" },
0454     { 0x19, "NCO-E-D" },
0455     { 0x16, "COH-E-C" },
0456     { 0x1c, "COH-E-D" },
0457     { 0xff, "*ERROR*" }
0458 };
0459 
0460 #define DC_TAG_VALID(state) \
0461     (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
0462      ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
0463 
0464 static char *dc_state_str(unsigned char state)
0465 {
0466     struct dc_state *dsc = dc_states;
0467     while (dsc->val != 0xff) {
0468         if (dsc->val == state)
0469             break;
0470         dsc++;
0471     }
0472     return dsc->name;
0473 }
0474 
0475 static uint32_t extract_dc(unsigned short addr, int data)
0476 {
0477     int valid, way;
0478     unsigned char state;
0479     uint32_t taghi, taglolo, taglohi;
0480     unsigned long long taglo, pa;
0481     uint8_t ecc, lru;
0482     int res = 0;
0483 
0484     printk("Dcache index 0x%04x  ", addr);
0485     for (way = 0; way < 4; way++) {
0486         __asm__ __volatile__ (
0487         "   .set    push\n\t"
0488         "   .set    noreorder\n\t"
0489         "   .set    mips64\n\t"
0490         "   .set    noat\n\t"
0491         "   cache   5, 0(%3)\n\t"   /* Index-load-tag-D */
0492         "   mfc0    %0, $29, 2\n\t"
0493         "   dmfc0   $1, $28, 2\n\t"
0494         "   dsrl32  %1, $1, 0\n\t"
0495         "   sll %2, $1, 0\n\t"
0496         "   .set    pop"
0497         : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
0498         : "r" ((way << 13) | addr));
0499 
0500         taglo = ((unsigned long long)taglohi << 32) | taglolo;
0501         pa = (taglo & 0xFFFFFFE000ULL) | addr;
0502         if (way == 0) {
0503             lru = (taghi >> 14) & 0xff;
0504             printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
0505                     ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
0506                     ((addr >> 6) & 0x3f), /* index */
0507                     (lru & 0x3),
0508                     ((lru >> 2) & 0x3),
0509                     ((lru >> 4) & 0x3),
0510                     ((lru >> 6) & 0x3));
0511         }
0512         state = (taghi >> 25) & 0x1f;
0513         valid = DC_TAG_VALID(state);
0514         printk(" %d  [PA %010llx]  [state %s (%02x)]  raw tags: %08X-%016llX\n",
0515                 way, pa, dc_state_str(state), state, taghi, taglo);
0516         if (valid) {
0517             if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
0518                 printk("   ** bad parity in PTag1\n");
0519                 res |= CP0_CERRD_TAG_ADDRESS;
0520             }
0521             if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
0522                 printk("   ** bad parity in PTag0\n");
0523                 res |= CP0_CERRD_TAG_ADDRESS;
0524             }
0525         } else {
0526             res |= CP0_CERRD_TAG_STATE;
0527         }
0528 
0529         if (data) {
0530             uint32_t datalohi, datalolo, datahi;
0531             unsigned long long datalo;
0532             int offset;
0533             char bad_ecc = 0;
0534 
0535             for (offset = 0; offset < 4; offset++) {
0536                 /* Index-load-data-D */
0537                 __asm__ __volatile__ (
0538                 "   .set    push\n\t"
0539                 "   .set    noreorder\n\t"
0540                 "   .set    mips64\n\t"
0541                 "   .set    noat\n\t"
0542                 "   cache   7, 0(%3)\n\t" /* Index-load-data-D */
0543                 "   mfc0    %0, $29, 3\n\t"
0544                 "   dmfc0   $1, $28, 3\n\t"
0545                 "   dsrl32  %1, $1, 0 \n\t"
0546                 "   sll %2, $1, 0 \n\t"
0547                 "   .set    pop"
0548                 : "=r" (datahi), "=r" (datalohi), "=r" (datalolo)
0549                 : "r" ((way << 13) | addr | (offset << 3)));
0550                 datalo = ((unsigned long long)datalohi << 32) | datalolo;
0551                 ecc = dc_ecc(datalo);
0552                 if (ecc != datahi) {
0553                     int bits;
0554                     bad_ecc |= 1 << (3-offset);
0555                     ecc ^= datahi;
0556                     bits = hweight8(ecc);
0557                     res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
0558                 }
0559                 printk("  %02X-%016llX", datahi, datalo);
0560             }
0561             printk("\n");
0562             if (bad_ecc)
0563                 printk("  dwords w/ bad ECC: %d %d %d %d\n",
0564                        !!(bad_ecc & 8), !!(bad_ecc & 4),
0565                        !!(bad_ecc & 2), !!(bad_ecc & 1));
0566         }
0567     }
0568     return res;
0569 }