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#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
 186        csr_out32(M_BCM1480_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
 187#else
 188        csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
 189#endif
 190        printk("Trace buffer frozen\n");
 191#endif
 192
 193        printk("Cache error exception on CPU %x:\n",
 194               (read_c0_prid() >> 25) & 0x7);
 195
 196        __asm__ __volatile__ (
 197        "       .set    push\n\t"
 198        "       .set    mips64\n\t"
 199        "       .set    noat\n\t"
 200        "       mfc0    %0, $26\n\t"
 201        "       mfc0    %1, $27\n\t"
 202        "       mfc0    %2, $27, 1\n\t"
 203        "       dmfc0   $1, $27, 3\n\t"
 204        "       dsrl32  %3, $1, 0 \n\t"
 205        "       sll     %4, $1, 0 \n\t"
 206        "       mfc0    %5, $30\n\t"
 207        "       .set    pop"
 208        : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
 209          "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
 210
 211        cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
 212        printk(" c0_errorepc ==   %08x\n", eepc);
 213        printk(" c0_errctl   ==   %08x", errctl);
 214        breakout_errctl(errctl);
 215        if (errctl & CP0_ERRCTL_ICACHE) {
 216                printk(" c0_cerr_i   ==   %08x", cerr_i);
 217                breakout_cerri(cerr_i);
 218                if (CP0_CERRI_IDX_VALID(cerr_i)) {
 219                        /* Check index of EPC, allowing for delay slot */
 220                        if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) &&
 221                            ((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4)))
 222                                printk(" cerr_i idx doesn't match eepc\n");
 223                        else {
 224                                res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
 225                                                 (cerr_i & CP0_CERRI_DATA) != 0);
 226                                if (!(res & cerr_i))
 227                                        printk("...didn't see indicated icache problem\n");
 228                        }
 229                }
 230        }
 231        if (errctl & CP0_ERRCTL_DCACHE) {
 232                printk(" c0_cerr_d   ==   %08x", cerr_d);
 233                breakout_cerrd(cerr_d);
 234                if (CP0_CERRD_DPA_VALID(cerr_d)) {
 235                        printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
 236                        if (!CP0_CERRD_IDX_VALID(cerr_d)) {
 237                                res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
 238                                                 (cerr_d & CP0_CERRD_DATA) != 0);
 239                                if (!(res & cerr_d))
 240                                        printk("...didn't see indicated dcache problem\n");
 241                        } else {
 242                                if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
 243                                        printk(" cerr_d idx doesn't match cerr_dpa\n");
 244                                else {
 245                                        res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
 246                                                         (cerr_d & CP0_CERRD_DATA) != 0);
 247                                        if (!(res & cerr_d))
 248                                                printk("...didn't see indicated problem\n");
 249                                }
 250                        }
 251                }
 252        }
 253
 254        check_bus_watcher();
 255
 256        /*
 257         * Calling panic() when a fatal cache error occurs scrambles the
 258         * state of the system (and the cache), making it difficult to
 259         * investigate after the fact.  However, if you just stall the CPU,
 260         * the other CPU may keep on running, which is typically very
 261         * undesirable.
 262         */
 263#ifdef CONFIG_SB1_CERR_STALL
 264        while (1)
 265                ;
 266#else
 267        panic("unhandled cache error");
 268#endif
 269}
 270
 271
 272/* Parity lookup table. */
 273static const uint8_t parity[256] = {
 274        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 275        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 276        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 277        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 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        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 283        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 284        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 285        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 286        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
 287        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 288        1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
 289        0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
 290};
 291
 292/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
 293static const uint64_t mask_72_64[8] = {
 294        0x0738C808099264FFULL,
 295        0x38C808099264FF07ULL,
 296        0xC808099264FF0738ULL,
 297        0x08099264FF0738C8ULL,
 298        0x099264FF0738C808ULL,
 299        0x9264FF0738C80809ULL,
 300        0x64FF0738C8080992ULL,
 301        0xFF0738C808099264ULL
 302};
 303
 304/* Calculate the parity on a range of bits */
 305static char range_parity(uint64_t dword, int max, int min)
 306{
 307        char parity = 0;
 308        int i;
 309        dword >>= min;
 310        for (i=max-min; i>=0; i--) {
 311                if (dword & 0x1)
 312                        parity = !parity;
 313                dword >>= 1;
 314        }
 315        return parity;
 316}
 317
 318/* Calculate the 4-bit even byte-parity for an instruction */
 319static unsigned char inst_parity(uint32_t word)
 320{
 321        int i, j;
 322        char parity = 0;
 323        for (j=0; j<4; j++) {
 324                char byte_parity = 0;
 325                for (i=0; i<8; i++) {
 326                        if (word & 0x80000000)
 327                                byte_parity = !byte_parity;
 328                        word <<= 1;
 329                }
 330                parity <<= 1;
 331                parity |= byte_parity;
 332        }
 333        return parity;
 334}
 335
 336static uint32_t extract_ic(unsigned short addr, int data)
 337{
 338        unsigned short way;
 339        int valid;
 340        uint32_t taghi, taglolo, taglohi;
 341        unsigned long long taglo, va;
 342        uint64_t tlo_tmp;
 343        uint8_t lru;
 344        int res = 0;
 345
 346        printk("Icache index 0x%04x  ", addr);
 347        for (way = 0; way < 4; way++) {
 348                /* Index-load-tag-I */
 349                __asm__ __volatile__ (
 350                "       .set    push            \n\t"
 351                "       .set    noreorder       \n\t"
 352                "       .set    mips64          \n\t"
 353                "       .set    noat            \n\t"
 354                "       cache   4, 0(%3)        \n\t"
 355                "       mfc0    %0, $29         \n\t"
 356                "       dmfc0   $1, $28         \n\t"
 357                "       dsrl32  %1, $1, 0       \n\t"
 358                "       sll     %2, $1, 0       \n\t"
 359                "       .set    pop"
 360                : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
 361                : "r" ((way << 13) | addr));
 362
 363                taglo = ((unsigned long long)taglohi << 32) | taglolo;
 364                if (way == 0) {
 365                        lru = (taghi >> 14) & 0xff;
 366                        printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
 367                                    ((addr >> 5) & 0x3), /* bank */
 368                                    ((addr >> 7) & 0x3f), /* index */
 369                                    (lru & 0x3),
 370                                    ((lru >> 2) & 0x3),
 371                                    ((lru >> 4) & 0x3),
 372                                    ((lru >> 6) & 0x3));
 373                }
 374                va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
 375                if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
 376                        va |= 0x3FFFF00000000000ULL;
 377                valid = ((taghi >> 29) & 1);
 378                if (valid) {
 379                        tlo_tmp = taglo & 0xfff3ff;
 380                        if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
 381                                printk("   ** bad parity in VTag0/G/ASID\n");
 382                                res |= CP0_CERRI_TAG_PARITY;
 383                        }
 384                        if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
 385                                printk("   ** bad parity in R/VTag1\n");
 386                                res |= CP0_CERRI_TAG_PARITY;
 387                        }
 388                }
 389                if (valid ^ ((taghi >> 27) & 1)) {
 390                        printk("   ** bad parity for valid bit\n");
 391                        res |= CP0_CERRI_TAG_PARITY;
 392                }
 393                printk(" %d  [VA %016llx]  [Vld? %d]  raw tags: %08X-%016llX\n",
 394                            way, va, valid, taghi, taglo);
 395
 396                if (data) {
 397                        uint32_t datahi, insta, instb;
 398                        uint8_t predecode;
 399                        int offset;
 400
 401                        /* (hit all banks and ways) */
 402                        for (offset = 0; offset < 4; offset++) {
 403                                /* Index-load-data-I */
 404                                __asm__ __volatile__ (
 405                                "       .set    push\n\t"
 406                                "       .set    noreorder\n\t"
 407                                "       .set    mips64\n\t"
 408                                "       .set    noat\n\t"
 409                                "       cache   6, 0(%3)  \n\t"
 410                                "       mfc0    %0, $29, 1\n\t"
 411                                "       dmfc0  $1, $28, 1\n\t"
 412                                "       dsrl32 %1, $1, 0 \n\t"
 413                                "       sll    %2, $1, 0 \n\t"
 414                                "       .set    pop         \n"
 415                                : "=r" (datahi), "=r" (insta), "=r" (instb)
 416                                : "r" ((way << 13) | addr | (offset << 3)));
 417                                predecode = (datahi >> 8) & 0xff;
 418                                if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
 419                                        printk("   ** bad parity in predecode\n");
 420                                        res |= CP0_CERRI_DATA_PARITY;
 421                                }
 422                                /* XXXKW should/could check predecode bits themselves */
 423                                if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
 424                                        printk("   ** bad parity in instruction a\n");
 425                                        res |= CP0_CERRI_DATA_PARITY;
 426                                }
 427                                if ((datahi & 0xf) ^ inst_parity(instb)) {
 428                                        printk("   ** bad parity in instruction b\n");
 429                                        res |= CP0_CERRI_DATA_PARITY;
 430                                }
 431                                printk("  %05X-%08X%08X", datahi, insta, instb);
 432                        }
 433                        printk("\n");
 434                }
 435        }
 436        return res;
 437}
 438
 439/* Compute the ECC for a data doubleword */
 440static uint8_t dc_ecc(uint64_t dword)
 441{
 442        uint64_t t;
 443        uint32_t w;
 444        uint8_t  p;
 445        int      i;
 446
 447        p = 0;
 448        for (i = 7; i >= 0; i--)
 449        {
 450                p <<= 1;
 451                t = dword & mask_72_64[i];
 452                w = (uint32_t)(t >> 32);
 453                p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
 454                      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
 455                w = (uint32_t)(t & 0xFFFFFFFF);
 456                p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
 457                      ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
 458        }
 459        return p;
 460}
 461
 462struct dc_state {
 463        unsigned char val;
 464        char *name;
 465};
 466
 467static struct dc_state dc_states[] = {
 468        { 0x00, "INVALID" },
 469        { 0x0f, "COH-SHD" },
 470        { 0x13, "NCO-E-C" },
 471        { 0x19, "NCO-E-D" },
 472        { 0x16, "COH-E-C" },
 473        { 0x1c, "COH-E-D" },
 474        { 0xff, "*ERROR*" }
 475};
 476
 477#define DC_TAG_VALID(state) \
 478    (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
 479     ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
 480
 481static char *dc_state_str(unsigned char state)
 482{
 483        struct dc_state *dsc = dc_states;
 484        while (dsc->val != 0xff) {
 485                if (dsc->val == state)
 486                        break;
 487                dsc++;
 488        }
 489        return dsc->name;
 490}
 491
 492static uint32_t extract_dc(unsigned short addr, int data)
 493{
 494        int valid, way;
 495        unsigned char state;
 496        uint32_t taghi, taglolo, taglohi;
 497        unsigned long long taglo, pa;
 498        uint8_t ecc, lru;
 499        int res = 0;
 500
 501        printk("Dcache index 0x%04x  ", addr);
 502        for (way = 0; way < 4; way++) {
 503                __asm__ __volatile__ (
 504                "       .set    push\n\t"
 505                "       .set    noreorder\n\t"
 506                "       .set    mips64\n\t"
 507                "       .set    noat\n\t"
 508                "       cache   5, 0(%3)\n\t"   /* Index-load-tag-D */
 509                "       mfc0    %0, $29, 2\n\t"
 510                "       dmfc0   $1, $28, 2\n\t"
 511                "       dsrl32  %1, $1, 0\n\t"
 512                "       sll     %2, $1, 0\n\t"
 513                "       .set    pop"
 514                : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
 515                : "r" ((way << 13) | addr));
 516
 517                taglo = ((unsigned long long)taglohi << 32) | taglolo;
 518                pa = (taglo & 0xFFFFFFE000ULL) | addr;
 519                if (way == 0) {
 520                        lru = (taghi >> 14) & 0xff;
 521                        printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
 522                                    ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
 523                                    ((addr >> 6) & 0x3f), /* index */
 524                                    (lru & 0x3),
 525                                    ((lru >> 2) & 0x3),
 526                                    ((lru >> 4) & 0x3),
 527                                    ((lru >> 6) & 0x3));
 528                }
 529                state = (taghi >> 25) & 0x1f;
 530                valid = DC_TAG_VALID(state);
 531                printk(" %d  [PA %010llx]  [state %s (%02x)]  raw tags: %08X-%016llX\n",
 532                            way, pa, dc_state_str(state), state, taghi, taglo);
 533                if (valid) {
 534                        if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
 535                                printk("   ** bad parity in PTag1\n");
 536                                res |= CP0_CERRD_TAG_ADDRESS;
 537                        }
 538                        if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
 539                                printk("   ** bad parity in PTag0\n");
 540                                res |= CP0_CERRD_TAG_ADDRESS;
 541                        }
 542                } else {
 543                        res |= CP0_CERRD_TAG_STATE;
 544                }
 545
 546                if (data) {
 547                        uint32_t datalohi, datalolo, datahi;
 548                        unsigned long long datalo;
 549                        int offset;
 550                        char bad_ecc = 0;
 551
 552                        for (offset = 0; offset < 4; offset++) {
 553                                /* Index-load-data-D */
 554                                __asm__ __volatile__ (
 555                                "       .set    push\n\t"
 556                                "       .set    noreorder\n\t"
 557                                "       .set    mips64\n\t"
 558                                "       .set    noat\n\t"
 559                                "       cache   7, 0(%3)\n\t" /* Index-load-data-D */
 560                                "       mfc0    %0, $29, 3\n\t"
 561                                "       dmfc0   $1, $28, 3\n\t"
 562                                "       dsrl32  %1, $1, 0 \n\t"
 563                                "       sll     %2, $1, 0 \n\t"
 564                                "       .set    pop"
 565                                : "=r" (datahi), "=r" (datalohi), "=r" (datalolo)
 566                                : "r" ((way << 13) | addr | (offset << 3)));
 567                                datalo = ((unsigned long long)datalohi << 32) | datalolo;
 568                                ecc = dc_ecc(datalo);
 569                                if (ecc != datahi) {
 570                                        int bits;
 571                                        bad_ecc |= 1 << (3-offset);
 572                                        ecc ^= datahi;
 573                                        bits = hweight8(ecc);
 574                                        res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
 575                                }
 576                                printk("  %02X-%016llX", datahi, datalo);
 577                        }
 578                        printk("\n");
 579                        if (bad_ecc)
 580                                printk("  dwords w/ bad ECC: %d %d %d %d\n",
 581                                       !!(bad_ecc & 8), !!(bad_ecc & 4),
 582                                       !!(bad_ecc & 2), !!(bad_ecc & 1));
 583                }
 584        }
 585        return res;
 586}
 587