cplbmgr.S 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*This file is subject to the terms and conditions of the GNU General Public
  2. * License.
  3. *
  4. * Blackfin BF533/2.6 support : LG Soft India
  5. * Modification: Dec 07 2004
  6. * 1. Correction in icheck_lock. Valid lock entries were
  7. * geting victimized, for instruction cplb replacement.
  8. * 2. Setup loop's are modified as now toolchain support's P Indexed
  9. * addressing
  10. * :LG Soft India
  11. *
  12. */
  13. /* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
  14. * is_data_miss==2 => Mark as Dirty, write to the clean data page
  15. * is_data_miss==1 => Replace a data CPLB.
  16. * is_data_miss==0 => Replace an instruction CPLB.
  17. *
  18. * Returns:
  19. * CPLB_RELOADED => Successfully updated CPLB table.
  20. * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted.This indicates
  21. * that the CPLBs in the configuration tablei are badly
  22. * configured, as this should never occur.
  23. * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the exception,
  24. * is not covered by any of the CPLBs in the configuration
  25. * table. The application isi presumably misbehaving.
  26. * CPLB_PROT_VIOL => The address being accessed, that triggered thei exception,
  27. * was not a first-write to a clean Write Back Data page,
  28. * and so presumably is a genuine violation of the page's
  29. * protection attributes. The application is misbehaving.
  30. */
  31. #define ASSEMBLY
  32. #include <asm-blackfin/linkage.h>
  33. #include <asm-blackfin/blackfin.h>
  34. #include <asm-blackfin/cplbtab.h>
  35. #include <asm-blackfin/cplb.h>
  36. .text
  37. .align 2;
  38. ENTRY(_cplb_mgr)
  39. [--SP]=( R7:0,P5:0 );
  40. CC = R0 == 2;
  41. IF CC JUMP dcplb_write;
  42. CC = R0 == 0;
  43. IF !CC JUMP dcplb_miss_compare;
  44. /* ICPLB Miss Exception. We need to choose one of the
  45. * currently-installed CPLBs, and replace it with one
  46. * from the configuration table.
  47. */
  48. P4.L = (ICPLB_FAULT_ADDR & 0xFFFF);
  49. P4.H = (ICPLB_FAULT_ADDR >> 16);
  50. P1 = 16;
  51. P5.L = page_size_table;
  52. P5.H = page_size_table;
  53. P0.L = (ICPLB_DATA0 & 0xFFFF);
  54. P0.H = (ICPLB_DATA0 >> 16);
  55. R4 = [P4]; /* Get faulting address*/
  56. R6 = 64; /* Advance past the fault address, which*/
  57. R6 = R6 + R4; /* we'll use if we find a match*/
  58. R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/
  59. R5 = 0;
  60. isearch:
  61. R1 = [P0-0x100]; /* Address for this CPLB */
  62. R0 = [P0++]; /* Info for this CPLB*/
  63. CC = BITTST(R0,0); /* Is the CPLB valid?*/
  64. IF !CC JUMP nomatch; /* Skip it, if not.*/
  65. CC = R4 < R1(IU); /* If fault address less than page start*/
  66. IF CC JUMP nomatch; /* then skip this one.*/
  67. R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/
  68. P1 = R2;
  69. P1 = P5 + (P1<<2); /* index into page-size table*/
  70. R2 = [P1]; /* Get the page size*/
  71. R1 = R1 + R2; /* and add to page start, to get page end*/
  72. CC = R4 < R1(IU); /* and see whether fault addr is in page.*/
  73. IF !CC R4 = R6; /* If so, advance the address and finish loop.*/
  74. IF !CC JUMP isearch_done;
  75. nomatch:
  76. /* Go around again*/
  77. R5 += 1;
  78. CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/
  79. IF !CC JUMP isearch;
  80. isearch_done:
  81. I0 = R4; /* Fault address we'll search for*/
  82. /* set up pointers */
  83. P0.L = (ICPLB_DATA0 & 0xFFFF);
  84. P0.H = (ICPLB_DATA0 >> 16);
  85. /* The replacement procedure for ICPLBs */
  86. P4.L = (IMEM_CONTROL & 0xFFFF);
  87. P4.H = (IMEM_CONTROL >> 16);
  88. /* disable cplbs */
  89. R5 = [P4]; /* Control Register*/
  90. BITCLR(R5,ENICPLB_P);
  91. CLI R1;
  92. SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
  93. .align 8;
  94. [P4] = R5;
  95. SSYNC;
  96. STI R1;
  97. R1 = -1; /* end point comparison */
  98. R3 = 16; /* counter */
  99. /* Search through CPLBs for first non-locked entry */
  100. /* Overwrite it by moving everyone else up by 1 */
  101. icheck_lock:
  102. R0 = [P0++];
  103. R3 = R3 + R1;
  104. CC = R3 == R1;
  105. IF CC JUMP all_locked;
  106. CC = BITTST(R0, 0); /* an invalid entry is good */
  107. IF !CC JUMP ifound_victim;
  108. CC = BITTST(R0,1); /* but a locked entry isn't */
  109. IF CC JUMP icheck_lock;
  110. ifound_victim:
  111. #ifdef CONFIG_CPLB_INFO
  112. R7 = [P0 - 0x104];
  113. P2.L = ipdt_table;
  114. P2.H = ipdt_table;
  115. P3.L = ipdt_swapcount_table;
  116. P3.H = ipdt_swapcount_table;
  117. P3 += -4;
  118. icount:
  119. R2 = [P2]; /* address from config table */
  120. P2 += 8;
  121. P3 += 8;
  122. CC = R2==-1;
  123. IF CC JUMP icount_done;
  124. CC = R7==R2;
  125. IF !CC JUMP icount;
  126. R7 = [P3];
  127. R7 += 1;
  128. [P3] = R7;
  129. CSYNC;
  130. icount_done:
  131. #endif
  132. LC0=R3;
  133. LSETUP(is_move,ie_move) LC0;
  134. is_move:
  135. R0 = [P0];
  136. [P0 - 4] = R0;
  137. R0 = [P0 - 0x100];
  138. [P0-0x104] = R0;
  139. ie_move:P0+=4;
  140. /* We've made space in the ICPLB table, so that ICPLB15
  141. * is now free to be overwritten. Next, we have to determine
  142. * which CPLB we need to install, from the configuration
  143. * table. This is a matter of getting the start-of-page
  144. * addresses and page-lengths from the config table, and
  145. * determining whether the fault address falls within that
  146. * range.
  147. */
  148. P2.L = ipdt_table;
  149. P2.H = ipdt_table;
  150. #ifdef CONFIG_CPLB_INFO
  151. P3.L = ipdt_swapcount_table;
  152. P3.H = ipdt_swapcount_table;
  153. P3 += -8;
  154. #endif
  155. P0.L = page_size_table;
  156. P0.H = page_size_table;
  157. /* Retrieve our fault address (which may have been advanced
  158. * because the faulting instruction crossed a page boundary).
  159. */
  160. R0 = I0;
  161. /* An extraction pattern, to get the page-size bits from
  162. * the CPLB data entry. Bits 16-17, so two bits at posn 16.
  163. */
  164. R1 = ((16<<8)|2);
  165. inext: R4 = [P2++]; /* address from config table */
  166. R2 = [P2++]; /* data from config table */
  167. #ifdef CONFIG_CPLB_INFO
  168. P3 += 8;
  169. #endif
  170. CC = R4 == -1; /* End of config table*/
  171. IF CC JUMP no_page_in_table;
  172. /* See if failed address > start address */
  173. CC = R4 <= R0(IU);
  174. IF !CC JUMP inext;
  175. /* extract page size (17:16)*/
  176. R3 = EXTRACT(R2, R1.L) (Z);
  177. /* add page size to addr to get range */
  178. P5 = R3;
  179. P5 = P0 + (P5 << 2); /* scaled, for int access*/
  180. R3 = [P5];
  181. R3 = R3 + R4;
  182. /* See if failed address < (start address + page size) */
  183. CC = R0 < R3(IU);
  184. IF !CC JUMP inext;
  185. /* We've found a CPLB in the config table that covers
  186. * the faulting address, so install this CPLB into the
  187. * last entry of the table.
  188. */
  189. P1.L = (ICPLB_DATA15 & 0xFFFF); /*ICPLB_DATA15*/
  190. P1.H = (ICPLB_DATA15 >> 16);
  191. [P1] = R2;
  192. [P1-0x100] = R4;
  193. #ifdef CONFIG_CPLB_INFO
  194. R3 = [P3];
  195. R3 += 1;
  196. [P3] = R3;
  197. #endif
  198. /* P4 points to IMEM_CONTROL, and R5 contains its old
  199. * value, after we disabled ICPLBS. Re-enable them.
  200. */
  201. BITSET(R5,ENICPLB_P);
  202. CLI R2;
  203. SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
  204. .align 8;
  205. [P4] = R5;
  206. SSYNC;
  207. STI R2;
  208. ( R7:0,P5:0 ) = [SP++];
  209. R0 = CPLB_RELOADED;
  210. RTS;
  211. /* FAILED CASES*/
  212. no_page_in_table:
  213. ( R7:0,P5:0 ) = [SP++];
  214. R0 = CPLB_NO_ADDR_MATCH;
  215. RTS;
  216. all_locked:
  217. ( R7:0,P5:0 ) = [SP++];
  218. R0 = CPLB_NO_UNLOCKED;
  219. RTS;
  220. prot_violation:
  221. ( R7:0,P5:0 ) = [SP++];
  222. R0 = CPLB_PROT_VIOL;
  223. RTS;
  224. dcplb_write:
  225. /* if a DCPLB is marked as write-back (CPLB_WT==0), and
  226. * it is clean (CPLB_DIRTY==0), then a write to the
  227. * CPLB's page triggers a protection violation. We have to
  228. * mark the CPLB as dirty, to indicate that there are
  229. * pending writes associated with the CPLB.
  230. */
  231. P4.L = (DCPLB_STATUS & 0xFFFF);
  232. P4.H = (DCPLB_STATUS >> 16);
  233. P3.L = (DCPLB_DATA0 & 0xFFFF);
  234. P3.H = (DCPLB_DATA0 >> 16);
  235. R5 = [P4];
  236. /* A protection violation can be caused by more than just writes
  237. * to a clean WB page, so we have to ensure that:
  238. * - It's a write
  239. * - to a clean WB page
  240. * - and is allowed in the mode the access occurred.
  241. */
  242. CC = BITTST(R5, 16); /* ensure it was a write*/
  243. IF !CC JUMP prot_violation;
  244. /* to check the rest, we have to retrieve the DCPLB.*/
  245. /* The low half of DCPLB_STATUS is a bit mask*/
  246. R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
  247. R3 = 30; /* so we can use this to determine the offset*/
  248. R2.L = SIGNBITS R2;
  249. R2 = R2.L (Z); /* into the DCPLB table.*/
  250. R3 = R3 - R2;
  251. P4 = R3;
  252. P3 = P3 + (P4<<2);
  253. R3 = [P3]; /* Retrieve the CPLB*/
  254. /* Now we can check whether it's a clean WB page*/
  255. CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
  256. IF CC JUMP prot_violation;
  257. CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
  258. IF CC JUMP prot_violation;
  259. /* Check whether the write is allowed in the mode that was active.*/
  260. R2 = 1<<3; /* checking write in user mode*/
  261. CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
  262. R5 = CC;
  263. R2 <<= R5; /* if was super, check write in super mode*/
  264. R2 = R3 & R2;
  265. CC = R2 == 0;
  266. IF CC JUMP prot_violation;
  267. /* It's a genuine write-to-clean-page.*/
  268. BITSET(R3, 7); /* mark as dirty*/
  269. [P3] = R3; /* and write back.*/
  270. CSYNC;
  271. ( R7:0,P5:0 ) = [SP++];
  272. R0 = CPLB_RELOADED;
  273. RTS;
  274. dcplb_miss_compare:
  275. /* Data CPLB Miss event. We need to choose a CPLB to
  276. * evict, and then locate a new CPLB to install from the
  277. * config table, that covers the faulting address.
  278. */
  279. P1.L = (DCPLB_DATA15 & 0xFFFF);
  280. P1.H = (DCPLB_DATA15 >> 16);
  281. P4.L = (DCPLB_FAULT_ADDR & 0xFFFF);
  282. P4.H = (DCPLB_FAULT_ADDR >> 16);
  283. R4 = [P4];
  284. I0 = R4;
  285. /* The replacement procedure for DCPLBs*/
  286. R6 = R1; /* Save for later*/
  287. /* Turn off CPLBs while we work.*/
  288. P4.L = (DMEM_CONTROL & 0xFFFF);
  289. P4.H = (DMEM_CONTROL >> 16);
  290. R5 = [P4];
  291. BITCLR(R5,ENDCPLB_P);
  292. CLI R0;
  293. SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
  294. .align 8;
  295. [P4] = R5;
  296. SSYNC;
  297. STI R0;
  298. /* Start looking for a CPLB to evict. Our order of preference
  299. * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
  300. * are no good.
  301. */
  302. I1.L = (DCPLB_DATA0 & 0xFFFF);
  303. I1.H = (DCPLB_DATA0 >> 16);
  304. P1 = 3;
  305. P2 = 16;
  306. I2.L = dcplb_preference;
  307. I2.H = dcplb_preference;
  308. LSETUP(sdsearch1, edsearch1) LC0 = P1;
  309. sdsearch1:
  310. R0 = [I2++]; /* Get the bits we're interested in*/
  311. P0 = I1; /* Go back to start of table*/
  312. LSETUP (sdsearch2, edsearch2) LC1 = P2;
  313. sdsearch2:
  314. R1 = [P0++]; /* Fetch each installed CPLB in turn*/
  315. R2 = R1 & R0; /* and test for interesting bits.*/
  316. CC = R2 == 0; /* If none are set, it'll do.*/
  317. IF !CC JUMP skip_stack_check;
  318. R2 = [P0 - 0x104]; /* R2 - PageStart */
  319. P3.L = page_size_table; /* retrive end address */
  320. P3.H = page_size_table; /* retrive end address */
  321. R3 = 0x2; /* 0th - position, 2 bits -length */
  322. nop; /*Anamoly 05000209*/
  323. R7 = EXTRACT(R1,R3.l);
  324. R7 = R7 << 2; /* Page size index offset */
  325. P5 = R7;
  326. P3 = P3 + P5;
  327. R7 = [P3]; /* page size in 1K bytes */
  328. R7 = R7 << 0xA; /* in bytes * 1024*/
  329. R7 = R2 + R7; /* R7 - PageEnd */
  330. R4 = SP; /* Test SP is in range */
  331. CC = R7 < R4; /* if PageEnd < SP */
  332. IF CC JUMP dfound_victim;
  333. R3 = 0x284; /* stack length from start of trap till the point */
  334. /* 20 stack locations for future modifications */
  335. R4 = R4 + R3;
  336. CC = R4 < R2; /* if SP + stacklen < PageStart */
  337. IF CC JUMP dfound_victim;
  338. skip_stack_check:
  339. edsearch2: NOP;
  340. edsearch1: NOP;
  341. /* If we got here, we didn't find a DCPLB we considered
  342. * replacable, which means all of them were locked.
  343. */
  344. JUMP all_locked;
  345. dfound_victim:
  346. #ifdef CONFIG_CPLB_INFO
  347. R1 = [P0 - 0x104];
  348. P2.L = dpdt_table;
  349. P2.H = dpdt_table;
  350. P3.L = dpdt_swapcount_table;
  351. P3.H = dpdt_swapcount_table;
  352. P3 += -4;
  353. dicount:
  354. R2 = [P2];
  355. P2 += 8;
  356. P3 += 8;
  357. CC = R2==-1;
  358. IF CC JUMP dicount_done;
  359. CC = R1==R2;
  360. IF !CC JUMP dicount;
  361. R1 = [P3];
  362. R1 += 1;
  363. [P3] = R1;
  364. CSYNC;
  365. dicount_done:
  366. #endif
  367. /* Clean down the hardware loops*/
  368. R2 = 0;
  369. LC1 = R2;
  370. LC0 = R2;
  371. /* There's a suitable victim in [P0-4] (because we've
  372. * advanced already). If it's a valid dirty write-back
  373. * CPLB, we need to flush the pending writes first.
  374. */
  375. CC = BITTST(R1, 0); /* Is it valid?*/
  376. IF !CC JUMP Ddoverwrite;/* nope.*/
  377. CC = BITTST(R1, 7); /* Is it dirty?*/
  378. IF !CC JUMP Ddoverwrite (BP); /* Nope.*/
  379. CC = BITTST(R1, 14); /* Is it Write-Through?*/
  380. IF CC JUMP Ddoverwrite; /* Yep*/
  381. /* This is a dirty page, so we need to flush all writes
  382. * that are pending on the page.
  383. */
  384. /* Retrieve the page start address*/
  385. R0 = [P0 - 0x104];
  386. [--sp] = rets;
  387. CALL dcplb_flush; /* R0==CPLB addr, R1==CPLB data*/
  388. rets = [sp++];
  389. Ddoverwrite:
  390. /* [P0-4] is a suitable victim CPLB, so we want to
  391. * overwrite it by moving all the following CPLBs
  392. * one space closer to the start.
  393. */
  394. R1.L = ((DCPLB_DATA15+4) & 0xFFFF); /*DCPLB_DATA15+4*/
  395. R1.H = ((DCPLB_DATA15+4) >> 16);
  396. R0 = P0;
  397. /* If the victim happens to be in DCPLB15,
  398. * we don't need to move anything.
  399. */
  400. CC = R1 == R0;
  401. IF CC JUMP de_moved;
  402. R1 = R1 - R0;
  403. R1 >>= 2;
  404. P1 = R1;
  405. LSETUP(ds_move, de_move) LC0=P1;
  406. ds_move:
  407. R0 = [P0++]; /* move data */
  408. [P0 - 8] = R0;
  409. R0 = [P0-0x104] /* move address */
  410. de_move: [P0-0x108] = R0;
  411. /* We've now made space in DCPLB15 for the new CPLB to be
  412. * installed. The next stage is to locate a CPLB in the
  413. * config table that covers the faulting address.
  414. */
  415. de_moved:NOP;
  416. R0 = I0; /* Our faulting address */
  417. P2.L = dpdt_table;
  418. P2.H = dpdt_table;
  419. #ifdef CONFIG_CPLB_INFO
  420. P3.L = dpdt_swapcount_table;
  421. P3.H = dpdt_swapcount_table;
  422. P3 += -8;
  423. #endif
  424. P1.L = page_size_table;
  425. P1.H = page_size_table;
  426. /* An extraction pattern, to retrieve bits 17:16.*/
  427. R1 = (16<<8)|2;
  428. dnext: R4 = [P2++]; /* address */
  429. R2 = [P2++]; /* data */
  430. #ifdef CONFIG_CPLB_INFO
  431. P3 += 8;
  432. #endif
  433. CC = R4 == -1;
  434. IF CC JUMP no_page_in_table;
  435. /* See if failed address > start address */
  436. CC = R4 <= R0(IU);
  437. IF !CC JUMP dnext;
  438. /* extract page size (17:16)*/
  439. R3 = EXTRACT(R2, R1.L) (Z);
  440. /* add page size to addr to get range */
  441. P5 = R3;
  442. P5 = P1 + (P5 << 2);
  443. R3 = [P5];
  444. R3 = R3 + R4;
  445. /* See if failed address < (start address + page size) */
  446. CC = R0 < R3(IU);
  447. IF !CC JUMP dnext;
  448. /* We've found the CPLB that should be installed, so
  449. * write it into CPLB15, masking off any caching bits
  450. * if necessary.
  451. */
  452. P1.L = (DCPLB_DATA15 & 0xFFFF);
  453. P1.H = (DCPLB_DATA15 >> 16);
  454. /* If the DCPLB has cache bits set, but caching hasn't
  455. * been enabled, then we want to mask off the cache-in-L1
  456. * bit before installing. Moreover, if caching is off, we
  457. * also want to ensure that the DCPLB has WT mode set, rather
  458. * than WB, since WB pages still trigger first-write exceptions
  459. * even when not caching is off, and the page isn't marked as
  460. * cachable. Finally, we could mark the page as clean, not dirty,
  461. * but we choose to leave that decision to the user; if the user
  462. * chooses to have a CPLB pre-defined as dirty, then they always
  463. * pay the cost of flushing during eviction, but don't pay the
  464. * cost of first-write exceptions to mark the page as dirty.
  465. */
  466. #ifdef CONFIG_BLKFIN_WT
  467. BITSET(R6, 14); /* Set WT*/
  468. #endif
  469. [P1] = R2;
  470. [P1-0x100] = R4;
  471. #ifdef CONFIG_CPLB_INFO
  472. R3 = [P3];
  473. R3 += 1;
  474. [P3] = R3;
  475. #endif
  476. /* We've installed the CPLB, so re-enable CPLBs. P4
  477. * points to DMEM_CONTROL, and R5 is the value we
  478. * last wrote to it, when we were disabling CPLBs.
  479. */
  480. BITSET(R5,ENDCPLB_P);
  481. CLI R2;
  482. .align 8;
  483. [P4] = R5;
  484. SSYNC;
  485. STI R2;
  486. ( R7:0,P5:0 ) = [SP++];
  487. R0 = CPLB_RELOADED;
  488. RTS;
  489. .data
  490. .align 4;
  491. page_size_table:
  492. .byte4 0x00000400; /* 1K */
  493. .byte4 0x00001000; /* 4K */
  494. .byte4 0x00100000; /* 1M */
  495. .byte4 0x00400000; /* 4M */
  496. .align 4;
  497. dcplb_preference:
  498. .byte4 0x00000001; /* valid bit */
  499. .byte4 0x00000082; /* dirty+lock bits */
  500. .byte4 0x00000002; /* lock bit */