~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/mm/cerr-sb1.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 74 static uint32_t extract_ic(unsigned short addr, int data);
 75 static uint32_t extract_dc(unsigned short addr, int data);
 76 
 77 static 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 
 90 static 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 
101 static 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 
144 static 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
175 extern void check_bus_watcher(void);
176 #endif
177 
178 asmlinkage 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. */
269 static 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] */
289 static 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 */
301 static 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 */
315 static 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 
332 static 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 */
436 static 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 
458 struct dc_state {
459         unsigned char val;
460         char *name;
461 };
462 
463 static 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 
477 static 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 
488 static 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp