cplbmgr.S 15 KB

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