linux/arch/mips/mm/cerr-sb1.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001,2002,2003 Broadcom Corporation
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public License
   6 * as published by the Free Software Foundation; either version 2
   7 * of the License, or (at your option) any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17 */
  18#include <linux/sched.h>
  19#include <asm/mipsregs.h>
  20#include <asm/sibyte/sb1250.h>
  21#include <asm/sibyte/sb1250_regs.h>
  22
  23#if !defined(CONFIG_SIBYTE_BUS_WATCHER) || defined(CONFIG_SIBYTE_BW_TRACE)
  24#include <asm/io.h>
  25#include <asm/sibyte/sb1250_scd.h>
  26#endif
  27
  28/*
  29 * We'd like to dump the L2_ECC_TAG register on errors, but errata make
  30 * that unsafe... So for now we don't.  (BCM1250/BCM112x erratum SOC-48.)
  31 */
  32#undef DUMP_L2_ECC_TAG_ON_ERROR
  33
  34/* SB1 definitions */
  35
  36/* XXX should come from config1 XXX */
  37#define SB1_CACHE_INDEX_MASK   0x1fe0
  38
  39#define CP0_ERRCTL_RECOVERABLE (1 << 31)
  40#define CP0_ERRCTL_DCACHE      (1 << 30)
  41#define CP0_ERRCTL_ICACHE      (1 << 29)
  42#define CP0_ERRCTL_MULTIBUS    (1 << 23)
  43#define CP0_ERRCTL_MC_TLB      (1 << 15)
  44#define CP0_ERRCTL_MC_TIMEOUT  (1 << 14)
  45
  46#define CP0_CERRI_TAG_PARITY   (1 << 29)
  47#define CP0_CERRI_DATA_PARITY  (1 << 28)
  48#define CP0_CERRI_EXTERNAL     (1 << 26)
  49
  50#define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL))
  51#define CP0_CERRI_DATA         (CP0_CERRI_DATA_PARITY)
  52
  53#define CP0_CERRD_MULTIPLE     (1 << 31)
  54#define CP0_CERRD_TAG_STATE    (1 << 30)
  55#define CP0_CERRD_TAG_ADDRESS  (1 << 29)
  56#define CP0_CERRD_DATA_SBE     (1 << 28)
  57#define CP0_CERRD_DATA_DBE     (1 << 27)
  58#define CP0_CERRD_EXTERNAL     (1 << 26)
  59#define CP0_CERRD_LOAD         (1 << 25)
  60#define CP0_CERRD_STORE        (1 << 24)
  61#define CP0_CERRD_FILLWB       (1 << 23)
  62#define CP0_CERRD_COHERENCY    (1 << 22)
  63#define CP0_CERRD_DUPTAG       (1 << 21)
  64
  65#define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL))
  66#define CP0_CERRD_IDX_VALID(c) \
  67   (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0)
  68#define CP0_CERRD_CAUSES \
  69   (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG)
  70#define CP0_CERRD_TYPES \
  71   (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL)
  72#define CP0_CERRD_DATA         (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
  73
  74static uint32_t extract_ic(unsigned short addr, int data);
  75static uint32_t extract_dc(unsigned short addr, int data);
  76
  77static inline void breakout_errctl(unsigned int val)
  78{
  79        if (val & CP0_ERRCTL_RECOVERABLE)
  80                printk(" recoverable");
  81        if (val & CP0_ERRCTL_DCACHE)
  82                printk(" dcache");
  83        if (val & CP0_ERRCTL_ICACHE)
  84                printk(" icache");
  85        if (val & CP0_ERRCTL_MULTIBUS)
  86                printk(" multiple-buserr");
  87        printk("\n");
  88}
  89
  90static inline void breakout_cerri(unsigned int val)
  91{
  92        if (val & CP0_CERRI_TAG_PARITY)
  93                printk(" tag-parity");
  94        if (val & CP0_CERRI_DATA_PARITY)
  95                printk(" data-parity");
  96        if (val & CP0_CERRI_EXTERNAL)
  97                printk(" external");
  98        printk("\n");
  99}
 100
 101static inline void breakout_cerrd(unsigned int val)
 102{
 103        switch (val & CP0_CERRD_CAUSES) {
 104        case CP0_CERRD_LOAD:
 105                printk(" load,");
 106                break;
 107        case CP0_CERRD_STORE:
 108                printk(" store,");
 109                break;
 110        case CP0_CERRD_FILLWB:
 111                printk(" fill/wb,");
 112                break;
 113        case CP0_CERRD_COHERENCY:
 114                printk(" coherency,");
 115                break;
 116        case CP0_CERRD_DUPTAG:
 117                printk(" duptags,");
 118                break;
 119        default:
 120                printk(" NO CAUSE,");
 121                break;
 122        }
 123        if (!(val & CP0_CERRD_TYPES))
 124                printk(" NO TYPE");
 125        else {
 126                if (val & CP0_CERRD_MULTIPLE)
 127                        printk(" multi-err");
 128                if (val & CP0_CERRD_TAG_STATE)
 129                        printk(" tag-state");
 130                if (val & CP0_CERRD_TAG_ADDRESS)
 131                        printk(" tag-address");
 132                if (val & CP0_CERRD_DATA_SBE)
 133                        printk(" data-SBE");
 134                if (val & CP0_CERRD_DATA_DBE)
 135                        printk(" data-DBE");
 136                if (val & CP0_CERRD_EXTERNAL)
 137                        printk(" external");
 138        }
 139        printk("\n");
 140}
 141
 142#ifndef CONFIG_SIBYTE_BUS_WATCHER
 143
 144static void check_bus_watcher(void)
 145{
 146        uint32_t status, l2_err, memio_err;
 147#ifdef DUMP_L2_ECC_TAG_ON_ERROR
 148        uint64_t l2_tag;
 149#endif
 150
 151        /* Destructive read, clears register and interrupt */
 152        status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
 153        /* Bit 31 is always on, but there's no #define for that */
 154        if (status & ~(1UL << 31)) {
 155                l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
 156#ifdef DUMP_L2_ECC_TAG_ON_ERROR
 157                l2_tag = in64(IOADDR(A_L2_ECC_TAG));
 158#endif
 159                memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
 160                printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
 161                printk("\nLast recorded signature:\n");
 162                printk("Request %02x from %d, answered by %d with Dcode %d\n",
 163                       (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
 164                       (int)(G_SCD_BERR_TID(status) >> 6),
 165                       (int)G_SCD_BERR_RID(status),
 166                       (int)G_SCD_BERR_DCODE(status));
 167#ifdef DUMP_L2_ECC_TAG_ON_ERROR
 168                printk("Last L2 tag w/ bad ECC: %016llx\n", l2_tag);
 169#endif
 170        } else {
 171                printk("Bus watcher indicates no error\n");
 172        }
 173}
 174#else
 175extern void check_bus_watcher(void);
 176#endif
 177
 178asmlinkage void sb1_cache_error(void)
 179{
 180        uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
 181        unsigned long long cerr_dpa;
 182
 183#ifdef CONFIG_SIBYTE_BW_TRACE
 184        /* Freeze the trace buffer now */
 185        csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
 186        printk("Trace buffer frozen\n");
 187#endif
 188
 189        printk("Cache error exception on CPU %x:\n",
 190               (read_c0_prid() >> 25) & 0x7);
 191
 192        __asm__ __volatile__ (
 193        "       .set    push\n\t"
 194        "       .set    mips64\n\t"
 195        "       .set    noat\n\t"
 196        "       mfc0    %0, $26\n\t"
 197        "       mfc0    %1, $27\n\t"
 198        "       mfc0    %2, $27, 1\n\t"
 199        "       dmfc0   $1, $27, 3\n\t"
 200        "       dsrl32  %3, $1, 0 \n\t"
 201        "       sll     %4, $1, 0 \n\t"
 202        "       mfc0    %5, $30\n\t"
 203        "       .set    pop"
 204        : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
 205          "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
 206
 207        cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
 208        printk(" c0_errorepc ==   %08x\n", eepc);
 209        printk(" c0_errctl   ==   %08x", errctl);
 210        breakout_errctl(errctl);
 211        if (errctl & CP0_ERRCTL_ICACHE) {
 212                printk(" c0_cerr_i   ==   %08x", cerr_i);
 213                breakout_cerri(cerr_i);
 214                if (CP0_CERRI_IDX_VALID(cerr_i)) {
 215                        /* Check index of EPC, allowing for delay slot */
 216                        if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) &&
 217                            ((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4)))
 218                                printk(" cerr_i idx doesn't match eepc\n");
 219                        else {
 220                                res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
 221                                                 (cerr_i & CP0_CERRI_DATA) != 0);
 222                                if (!(res & cerr_i))
 223                                        printk("...didn't see indicated icache problem\n");
 224                        }
 225                }
 226        }
 227        if (errctl & CP0_ERRCTL_DCACHE) {
 228                printk(" c0_cerr_d   ==   %08x", cerr_d);
 229                breakout_cerrd(cerr_d);
 230                if (CP0_CERRD_DPA_VALID(cerr_d)) {
 231                        printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
 232                        if (!CP0_CERRD_IDX_VALID(cerr_d)) {
 233                                res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
 234                                                 (cerr_d & CP0_CERRD_DATA) != 0);
 235                                if (!(res & cerr_d))
 236                                        printk("...didn't see indicated dcache problem\n");
 237                        } else {
 238                                if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
 239                                        printk(" cerr_d idx doesn't match cerr_dpa\n");
 240                                else {
 241                                        res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
 242                                                         (cerr_d & CP0_CERRD_DATA) != 0);
 243                                        if (!(res & cerr_d))
 244                                                printk("...didn't see indicated problem\n");
 245                                }
 246                        }
 247                }
 248        }
 249
 250        check_bus_watcher();
 251
 252        /*
 253         * Calling panic() when a fatal cache error occurs scrambles the
 254         * state of the system (and the cache), making it difficult to
 255         * investigate after the fact.  However, if you just stall the CPU,
 256         * the other CPU may keep on running, which is typically very
 257         * undesirable.
 258         */
 259#ifdef CONFIG_SB1_CERR_STALL
 260        while (1)
 261                ;
 262#else
 263        panic("unhandled cache error");
 264#endif
 265}
 266
 267
 268/* Parity lookup table. */
 269static const uint8_t parity[256] = {
 270        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 271        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 272        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 273        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 274        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 275        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 276        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 277        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 278        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 279        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 280        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 281        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 282        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 283        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 284        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 285        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
 286};
 287
 288/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
 289static const uint64_t mask_72_64[8] = {
 290        0x0738C808099264FFULL,
 291        0x38C808099264FF07ULL,
 292        0xC808099264FF0738ULL,
 293        0x08099264FF0738C8ULL,
 294        0x099264FF0738C808ULL,
 295        0x9264FF0738C80809ULL,
 296        0x64FF0738C8080992ULL,
 297        0xFF0738C808099264ULL
 298};
 299
 300/* Calculate the parity on a range of bits */
 301static char range_parity(uint64_t dword, int max, int min)
 302{
 303        char parity = 0;
 304        int i;
 305        dword >>= min;
 306        for (i=max-min; i>=0; i--) {
 307                if (dword & 0x1)
 308                        parity = !parity;
 309                dword >>= 1;
 310        }
 311        return parity;
 312}
 313
 314/* Calculate the 4-bit even byte-parity for an instruction */
 315static unsigned char inst_parity(uint32_t word)
 316{
 317        int i, j;
 318        char parity = 0;
 319        for (j=0; j<4; j++) {
 320                char byte_parity = 0;
 321                for (i=0; i<8; i++) {
 322                        if (word & 0x80000000)
 323                                byte_parity = !byte_parity;
 324                        word <<= 1;
 325                }
 326                parity <<= 1;
 327                parity |= byte_parity;
 328        }
 329        return parity;
 330}
 331
 332static uint32_t extract_ic(unsigned short addr, int data)
 333{
 334        unsigned short way;
 335        int valid;
 336        uint32_t taghi, taglolo, taglohi;
 337        unsigned long long taglo, va;
 338        uint64_t tlo_tmp;
 339        uint8_t lru;
 340        int res = 0;
 341
 342        printk("Icache index 0x%04x  ", addr);
 343        for (way = 0; way < 4; way++) {
 344                /* Index-load-tag-I */
 345                __asm__ __volatile__ (
 346                "       .set    push            \n\t"
 347                "       .set    noreorder       \n\t"
 348                "       .set    mips64          \n\t"
 349                "       .set    noat            \n\t"
 350                "       cache   4, 0(%3)        \n\t"
 351                "       mfc0    %0, $29         \n\t"
 352                "       dmfc0   $1, $28         \n\t"
 353                "       dsrl32  %1, $1, 0       \n\t"
 354                "       sll     %2, $1, 0       \n\t"
 355                "       .set    pop"
 356                : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
 357                : "r" ((way << 13) | addr));
 358
 359                taglo = ((unsigned long long)taglohi << 32) | taglolo;
 360                if (way == 0) {
 361                        lru = (taghi >> 14) & 0xff;
 362                        printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
 363                                    ((addr >> 5) & 0x3), /* bank */
 364                                    ((addr >> 7) & 0x3f), /* index */
 365                                    (lru & 0x3),
 366                                    ((lru >> 2) & 0x3),
 367                                    ((lru >> 4) & 0x3),
 368                                    ((lru >> 6) & 0x3));
 369                }
 370                va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
 371                if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
 372                        va |= 0x3FFFF00000000000ULL;
 373                valid = ((taghi >> 29) & 1);
 374                if (valid) {
 375                        tlo_tmp = taglo & 0xfff3ff;
 376                        if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
 377                                printk("   ** bad parity in VTag0/G/ASID\n");
 378                                res |= CP0_CERRI_TAG_PARITY;
 379                        }
 380                        if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
 381                                printk("   ** bad parity in R/VTag1\n");
 382                                res |= CP0_CERRI_TAG_PARITY;
 383                        }
 384                }
 385                if (valid ^ ((taghi >> 27) & 1)) {
 386                        printk("   ** bad parity for valid bit\n");
 387                        res |= CP0_CERRI_TAG_PARITY;
 388                }
 389                printk(" %d  [VA %016llx]  [Vld? %d]  raw tags: %08X-%016llX\n",
 390                            way, va, valid, taghi, taglo);
 391
 392                if (data) {
 393                        uint32_t datahi, insta, instb;
 394                        uint8_t predecode;
 395                        int offset;
 396
 397                        /* (hit all banks and ways) */
 398                        for (offset = 0; offset < 4; offset++) {
 399                                /* Index-load-data-I */
 400                                __asm__ __volatile__ (
 401                                "       .set    push\n\t"
 402                                "       .set    noreorder\n\t"
 403                                "       .set    mips64\n\t"
 404                                "       .set    noat\n\t"
 405                                "       cache   6, 0(%3)  \n\t"
 406                                "       mfc0    %0, $29, 1\n\t"
 407                                "       dmfc0  $1, $28, 1\n\t"
 408                                "       dsrl32 %1, $1, 0 \n\t"
 409                                "       sll    %2, $1, 0 \n\t"
 410                                "       .set    pop         \n"
 411                                : "=r" (datahi), "=r" (insta), "=r" (instb)
 412                                : "r" ((way << 13) | addr | (offset << 3)));
 413                                predecode = (datahi >> 8) & 0xff;
 414                                if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
 415                                        printk("   ** bad parity in predecode\n");
 416                                        res |= CP0_CERRI_DATA_PARITY;
 417                                }
 418                                /* XXXKW should/could check predecode bits themselves */
 419                                if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
 420                                        printk("   ** bad parity in instruction a\n");
 421                                        res |= CP0_CERRI_DATA_PARITY;
 422                                }
 423                                if ((datahi & 0xf) ^ inst_parity(instb)) {
 424                                        printk("   ** bad parity in instruction b\n");
 425                                        res |= CP0_CERRI_DATA_PARITY;
 426                                }
 427                                printk("  %05X-%08X%08X", datahi, insta, instb);
 428                        }
 429                        printk("\n");
 430                }
 431        }
 432        return res;
 433}
 434
 435/* Compute the ECC for a data doubleword */
 436static uint8_t dc_ecc(uint64_t dword)
 437{
 438        uint64_t t;
 439        uint32_t w;
 440        uint8_t  p;
 441        int      i;
 442
 443        p = 0;
 444        for (i = 7; i >= 0; i--)
 445        {
 446                p <<= 1;
 447                t = dword & mask_72_64[i];
 448                w = (uint32_t)(t >> 32);
 449                p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
 450                      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
 451                w = (uint32_t)(t & 0xFFFFFFFF);
 452                p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
 453                      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
 454        }
 455        return p;
 456}
 457
 458struct dc_state {
 459        unsigned char val;
 460        char *name;
 461};
 462
 463static struct dc_state dc_states[] = {
 464        { 0x00, "INVALID" },
 465        { 0x0f, "COH-SHD" },
 466        { 0x13, "NCO-E-C" },
 467        { 0x19, "NCO-E-D" },
 468        { 0x16, "COH-E-C" },
 469        { 0x1c, "COH-E-D" },
 470        { 0xff, "*ERROR*" }
 471};
 472
 473#define DC_TAG_VALID(state) \
 474    (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
 475     ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
 476
 477static char *dc_state_str(unsigned char state)
 478{
 479        struct dc_state *dsc = dc_states;
 480        while (dsc->val != 0xff) {
 481                if (dsc->val == state)
 482                        break;
 483                dsc++;
 484        }
 485        return dsc->name;
 486}
 487
 488static uint32_t extract_dc(unsigned short addr, int data)
 489{
 490        int valid, way;
 491        unsigned char state;
 492        uint32_t taghi, taglolo, taglohi;
 493        unsigned long long taglo, pa;
 494        uint8_t ecc, lru;
 495        int res = 0;
 496
 497        printk("Dcache index 0x%04x  ", addr);
 498        for (way = 0; way < 4; way++) {
 499                __asm__ __volatile__ (
 500                "       .set    push\n\t"
 501                "       .set    noreorder\n\t"
 502                "       .set    mips64\n\t"
 503                "       .set    noat\n\t"
 504                "       cache   5, 0(%3)\n\t"   /* Index-load-tag-D */
 505                "       mfc0    %0, $29, 2\n\t"
 506                "       dmfc0   $1, $28, 2\n\t"
 507                "       dsrl32  %1, $1, 0\n\t"
 508                "       sll     %2, $1, 0\n\t"
 509                "       .set    pop"
 510                : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
 511                : "r" ((way << 13) | addr));
 512
 513                taglo = ((unsigned long long)taglohi << 32) | taglolo;
 514                pa = (taglo & 0xFFFFFFE000ULL) | addr;
 515                if (way == 0) {
 516                        lru = (taghi >> 14) & 0xff;
 517                        printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
 518                                    ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
 519                                    ((addr >> 6) & 0x3f), /* index */
 520                                    (lru & 0x3),
 521                                    ((lru >> 2) & 0x3),
 522                                    ((lru >> 4) & 0x3),
 523                                    ((lru >> 6) & 0x3));
 524                }
 525                state = (taghi >> 25) & 0x1f;
 526                valid = DC_TAG_VALID(state);
 527                printk(" %d  [PA %010llx]  [state %s (%02x)]  raw tags: %08X-%016llX\n",
 528                            way, pa, dc_state_str(state), state, taghi, taglo);
 529                if (valid) {
 530                        if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
 531                                printk("   ** bad parity in PTag1\n");
 532                                res |= CP0_CERRD_TAG_ADDRESS;
 533                        }
 534                        if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
 535                                printk("   ** bad parity in PTag0\n");
 536                                res |= CP0_CERRD_TAG_ADDRESS;
 537                        }
 538                } else {
 539                        res |= CP0_CERRD_TAG_STATE;
 540                }
 541
 542                if (data) {
 543                        uint32_t datalohi, datalolo, datahi;
 544                        unsigned long long datalo;
 545                        int offset;
 546                        char bad_ecc = 0;
 547
 548                        for (offset = 0; offset < 4; offset++) {
 549                                /* Index-load-data-D */
 550                                __asm__ __volatile__ (
 551                                "       .set    push\n\t"
 552                                "       .set    noreorder\n\t"
 553                                "       .set    mips64\n\t"
 554                                "       .set    noat\n\t"
 555                                "       cache   7, 0(%3)\n\t" /* Index-load-data-D */
 556                                "       mfc0    %0, $29, 3\n\t"
 557                                "       dmfc0   $1, $28, 3\n\t"
 558                                "       dsrl32  %1, $1, 0 \n\t"
 559                                "       sll     %2, $1, 0 \n\t"
 560                                "       .set    pop"
 561                                : "=r" (datahi), "=r" (datalohi), "=r" (datalolo)
 562                                : "r" ((way << 13) | addr | (offset << 3)));
 563                                datalo = ((unsigned long long)datalohi << 32) | datalolo;
 564                                ecc = dc_ecc(datalo);
 565                                if (ecc != datahi) {
 566                                        int bits;
 567                                        bad_ecc |= 1 << (3-offset);
 568                                        ecc ^= datahi;
 569                                        bits = hweight8(ecc);
 570                                        res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
 571                                }
 572                                printk("  %02X-%016llX", datahi, datalo);
 573                        }
 574                        printk("\n");
 575                        if (bad_ecc)
 576                                printk("  dwords w/ bad ECC: %d %d %d %d\n",
 577                                       !!(bad_ecc & 8), !!(bad_ecc & 4),
 578                                       !!(bad_ecc & 2), !!(bad_ecc & 1));
 579                }
 580        }
 581        return res;
 582}
 583