cache_error.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 2001 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. /* SB1 definitions */
  21. /* XXX should come from config1 XXX */
  22. #define SB1_CACHE_INDEX_MASK   0x1fe0
  23. #define CP0_ERRCTL_RECOVERABLE (1 << 31)
  24. #define CP0_ERRCTL_DCACHE      (1 << 30)
  25. #define CP0_ERRCTL_ICACHE      (1 << 29)
  26. #define CP0_ERRCTL_MULTIBUS    (1 << 23)
  27. #define CP0_ERRCTL_MC_TLB      (1 << 15)
  28. #define CP0_ERRCTL_MC_TIMEOUT  (1 << 14)
  29. #define CP0_CERRI_TAG_PARITY   (1 << 29)
  30. #define CP0_CERRI_DATA_PARITY  (1 << 28)
  31. #define CP0_CERRI_EXTERNAL     (1 << 26)
  32. #define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL))
  33. #define CP0_CERRI_DATA         (CP0_CERRI_DATA_PARITY)
  34. #define CP0_CERRD_MULTIPLE     (1 << 31)
  35. #define CP0_CERRD_TAG_STATE    (1 << 30)
  36. #define CP0_CERRD_TAG_ADDRESS  (1 << 29)
  37. #define CP0_CERRD_DATA_SBE     (1 << 28)
  38. #define CP0_CERRD_DATA_DBE     (1 << 27)
  39. #define CP0_CERRD_EXTERNAL     (1 << 26)
  40. #define CP0_CERRD_LOAD         (1 << 25)
  41. #define CP0_CERRD_STORE        (1 << 24)
  42. #define CP0_CERRD_FILLWB       (1 << 23)
  43. #define CP0_CERRD_COHERENCY    (1 << 22)
  44. #define CP0_CERRD_DUPTAG       (1 << 21)
  45. #define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL))
  46. #define CP0_CERRD_IDX_VALID(c) 
  47.    (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0)
  48. #define CP0_CERRD_CAUSES 
  49.    (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG)
  50. #define CP0_CERRD_TYPES 
  51.    (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL)
  52. #define CP0_CERRD_DATA         (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
  53. static uint32_t extract_ic(unsigned short addr, int data);
  54. static uint32_t extract_dc(unsigned short addr, int data);
  55. spinlock_t in_cacheerr = SPIN_LOCK_UNLOCKED;
  56. static inline void breakout_errctl(unsigned int val)
  57. {
  58. if (val & CP0_ERRCTL_RECOVERABLE)
  59. printk(" recoverable");
  60. if (val & CP0_ERRCTL_DCACHE)
  61. printk(" dcache");
  62. if (val & CP0_ERRCTL_ICACHE)
  63. printk(" icache");
  64. if (val & CP0_ERRCTL_MULTIBUS)
  65. printk(" multiple-buserr");
  66. printk("n");
  67. }
  68. static inline void breakout_cerri(unsigned int val)
  69. {
  70. if (val & CP0_CERRI_TAG_PARITY)
  71. printk(" tag-parity");
  72. if (val & CP0_CERRI_DATA_PARITY)
  73. printk(" data-parity");
  74. if (val & CP0_CERRI_EXTERNAL)
  75. printk(" external");
  76. printk("n");
  77. }
  78. static inline void breakout_cerrd(unsigned int val)
  79. {
  80. switch (val & CP0_CERRD_CAUSES) {
  81. case CP0_CERRD_LOAD:
  82. printk(" load,");
  83. break;
  84. case CP0_CERRD_STORE:
  85. printk(" store,");
  86. break;
  87. case CP0_CERRD_FILLWB:
  88. printk(" fill/wb,");
  89. break;
  90. case CP0_CERRD_COHERENCY:
  91. printk(" coherency,");
  92. break;
  93. case CP0_CERRD_DUPTAG:
  94. printk(" duptags,");
  95. break;
  96. default:
  97. printk(" NO CAUSE,");
  98. break;
  99. }
  100. if (!(val & CP0_CERRD_TYPES))
  101. printk(" NO TYPE");
  102. else {
  103. if (val & CP0_CERRD_MULTIPLE)
  104. printk(" multi-err");
  105. if (val & CP0_CERRD_TAG_STATE)
  106. printk(" tag-state");
  107. if (val & CP0_CERRD_TAG_ADDRESS)
  108. printk(" tag-address");
  109. if (val & CP0_CERRD_DATA_SBE)
  110. printk(" data-SBE");
  111. if (val & CP0_CERRD_DATA_DBE)
  112. printk(" data-DBE");
  113. if (val & CP0_CERRD_EXTERNAL)
  114. printk(" external");
  115. }
  116. printk("n");
  117. }
  118. asmlinkage void sb1_cache_error(void)
  119. {
  120. uint64_t cerr_dpa;
  121. uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
  122. /* Prevent re-entrance in the SMP case */
  123. spin_lock(&in_cacheerr);
  124. printk("Cache error exception on CPU %x:n",
  125.        (read_32bit_cp0_register(CP0_PRID) >> 25) & 0x7);
  126. __asm__ __volatile__ (
  127. ".set pushnt"
  128. ".set mips64nt"
  129. ".set noatnt"
  130. "mfc0   %0, $26, 0nt"
  131. "mfc0   %1, $27, 0nt"
  132. "mfc0   %2, $27, 1nt"
  133. "dmfc0  $1, $27, 3nt"
  134. "dsrl32 %3, $1, 0 nt"
  135. "sll    %4, $1, 0 nt"
  136. "mfc0   %5, $30nt"
  137. ".set popn"
  138. : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
  139.   "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
  140. cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
  141. printk(" cp0_errorepc ==   %08xn", eepc);
  142. printk(" cp0_errctl   ==   %08x", errctl);
  143. breakout_errctl(errctl);
  144. if (errctl & CP0_ERRCTL_ICACHE) {
  145. printk(" cp0_cerr_i   ==   %08x", cerr_i);
  146. breakout_cerri(cerr_i);
  147. if (CP0_CERRI_IDX_VALID(cerr_i)) {
  148. if ((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK))
  149. printk(" cerr_i idx doesn't match eepcn");
  150. else {
  151. res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
  152.  (cerr_i & CP0_CERRI_DATA) != 0);
  153. if (!(res & cerr_i))
  154. printk("...didn't see indicated icache problemn");
  155. }
  156. }
  157. }
  158. if (errctl & CP0_ERRCTL_DCACHE) {
  159. printk(" cp0_cerr_d   ==   %08x", cerr_d);
  160. breakout_cerrd(cerr_d);
  161. if (CP0_CERRD_DPA_VALID(cerr_d)) {
  162. printk(" cp0_cerr_dpa == %010llxn", cerr_dpa);
  163. if (!CP0_CERRD_IDX_VALID(cerr_d)) {
  164. res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
  165.  (cerr_d & CP0_CERRD_DATA) != 0);
  166. if (!(res & cerr_d))
  167. printk("...didn't see indicated dcache problemn");
  168. } else {
  169. if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
  170. printk(" cerr_d idx doesn't match cerr_dpan");
  171. else {
  172. res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
  173.  (cerr_d & CP0_CERRD_DATA) != 0);
  174. if (!(res & cerr_d))
  175. printk("...didn't see indicated problemn");
  176. }
  177. }
  178. }
  179. }
  180. while (1);
  181. /*
  182.  * This tends to make things get really ugly; let's just stall instead.
  183.  *    panic("Can't handle the cache error!");
  184.  */
  185. }
  186. /* Parity lookup table. */
  187. static const uint8_t parity[256] = {
  188. 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  189. 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  190. 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  191. 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  192. 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
  193. 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  194. 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
  195. 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
  196. };
  197. /* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
  198. static const uint64_t mask_72_64[8] = {
  199. 0x0738C808099264FFL,
  200. 0x38C808099264FF07L,
  201. 0xC808099264FF0738L,
  202. 0x08099264FF0738C8L,
  203. 0x099264FF0738C808L,
  204. 0x9264FF0738C80809L,
  205. 0x64FF0738C8080992L,
  206. 0xFF0738C808099264L
  207. };
  208. /* Calculate the parity on a range of bits */
  209. static char range_parity(uint64_t dword, int max, int min)
  210. {
  211. char parity = 0;
  212. int i;
  213. dword >>= min;
  214. for (i=max-min; i>=0; i--) {
  215. if (dword & 0x1)
  216. parity = !parity;
  217. dword >>= 1;
  218. }
  219. return parity;
  220. }
  221. /* Calculate the 4-bit even byte-parity for an instruction */
  222. static unsigned char inst_parity(uint32_t word)
  223. {
  224. int i, j;
  225. char parity = 0;
  226. for (j=0; j<4; j++) {
  227. char byte_parity = 0;
  228. for (i=0; i<8; i++) {
  229. if (word & 0x80000000)
  230. byte_parity = !byte_parity;
  231. word <<= 1;
  232. }
  233. parity <<= 1;
  234. parity |= byte_parity;
  235. }
  236. return parity;
  237. }
  238. static uint32_t extract_ic(unsigned short addr, int data)
  239. {
  240. unsigned short way;
  241. int valid;
  242. uint64_t taglo, va, tlo_tmp;
  243. uint32_t taghi, taglolo, taglohi;
  244. uint8_t lru;
  245. int res = 0;
  246. printk("Icache index 0x%04x  ", addr);
  247. for (way = 0; way < 4; way++) {
  248. /* Index-load-tag-I */
  249. __asm__ __volatile__ (
  250. ".set push        nt"
  251. ".set noreorder   nt"
  252. ".set mips64      nt"
  253. ".set noat        nt"
  254. "cache  4, 0(%3)  nt"
  255. "mfc0   %0, $29, 0nt"
  256. "dmfc0  $1, $28, 0nt"
  257. "dsrl32 %1, $1, 0 nt"
  258. "sll    %2, $1, 0 nt"
  259. ".set pop         n"
  260. : "=r" (taghi), "=r" (taglohi),
  261.   "=r" (taglolo)
  262. : "r" ((way << 13) | addr));
  263. taglo = ((unsigned long long)taglohi << 32) | taglolo;
  264. if (way == 0) {
  265. lru = (taghi >> 14) & 0xff;
  266. printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRUn",
  267.        ((addr >> 5) & 0x3), /* bank */
  268.        ((addr >> 7) & 0x3f), /* index */
  269.        (lru & 0x3),
  270.        ((lru >> 2) & 0x3),
  271.        ((lru >> 4) & 0x3),
  272.        ((lru >> 6) & 0x3));
  273. }
  274. va = (taglo & 0xC0000FFFFFFFE000) | addr;
  275. if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
  276. va |= 0x3FFFF00000000000;
  277. valid = ((taghi >> 29) & 1);
  278. if (valid) {
  279. tlo_tmp = taglo & 0xfff3ff;
  280. if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
  281. printk("   ** bad parity in VTag0/G/ASIDn");
  282. res |= CP0_CERRI_TAG_PARITY;
  283. }
  284. if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
  285. printk("   ** bad parity in R/VTag1n");
  286. res |= CP0_CERRI_TAG_PARITY;
  287. }
  288. }
  289. if (valid ^ ((taghi >> 27) & 1)) {
  290. printk("   ** bad parity for valid bitn");
  291. res |= CP0_CERRI_TAG_PARITY;
  292. }
  293. printk(" %d  [VA %016llx]  [Vld? %d]  raw tags: %08X-%016llXn",
  294.        way, va, valid, taghi, taglo);
  295. if (data) {
  296. uint32_t datahi, insta, instb;
  297. uint8_t predecode;
  298. int offset;
  299. /* (hit all banks and ways) */
  300. for (offset = 0; offset < 4; offset++) {
  301. /* Index-load-data-I */
  302. __asm__ __volatile__ (
  303. ".set push        nt"
  304. ".set noreorder   nt"
  305. ".set mips64      nt"
  306. ".set noat        nt"
  307. "cache  6, 0(%3)  nt"
  308. "mfc0   %0, $29, 1nt"
  309. "dmfc0  $1, $28, 1nt"
  310. "dsrl32 %1, $1, 0 nt"
  311. "sll    %2, $1, 0 nt"
  312. ".set pop         n"
  313. : "=r" (datahi), "=r" (insta),
  314.   "=r" (instb)
  315. : "r" ((way << 13) | addr | (offset << 3)));
  316. predecode = (datahi >> 8) & 0xff;
  317. if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
  318. printk("   ** bad parity in predecoden");
  319. res |= CP0_CERRI_DATA_PARITY;
  320. }
  321. /* XXXKW should/could check predecode bits themselves */
  322. if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
  323. printk("   ** bad parity in instruction an");
  324. res |= CP0_CERRI_DATA_PARITY;
  325. }
  326. if ((datahi & 0xf) ^ inst_parity(instb)) {
  327. printk("   ** bad parity in instruction bn");
  328. res |= CP0_CERRI_DATA_PARITY;
  329. }
  330. printk("  %05X-%08X%08X", datahi, insta, instb);
  331. }
  332. printk("n");
  333. }
  334. }
  335. return res;
  336. }
  337. /* Compute the ECC for a data doubleword */
  338. static uint8_t dc_ecc(uint64_t dword)
  339. {
  340. uint64_t t;
  341. uint32_t w;
  342. uint8_t  p;
  343. int      i;
  344. p = 0;
  345. for (i = 7; i >= 0; i--)
  346. {
  347. p <<= 1;
  348. t = dword & mask_72_64[i];
  349. w = (uint32_t)(t >> 32);
  350. p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
  351.       ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
  352. w = (uint32_t)(t & 0xFFFFFFFF);
  353. p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
  354.       ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
  355. }
  356. return p;
  357. }
  358. struct dc_state {
  359. unsigned char val;
  360. char *name;
  361. };
  362. static struct dc_state dc_states[] = {
  363. { 0x00, "INVALID" },
  364. { 0x0f, "COH-SHD" },
  365. { 0x13, "NCO-E-C" },
  366. { 0x19, "NCO-E-D" },
  367. { 0x16, "COH-E-C" },
  368. { 0x1c, "COH-E-D" },
  369. { 0xff, "*ERROR*" }
  370. };
  371. #define DC_TAG_VALID(state) 
  372.     (((state) == 0xf) || ((state) == 0x13) || ((state) == 0x19) || ((state == 0x16)) || ((state) == 0x1c))
  373. static char *dc_state_str(unsigned char state)
  374. {
  375. struct dc_state *dsc = dc_states;
  376. while (dsc->val != 0xff) {
  377. if (dsc->val == state)
  378. break;
  379. dsc++;
  380. }
  381. return dsc->name;
  382. }
  383. static uint32_t extract_dc(unsigned short addr, int data)
  384. {
  385. int valid, way;
  386. unsigned char state;
  387. uint64_t taglo, pa;
  388. uint32_t taghi, taglolo, taglohi;
  389. uint8_t ecc, lru;
  390. int res = 0;
  391. printk("Dcache index 0x%04x  ", addr);
  392. for (way = 0; way < 4; way++) {
  393. /* Index-load-tag-D */
  394. __asm__ __volatile__ (
  395. ".set push        nt"
  396. ".set noreorder   nt"
  397. ".set mips64      nt"
  398. ".set noat        nt"
  399. "cache  5, 0(%3)  nt"
  400. "mfc0   %0, $29, 2nt"
  401. "dmfc0  $1, $28, 2nt"
  402. "dsrl32 %1, $1, 0 nt"
  403. "sll    %2, $1, 0 nt"
  404. ".set pop         n"
  405. : "=r" (taghi), "=r" (taglohi),
  406.   "=r" (taglolo)
  407. : "r" ((way << 13) | addr));
  408. taglo = ((unsigned long long)taglohi << 32) | taglolo;
  409. pa = (taglo & 0xFFFFFFE000) | addr;
  410. if (way == 0) {
  411. lru = (taghi >> 14) & 0xff;
  412. printk("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRUn",
  413.        ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
  414.        ((addr >> 6) & 0x3f), /* index */
  415.        (lru & 0x3),
  416.        ((lru >> 2) & 0x3),
  417.        ((lru >> 4) & 0x3),
  418.        ((lru >> 6) & 0x3));
  419. }
  420. state = (taghi >> 25) & 0x1f;
  421. valid = DC_TAG_VALID(state);
  422. printk(" %d  [PA %010llx]  [state %s (%02x)]  raw tags: %08X-%016llXn",
  423.        way, pa, dc_state_str(state), state, taghi, taglo);
  424. if (valid) {
  425. if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
  426. printk("   ** bad parity in PTag1n");
  427. res |= CP0_CERRD_TAG_ADDRESS;
  428. }
  429. if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
  430. printk("   ** bad parity in PTag0n");
  431. res |= CP0_CERRD_TAG_ADDRESS;
  432. }
  433. } else {
  434. res |= CP0_CERRD_TAG_STATE;
  435. }
  436. if (data) {
  437. uint64_t datalo;
  438. uint32_t datalohi, datalolo, datahi;
  439. int offset;
  440. for (offset = 0; offset < 4; offset++) {
  441. /* Index-load-data-D */
  442. __asm__ __volatile__ (
  443. ".set push        nt"
  444. ".set noreorder   nt"
  445. ".set mips64      nt"
  446. ".set noat        nt"
  447. "cache  7, 0(%3)  nt"
  448. "mfc0   %0, $29, 3nt"
  449. "dmfc0  $1, $28, 3nt"
  450. "dsrl32 %1, $1, 0 nt"
  451. "sll    %2, $1, 0 nt"
  452. ".set pop         n"
  453. : "=r" (datahi), "=r" (datalohi),
  454. "=r" (datalolo)
  455. : "r" ((way << 13) | addr | (offset << 3)));
  456. datalo = ((unsigned long long)datalohi << 32) | datalolo;
  457. ecc = dc_ecc(datalo);
  458. if (ecc != datahi) {
  459. int bits = 0;
  460. printk("  ** bad ECC (%02x %02x) ->",
  461.        datahi, ecc);
  462. ecc ^= datahi;
  463. while (ecc) {
  464. if (ecc & 1) bits++;
  465. ecc >>= 1;
  466. }
  467. res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
  468. }
  469. printk("  %02X-%016llX", datahi, datalo);
  470. }
  471. printk("n");
  472. }
  473. }
  474. return res;
  475. }