cplbmgr.S 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  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. R0 = CPLB_NO_ADDR_MATCH;
  235. JUMP .Lfail_ret;
  236. .Lall_locked:
  237. R0 = CPLB_NO_UNLOCKED;
  238. JUMP .Lfail_ret;
  239. .Lprot_violation:
  240. R0 = CPLB_PROT_VIOL;
  241. .Lfail_ret:
  242. /* Make sure we turn protection/cache back on, even in the failing case */
  243. BITSET(R5,ENICPLB_P);
  244. CLI R2;
  245. SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
  246. .align 8;
  247. [P4] = R5;
  248. SSYNC;
  249. STI R2;
  250. ( R7:4,P5:3 ) = [SP++];
  251. RTS;
  252. .Ldcplb_write:
  253. /* if a DCPLB is marked as write-back (CPLB_WT==0), and
  254. * it is clean (CPLB_DIRTY==0), then a write to the
  255. * CPLB's page triggers a protection violation. We have to
  256. * mark the CPLB as dirty, to indicate that there are
  257. * pending writes associated with the CPLB.
  258. */
  259. P4.L = LO(DCPLB_STATUS);
  260. P4.H = HI(DCPLB_STATUS);
  261. P3.L = LO(DCPLB_DATA0);
  262. P3.H = HI(DCPLB_DATA0);
  263. R5 = [P4];
  264. /* A protection violation can be caused by more than just writes
  265. * to a clean WB page, so we have to ensure that:
  266. * - It's a write
  267. * - to a clean WB page
  268. * - and is allowed in the mode the access occurred.
  269. */
  270. CC = BITTST(R5, 16); /* ensure it was a write*/
  271. IF !CC JUMP .Lprot_violation;
  272. /* to check the rest, we have to retrieve the DCPLB.*/
  273. /* The low half of DCPLB_STATUS is a bit mask*/
  274. R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
  275. R3 = 30; /* so we can use this to determine the offset*/
  276. R2.L = SIGNBITS R2;
  277. R2 = R2.L (Z); /* into the DCPLB table.*/
  278. R3 = R3 - R2;
  279. P4 = R3;
  280. P3 = P3 + (P4<<2);
  281. R3 = [P3]; /* Retrieve the CPLB*/
  282. /* Now we can check whether it's a clean WB page*/
  283. CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
  284. IF CC JUMP .Lprot_violation;
  285. CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
  286. IF CC JUMP .Lprot_violation;
  287. /* Check whether the write is allowed in the mode that was active.*/
  288. R2 = 1<<3; /* checking write in user mode*/
  289. CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
  290. R5 = CC;
  291. R2 <<= R5; /* if was super, check write in super mode*/
  292. R2 = R3 & R2;
  293. CC = R2 == 0;
  294. IF CC JUMP .Lprot_violation;
  295. /* It's a genuine write-to-clean-page.*/
  296. BITSET(R3, 7); /* mark as dirty*/
  297. [P3] = R3; /* and write back.*/
  298. NOP;
  299. CSYNC;
  300. ( R7:4,P5:3 ) = [SP++];
  301. R0 = CPLB_RELOADED;
  302. RTS;
  303. .Ldcplb_miss_compare:
  304. /* Data CPLB Miss event. We need to choose a CPLB to
  305. * evict, and then locate a new CPLB to install from the
  306. * config table, that covers the faulting address.
  307. */
  308. P1.L = LO(DCPLB_DATA15);
  309. P1.H = HI(DCPLB_DATA15);
  310. P4.L = LO(DCPLB_FAULT_ADDR);
  311. P4.H = HI(DCPLB_FAULT_ADDR);
  312. R4 = [P4];
  313. I0 = R4;
  314. /* The replacement procedure for DCPLBs*/
  315. R6 = R1; /* Save for later*/
  316. /* Turn off CPLBs while we work.*/
  317. P4.L = LO(DMEM_CONTROL);
  318. P4.H = HI(DMEM_CONTROL);
  319. R5 = [P4];
  320. BITCLR(R5,ENDCPLB_P);
  321. CLI R0;
  322. SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
  323. .align 8;
  324. [P4] = R5;
  325. SSYNC;
  326. STI R0;
  327. /* Start looking for a CPLB to evict. Our order of preference
  328. * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
  329. * are no good.
  330. */
  331. I1.L = LO(DCPLB_DATA0);
  332. I1.H = HI(DCPLB_DATA0);
  333. P1 = 2;
  334. P2 = 16;
  335. I2.L = _dcplb_preference;
  336. I2.H = _dcplb_preference;
  337. LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
  338. .Lsdsearch1:
  339. R0 = [I2++]; /* Get the bits we're interested in*/
  340. P0 = I1; /* Go back to start of table*/
  341. LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
  342. .Lsdsearch2:
  343. R1 = [P0++]; /* Fetch each installed CPLB in turn*/
  344. R2 = R1 & R0; /* and test for interesting bits.*/
  345. CC = R2 == 0; /* If none are set, it'll do.*/
  346. IF !CC JUMP .Lskip_stack_check;
  347. R2 = [P0 - 0x104]; /* R2 - PageStart */
  348. P3.L = _page_size_table; /* retrieve end address */
  349. P3.H = _page_size_table; /* retrieve end address */
  350. R3 = 0x1002; /* 16th - position, 2 bits -length */
  351. #if ANOMALY_05000209
  352. nop; /* Anomaly 05000209 */
  353. #endif
  354. R7 = EXTRACT(R1,R3.l);
  355. R7 = R7 << 2; /* Page size index offset */
  356. P5 = R7;
  357. P3 = P3 + P5;
  358. R7 = [P3]; /* page size in bytes */
  359. R7 = R2 + R7; /* R7 - PageEnd */
  360. R4 = SP; /* Test SP is in range */
  361. CC = R7 < R4; /* if PageEnd < SP */
  362. IF CC JUMP .Ldfound_victim;
  363. R3 = 0x284; /* stack length from start of trap till
  364. * the point.
  365. * 20 stack locations for future modifications
  366. */
  367. R4 = R4 + R3;
  368. CC = R4 < R2; /* if SP + stacklen < PageStart */
  369. IF CC JUMP .Ldfound_victim;
  370. .Lskip_stack_check:
  371. .Ledsearch2: NOP;
  372. .Ledsearch1: NOP;
  373. /* If we got here, we didn't find a DCPLB we considered
  374. * replacable, which means all of them were locked.
  375. */
  376. JUMP .Lall_locked;
  377. .Ldfound_victim:
  378. #ifdef CONFIG_CPLB_INFO
  379. R7 = [P0 - 0x104];
  380. P2.L = _dpdt_table;
  381. P2.H = _dpdt_table;
  382. P3.L = _dpdt_swapcount_table;
  383. P3.H = _dpdt_swapcount_table;
  384. P3 += -4;
  385. .Ldicount:
  386. R2 = [P2];
  387. P2 += 8;
  388. P3 += 8;
  389. CC = R2==-1;
  390. IF CC JUMP .Ldicount_done;
  391. CC = R7==R2;
  392. IF !CC JUMP .Ldicount;
  393. R7 = [P3];
  394. R7 += 1;
  395. [P3] = R7;
  396. .Ldicount_done:
  397. #endif
  398. /* Clean down the hardware loops*/
  399. R2 = 0;
  400. LC1 = R2;
  401. LC0 = R2;
  402. /* There's a suitable victim in [P0-4] (because we've
  403. * advanced already).
  404. */
  405. .LDdoverwrite:
  406. /* [P0-4] is a suitable victim CPLB, so we want to
  407. * overwrite it by moving all the following CPLBs
  408. * one space closer to the start.
  409. */
  410. R1.L = LO(DCPLB_DATA16); /* DCPLB_DATA15 + 4 */
  411. R1.H = HI(DCPLB_DATA16);
  412. R0 = P0;
  413. /* If the victim happens to be in DCPLB15,
  414. * we don't need to move anything.
  415. */
  416. CC = R1 == R0;
  417. IF CC JUMP .Lde_moved;
  418. R1 = R1 - R0;
  419. R1 >>= 2;
  420. P1 = R1;
  421. LSETUP(.Lds_move, .Lde_move) LC0=P1;
  422. .Lds_move:
  423. R0 = [P0++]; /* move data */
  424. [P0 - 8] = R0;
  425. R0 = [P0-0x104] /* move address */
  426. .Lde_move: [P0-0x108] = R0;
  427. /* We've now made space in DCPLB15 for the new CPLB to be
  428. * installed. The next stage is to locate a CPLB in the
  429. * config table that covers the faulting address.
  430. */
  431. .Lde_moved:NOP;
  432. R0 = I0; /* Our faulting address */
  433. P2.L = _dpdt_table;
  434. P2.H = _dpdt_table;
  435. #ifdef CONFIG_CPLB_INFO
  436. P3.L = _dpdt_swapcount_table;
  437. P3.H = _dpdt_swapcount_table;
  438. P3 += -8;
  439. #endif
  440. P1.L = _page_size_table;
  441. P1.H = _page_size_table;
  442. /* An extraction pattern, to retrieve bits 17:16.*/
  443. R1 = (16<<8)|2;
  444. .Ldnext: R4 = [P2++]; /* address */
  445. R2 = [P2++]; /* data */
  446. #ifdef CONFIG_CPLB_INFO
  447. P3 += 8;
  448. #endif
  449. CC = R4 == -1;
  450. IF CC JUMP .Lno_page_in_table;
  451. /* See if failed address > start address */
  452. CC = R4 <= R0(IU);
  453. IF !CC JUMP .Ldnext;
  454. /* extract page size (17:16)*/
  455. R3 = EXTRACT(R2, R1.L) (Z);
  456. /* add page size to addr to get range */
  457. P5 = R3;
  458. P5 = P1 + (P5 << 2);
  459. R3 = [P5];
  460. R3 = R3 + R4;
  461. /* See if failed address < (start address + page size) */
  462. CC = R0 < R3(IU);
  463. IF !CC JUMP .Ldnext;
  464. /* We've found the CPLB that should be installed, so
  465. * write it into CPLB15, masking off any caching bits
  466. * if necessary.
  467. */
  468. P1.L = LO(DCPLB_DATA15);
  469. P1.H = HI(DCPLB_DATA15);
  470. /* If the DCPLB has cache bits set, but caching hasn't
  471. * been enabled, then we want to mask off the cache-in-L1
  472. * bit before installing. Moreover, if caching is off, we
  473. * also want to ensure that the DCPLB has WT mode set, rather
  474. * than WB, since WB pages still trigger first-write exceptions
  475. * even when not caching is off, and the page isn't marked as
  476. * cachable. Finally, we could mark the page as clean, not dirty,
  477. * but we choose to leave that decision to the user; if the user
  478. * chooses to have a CPLB pre-defined as dirty, then they always
  479. * pay the cost of flushing during eviction, but don't pay the
  480. * cost of first-write exceptions to mark the page as dirty.
  481. */
  482. #ifdef CONFIG_BFIN_WT
  483. BITSET(R6, 14); /* Set WT*/
  484. #endif
  485. [P1] = R2;
  486. [P1-0x100] = R4;
  487. #ifdef CONFIG_CPLB_INFO
  488. R3 = [P3];
  489. R3 += 1;
  490. [P3] = R3;
  491. #endif
  492. /* We've installed the CPLB, so re-enable CPLBs. P4
  493. * points to DMEM_CONTROL, and R5 is the value we
  494. * last wrote to it, when we were disabling CPLBs.
  495. */
  496. BITSET(R5,ENDCPLB_P);
  497. CLI R2;
  498. .align 8;
  499. [P4] = R5;
  500. SSYNC;
  501. STI R2;
  502. ( R7:4,P5:3 ) = [SP++];
  503. R0 = CPLB_RELOADED;
  504. RTS;
  505. ENDPROC(_cplb_mgr)
  506. .data
  507. .align 4;
  508. _page_size_table:
  509. .byte4 0x00000400; /* 1K */
  510. .byte4 0x00001000; /* 4K */
  511. .byte4 0x00100000; /* 1M */
  512. .byte4 0x00400000; /* 4M */
  513. .align 4;
  514. _dcplb_preference:
  515. .byte4 0x00000001; /* valid bit */
  516. .byte4 0x00000002; /* lock bit */