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