Commit | Line | Data |
---|---|---|
1394f032 BW |
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 | ||
30 | /* Usage: int _cplb_mgr(is_data_miss,int enable_cache) | |
31 | * is_data_miss==2 => Mark as Dirty, write to the clean data page | |
32 | * is_data_miss==1 => Replace a data CPLB. | |
33 | * is_data_miss==0 => Replace an instruction CPLB. | |
34 | * | |
35 | * Returns: | |
36 | * CPLB_RELOADED => Successfully updated CPLB table. | |
37 | * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted. | |
38 | * This indicates that the CPLBs in the configuration | |
39 | * tablei are badly configured, as this should never | |
40 | * occur. | |
41 | * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the | |
42 | * exception, is not covered by any of the CPLBs in | |
43 | * the configuration table. The application is | |
44 | * presumably misbehaving. | |
45 | * CPLB_PROT_VIOL => The address being accessed, that triggered the | |
46 | * exception, was not a first-write to a clean Write | |
47 | * Back Data page, and so presumably is a genuine | |
48 | * violation of the page's protection attributes. | |
49 | * The application is misbehaving. | |
50 | */ | |
51 | ||
52 | #include <linux/linkage.h> | |
53 | #include <asm/blackfin.h> | |
54 | #include <asm/cplb.h> | |
b8a98989 | 55 | #include <asm/asm-offsets.h> |
1394f032 BW |
56 | |
57 | #ifdef CONFIG_EXCPT_IRQ_SYSC_L1 | |
58 | .section .l1.text | |
59 | #else | |
60 | .text | |
61 | #endif | |
62 | ||
63 | .align 2; | |
64 | ENTRY(_cplb_mgr) | |
65 | ||
66 | [--SP]=( R7:4,P5:3 ); | |
67 | ||
68 | CC = R0 == 2; | |
69 | IF CC JUMP .Ldcplb_write; | |
70 | ||
71 | CC = R0 == 0; | |
72 | IF !CC JUMP .Ldcplb_miss_compare; | |
73 | ||
74 | /* ICPLB Miss Exception. We need to choose one of the | |
75 | * currently-installed CPLBs, and replace it with one | |
76 | * from the configuration table. | |
6a3f0b46 | 77 | */ |
1394f032 | 78 | |
f53e8676 RG |
79 | /* A multi-word instruction can cross a page boundary. This means the |
80 | * first part of the instruction can be in a valid page, but the | |
81 | * second part is not, and hence generates the instruction miss. | |
82 | * However, the fault address is for the start of the instruction, | |
83 | * not the part that's in the bad page. Therefore, we have to check | |
84 | * whether the fault address applies to a page that is already present | |
85 | * in the table. | |
86 | */ | |
87 | ||
e208f83a MF |
88 | P4.L = LO(ICPLB_FAULT_ADDR); |
89 | P4.H = HI(ICPLB_FAULT_ADDR); | |
1394f032 BW |
90 | |
91 | P1 = 16; | |
92 | P5.L = _page_size_table; | |
93 | P5.H = _page_size_table; | |
94 | ||
e208f83a MF |
95 | P0.L = LO(ICPLB_DATA0); |
96 | P0.H = HI(ICPLB_DATA0); | |
1394f032 BW |
97 | R4 = [P4]; /* Get faulting address*/ |
98 | R6 = 64; /* Advance past the fault address, which*/ | |
99 | R6 = R6 + R4; /* we'll use if we find a match*/ | |
f53e8676 | 100 | R3 = ((16 << 8) | 2); /* Extract mask, two bits at posn 16 */ |
1394f032 BW |
101 | |
102 | R5 = 0; | |
103 | .Lisearch: | |
104 | ||
105 | R1 = [P0-0x100]; /* Address for this CPLB */ | |
106 | ||
107 | R0 = [P0++]; /* Info for this CPLB*/ | |
108 | CC = BITTST(R0,0); /* Is the CPLB valid?*/ | |
109 | IF !CC JUMP .Lnomatch; /* Skip it, if not.*/ | |
110 | CC = R4 < R1(IU); /* If fault address less than page start*/ | |
111 | IF CC JUMP .Lnomatch; /* then skip this one.*/ | |
112 | R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/ | |
113 | P1 = R2; | |
114 | P1 = P5 + (P1<<2); /* index into page-size table*/ | |
115 | R2 = [P1]; /* Get the page size*/ | |
116 | R1 = R1 + R2; /* and add to page start, to get page end*/ | |
117 | CC = R4 < R1(IU); /* and see whether fault addr is in page.*/ | |
118 | IF !CC R4 = R6; /* If so, advance the address and finish loop.*/ | |
119 | IF !CC JUMP .Lisearch_done; | |
120 | .Lnomatch: | |
121 | /* Go around again*/ | |
122 | R5 += 1; | |
123 | CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/ | |
124 | IF !CC JUMP .Lisearch; | |
125 | ||
126 | .Lisearch_done: | |
127 | I0 = R4; /* Fault address we'll search for*/ | |
128 | ||
129 | /* set up pointers */ | |
e208f83a MF |
130 | P0.L = LO(ICPLB_DATA0); |
131 | P0.H = HI(ICPLB_DATA0); | |
1394f032 BW |
132 | |
133 | /* The replacement procedure for ICPLBs */ | |
134 | ||
e208f83a MF |
135 | P4.L = LO(IMEM_CONTROL); |
136 | P4.H = HI(IMEM_CONTROL); | |
1394f032 | 137 | |
f53e8676 RG |
138 | /* Turn off CPLBs while we work, necessary according to HRM before |
139 | * modifying CPLB descriptors | |
140 | */ | |
1394f032 BW |
141 | R5 = [P4]; /* Control Register*/ |
142 | BITCLR(R5,ENICPLB_P); | |
143 | CLI R1; | |
144 | SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ | |
145 | .align 8; | |
146 | [P4] = R5; | |
147 | SSYNC; | |
148 | STI R1; | |
149 | ||
150 | R1 = -1; /* end point comparison */ | |
151 | R3 = 16; /* counter */ | |
152 | ||
153 | /* Search through CPLBs for first non-locked entry */ | |
154 | /* Overwrite it by moving everyone else up by 1 */ | |
155 | .Licheck_lock: | |
156 | R0 = [P0++]; | |
157 | R3 = R3 + R1; | |
158 | CC = R3 == R1; | |
159 | IF CC JUMP .Lall_locked; | |
160 | CC = BITTST(R0, 0); /* an invalid entry is good */ | |
161 | IF !CC JUMP .Lifound_victim; | |
162 | CC = BITTST(R0,1); /* but a locked entry isn't */ | |
163 | IF CC JUMP .Licheck_lock; | |
164 | ||
165 | .Lifound_victim: | |
166 | #ifdef CONFIG_CPLB_INFO | |
167 | R7 = [P0 - 0x104]; | |
b8a98989 GY |
168 | GET_PDA(P2, R2); |
169 | P3 = [P2 + PDA_IPDT_SWAPCOUNT]; | |
170 | P2 = [P2 + PDA_IPDT]; | |
1394f032 BW |
171 | P3 += -4; |
172 | .Licount: | |
173 | R2 = [P2]; /* address from config table */ | |
174 | P2 += 8; | |
175 | P3 += 8; | |
176 | CC = R2==-1; | |
177 | IF CC JUMP .Licount_done; | |
178 | CC = R7==R2; | |
179 | IF !CC JUMP .Licount; | |
180 | R7 = [P3]; | |
181 | R7 += 1; | |
182 | [P3] = R7; | |
183 | CSYNC; | |
184 | .Licount_done: | |
185 | #endif | |
186 | LC0=R3; | |
187 | LSETUP(.Lis_move,.Lie_move) LC0; | |
188 | .Lis_move: | |
189 | R0 = [P0]; | |
190 | [P0 - 4] = R0; | |
191 | R0 = [P0 - 0x100]; | |
192 | [P0-0x104] = R0; | |
13fe24f3 RG |
193 | .Lie_move: |
194 | P0+=4; | |
195 | ||
196 | /* Clear ICPLB_DATA15, in case we don't find a replacement | |
197 | * otherwise, we would have a duplicate entry, and will crash | |
198 | */ | |
199 | R0 = 0; | |
200 | [P0 - 4] = R0; | |
1394f032 BW |
201 | |
202 | /* We've made space in the ICPLB table, so that ICPLB15 | |
203 | * is now free to be overwritten. Next, we have to determine | |
204 | * which CPLB we need to install, from the configuration | |
205 | * table. This is a matter of getting the start-of-page | |
206 | * addresses and page-lengths from the config table, and | |
207 | * determining whether the fault address falls within that | |
208 | * range. | |
209 | */ | |
210 | ||
b8a98989 GY |
211 | GET_PDA(P3, R0); |
212 | P2 = [P3 + PDA_IPDT]; | |
1394f032 | 213 | #ifdef CONFIG_CPLB_INFO |
b8a98989 | 214 | P3 = [P3 + PDA_IPDT_SWAPCOUNT]; |
1394f032 BW |
215 | P3 += -8; |
216 | #endif | |
217 | P0.L = _page_size_table; | |
218 | P0.H = _page_size_table; | |
219 | ||
220 | /* Retrieve our fault address (which may have been advanced | |
221 | * because the faulting instruction crossed a page boundary). | |
222 | */ | |
223 | ||
224 | R0 = I0; | |
225 | ||
226 | /* An extraction pattern, to get the page-size bits from | |
227 | * the CPLB data entry. Bits 16-17, so two bits at posn 16. | |
228 | */ | |
229 | ||
230 | R1 = ((16<<8)|2); | |
231 | .Linext: R4 = [P2++]; /* address from config table */ | |
232 | R2 = [P2++]; /* data from config table */ | |
233 | #ifdef CONFIG_CPLB_INFO | |
234 | P3 += 8; | |
235 | #endif | |
236 | ||
237 | CC = R4 == -1; /* End of config table*/ | |
238 | IF CC JUMP .Lno_page_in_table; | |
239 | ||
240 | /* See if failed address > start address */ | |
241 | CC = R4 <= R0(IU); | |
6a3f0b46 | 242 | IF !CC JUMP .Linext; |
1394f032 BW |
243 | |
244 | /* extract page size (17:16)*/ | |
245 | R3 = EXTRACT(R2, R1.L) (Z); | |
246 | ||
247 | /* add page size to addr to get range */ | |
248 | ||
249 | P5 = R3; | |
250 | P5 = P0 + (P5 << 2); /* scaled, for int access*/ | |
251 | R3 = [P5]; | |
252 | R3 = R3 + R4; | |
253 | ||
254 | /* See if failed address < (start address + page size) */ | |
255 | CC = R0 < R3(IU); | |
256 | IF !CC JUMP .Linext; | |
257 | ||
258 | /* We've found a CPLB in the config table that covers | |
259 | * the faulting address, so install this CPLB into the | |
260 | * last entry of the table. | |
261 | */ | |
262 | ||
e208f83a MF |
263 | P1.L = LO(ICPLB_DATA15); /* ICPLB_DATA15 */ |
264 | P1.H = HI(ICPLB_DATA15); | |
1394f032 BW |
265 | [P1] = R2; |
266 | [P1-0x100] = R4; | |
267 | #ifdef CONFIG_CPLB_INFO | |
268 | R3 = [P3]; | |
269 | R3 += 1; | |
270 | [P3] = R3; | |
271 | #endif | |
272 | ||
273 | /* P4 points to IMEM_CONTROL, and R5 contains its old | |
274 | * value, after we disabled ICPLBS. Re-enable them. | |
275 | */ | |
276 | ||
277 | BITSET(R5,ENICPLB_P); | |
278 | CLI R2; | |
279 | SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ | |
280 | .align 8; | |
281 | [P4] = R5; | |
282 | SSYNC; | |
283 | STI R2; | |
284 | ||
285 | ( R7:4,P5:3 ) = [SP++]; | |
286 | R0 = CPLB_RELOADED; | |
287 | RTS; | |
288 | ||
289 | /* FAILED CASES*/ | |
290 | .Lno_page_in_table: | |
1394f032 | 291 | R0 = CPLB_NO_ADDR_MATCH; |
6a3f0b46 RG |
292 | JUMP .Lfail_ret; |
293 | ||
1394f032 | 294 | .Lall_locked: |
1394f032 | 295 | R0 = CPLB_NO_UNLOCKED; |
6a3f0b46 RG |
296 | JUMP .Lfail_ret; |
297 | ||
1394f032 | 298 | .Lprot_violation: |
1394f032 | 299 | R0 = CPLB_PROT_VIOL; |
6a3f0b46 RG |
300 | |
301 | .Lfail_ret: | |
302 | /* Make sure we turn protection/cache back on, even in the failing case */ | |
303 | BITSET(R5,ENICPLB_P); | |
304 | CLI R2; | |
305 | SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */ | |
306 | .align 8; | |
307 | [P4] = R5; | |
308 | SSYNC; | |
309 | STI R2; | |
310 | ||
311 | ( R7:4,P5:3 ) = [SP++]; | |
1394f032 BW |
312 | RTS; |
313 | ||
314 | .Ldcplb_write: | |
315 | ||
316 | /* if a DCPLB is marked as write-back (CPLB_WT==0), and | |
317 | * it is clean (CPLB_DIRTY==0), then a write to the | |
318 | * CPLB's page triggers a protection violation. We have to | |
319 | * mark the CPLB as dirty, to indicate that there are | |
320 | * pending writes associated with the CPLB. | |
321 | */ | |
322 | ||
e208f83a MF |
323 | P4.L = LO(DCPLB_STATUS); |
324 | P4.H = HI(DCPLB_STATUS); | |
325 | P3.L = LO(DCPLB_DATA0); | |
326 | P3.H = HI(DCPLB_DATA0); | |
1394f032 BW |
327 | R5 = [P4]; |
328 | ||
329 | /* A protection violation can be caused by more than just writes | |
330 | * to a clean WB page, so we have to ensure that: | |
331 | * - It's a write | |
332 | * - to a clean WB page | |
333 | * - and is allowed in the mode the access occurred. | |
334 | */ | |
335 | ||
336 | CC = BITTST(R5, 16); /* ensure it was a write*/ | |
337 | IF !CC JUMP .Lprot_violation; | |
338 | ||
339 | /* to check the rest, we have to retrieve the DCPLB.*/ | |
340 | ||
341 | /* The low half of DCPLB_STATUS is a bit mask*/ | |
342 | ||
343 | R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/ | |
344 | R3 = 30; /* so we can use this to determine the offset*/ | |
345 | R2.L = SIGNBITS R2; | |
346 | R2 = R2.L (Z); /* into the DCPLB table.*/ | |
347 | R3 = R3 - R2; | |
348 | P4 = R3; | |
349 | P3 = P3 + (P4<<2); | |
350 | R3 = [P3]; /* Retrieve the CPLB*/ | |
351 | ||
352 | /* Now we can check whether it's a clean WB page*/ | |
353 | ||
354 | CC = BITTST(R3, 14); /* 0==WB, 1==WT*/ | |
355 | IF CC JUMP .Lprot_violation; | |
356 | CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/ | |
357 | IF CC JUMP .Lprot_violation; | |
358 | ||
359 | /* Check whether the write is allowed in the mode that was active.*/ | |
360 | ||
361 | R2 = 1<<3; /* checking write in user mode*/ | |
362 | CC = BITTST(R5, 17); /* 0==was user, 1==was super*/ | |
363 | R5 = CC; | |
364 | R2 <<= R5; /* if was super, check write in super mode*/ | |
365 | R2 = R3 & R2; | |
366 | CC = R2 == 0; | |
367 | IF CC JUMP .Lprot_violation; | |
368 | ||
369 | /* It's a genuine write-to-clean-page.*/ | |
370 | ||
371 | BITSET(R3, 7); /* mark as dirty*/ | |
372 | [P3] = R3; /* and write back.*/ | |
373 | NOP; | |
374 | CSYNC; | |
375 | ( R7:4,P5:3 ) = [SP++]; | |
376 | R0 = CPLB_RELOADED; | |
377 | RTS; | |
378 | ||
379 | .Ldcplb_miss_compare: | |
380 | ||
381 | /* Data CPLB Miss event. We need to choose a CPLB to | |
382 | * evict, and then locate a new CPLB to install from the | |
383 | * config table, that covers the faulting address. | |
384 | */ | |
385 | ||
e208f83a MF |
386 | P1.L = LO(DCPLB_DATA15); |
387 | P1.H = HI(DCPLB_DATA15); | |
1394f032 | 388 | |
e208f83a MF |
389 | P4.L = LO(DCPLB_FAULT_ADDR); |
390 | P4.H = HI(DCPLB_FAULT_ADDR); | |
1394f032 BW |
391 | R4 = [P4]; |
392 | I0 = R4; | |
393 | ||
394 | /* The replacement procedure for DCPLBs*/ | |
395 | ||
396 | R6 = R1; /* Save for later*/ | |
397 | ||
398 | /* Turn off CPLBs while we work.*/ | |
e208f83a MF |
399 | P4.L = LO(DMEM_CONTROL); |
400 | P4.H = HI(DMEM_CONTROL); | |
1394f032 BW |
401 | R5 = [P4]; |
402 | BITCLR(R5,ENDCPLB_P); | |
403 | CLI R0; | |
404 | SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ | |
405 | .align 8; | |
406 | [P4] = R5; | |
407 | SSYNC; | |
408 | STI R0; | |
409 | ||
410 | /* Start looking for a CPLB to evict. Our order of preference | |
411 | * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs | |
412 | * are no good. | |
413 | */ | |
414 | ||
e208f83a MF |
415 | I1.L = LO(DCPLB_DATA0); |
416 | I1.H = HI(DCPLB_DATA0); | |
1394f032 BW |
417 | P1 = 2; |
418 | P2 = 16; | |
419 | I2.L = _dcplb_preference; | |
420 | I2.H = _dcplb_preference; | |
421 | LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1; | |
422 | .Lsdsearch1: | |
423 | R0 = [I2++]; /* Get the bits we're interested in*/ | |
424 | P0 = I1; /* Go back to start of table*/ | |
425 | LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2; | |
426 | .Lsdsearch2: | |
427 | R1 = [P0++]; /* Fetch each installed CPLB in turn*/ | |
428 | R2 = R1 & R0; /* and test for interesting bits.*/ | |
429 | CC = R2 == 0; /* If none are set, it'll do.*/ | |
430 | IF !CC JUMP .Lskip_stack_check; | |
431 | ||
432 | R2 = [P0 - 0x104]; /* R2 - PageStart */ | |
433 | P3.L = _page_size_table; /* retrieve end address */ | |
434 | P3.H = _page_size_table; /* retrieve end address */ | |
435 | R3 = 0x1002; /* 16th - position, 2 bits -length */ | |
1aafd909 | 436 | #if ANOMALY_05000209 |
1394f032 BW |
437 | nop; /* Anomaly 05000209 */ |
438 | #endif | |
439 | R7 = EXTRACT(R1,R3.l); | |
440 | R7 = R7 << 2; /* Page size index offset */ | |
441 | P5 = R7; | |
442 | P3 = P3 + P5; | |
443 | R7 = [P3]; /* page size in bytes */ | |
444 | ||
445 | R7 = R2 + R7; /* R7 - PageEnd */ | |
446 | R4 = SP; /* Test SP is in range */ | |
447 | ||
448 | CC = R7 < R4; /* if PageEnd < SP */ | |
449 | IF CC JUMP .Ldfound_victim; | |
450 | R3 = 0x284; /* stack length from start of trap till | |
451 | * the point. | |
452 | * 20 stack locations for future modifications | |
453 | */ | |
454 | R4 = R4 + R3; | |
455 | CC = R4 < R2; /* if SP + stacklen < PageStart */ | |
456 | IF CC JUMP .Ldfound_victim; | |
457 | .Lskip_stack_check: | |
458 | ||
459 | .Ledsearch2: NOP; | |
460 | .Ledsearch1: NOP; | |
461 | ||
462 | /* If we got here, we didn't find a DCPLB we considered | |
463 | * replacable, which means all of them were locked. | |
464 | */ | |
465 | ||
466 | JUMP .Lall_locked; | |
467 | .Ldfound_victim: | |
468 | ||
469 | #ifdef CONFIG_CPLB_INFO | |
470 | R7 = [P0 - 0x104]; | |
b8a98989 GY |
471 | GET_PDA(P2, R2); |
472 | P3 = [P2 + PDA_DPDT_SWAPCOUNT]; | |
473 | P2 = [P2 + PDA_DPDT]; | |
1394f032 BW |
474 | P3 += -4; |
475 | .Ldicount: | |
476 | R2 = [P2]; | |
477 | P2 += 8; | |
478 | P3 += 8; | |
479 | CC = R2==-1; | |
480 | IF CC JUMP .Ldicount_done; | |
481 | CC = R7==R2; | |
482 | IF !CC JUMP .Ldicount; | |
483 | R7 = [P3]; | |
484 | R7 += 1; | |
485 | [P3] = R7; | |
486 | .Ldicount_done: | |
487 | #endif | |
488 | ||
489 | /* Clean down the hardware loops*/ | |
490 | R2 = 0; | |
491 | LC1 = R2; | |
492 | LC0 = R2; | |
493 | ||
494 | /* There's a suitable victim in [P0-4] (because we've | |
495 | * advanced already). | |
496 | */ | |
497 | ||
498 | .LDdoverwrite: | |
499 | ||
500 | /* [P0-4] is a suitable victim CPLB, so we want to | |
501 | * overwrite it by moving all the following CPLBs | |
502 | * one space closer to the start. | |
503 | */ | |
504 | ||
e208f83a MF |
505 | R1.L = LO(DCPLB_DATA16); /* DCPLB_DATA15 + 4 */ |
506 | R1.H = HI(DCPLB_DATA16); | |
1394f032 BW |
507 | R0 = P0; |
508 | ||
509 | /* If the victim happens to be in DCPLB15, | |
510 | * we don't need to move anything. | |
511 | */ | |
512 | ||
513 | CC = R1 == R0; | |
514 | IF CC JUMP .Lde_moved; | |
515 | R1 = R1 - R0; | |
516 | R1 >>= 2; | |
517 | P1 = R1; | |
518 | LSETUP(.Lds_move, .Lde_move) LC0=P1; | |
519 | .Lds_move: | |
520 | R0 = [P0++]; /* move data */ | |
521 | [P0 - 8] = R0; | |
522 | R0 = [P0-0x104] /* move address */ | |
13fe24f3 RG |
523 | .Lde_move: |
524 | [P0-0x108] = R0; | |
525 | ||
526 | .Lde_moved: | |
527 | NOP; | |
528 | ||
529 | /* Clear DCPLB_DATA15, in case we don't find a replacement | |
530 | * otherwise, we would have a duplicate entry, and will crash | |
531 | */ | |
532 | R0 = 0; | |
533 | [P0 - 0x4] = R0; | |
1394f032 BW |
534 | |
535 | /* We've now made space in DCPLB15 for the new CPLB to be | |
536 | * installed. The next stage is to locate a CPLB in the | |
537 | * config table that covers the faulting address. | |
538 | */ | |
539 | ||
1394f032 BW |
540 | R0 = I0; /* Our faulting address */ |
541 | ||
b8a98989 GY |
542 | GET_PDA(P3, R1); |
543 | P2 = [P3 + PDA_DPDT]; | |
1394f032 | 544 | #ifdef CONFIG_CPLB_INFO |
b8a98989 | 545 | P3 = [P3 + PDA_DPDT_SWAPCOUNT]; |
1394f032 BW |
546 | P3 += -8; |
547 | #endif | |
548 | ||
549 | P1.L = _page_size_table; | |
550 | P1.H = _page_size_table; | |
551 | ||
552 | /* An extraction pattern, to retrieve bits 17:16.*/ | |
553 | ||
554 | R1 = (16<<8)|2; | |
555 | .Ldnext: R4 = [P2++]; /* address */ | |
556 | R2 = [P2++]; /* data */ | |
557 | #ifdef CONFIG_CPLB_INFO | |
558 | P3 += 8; | |
559 | #endif | |
560 | ||
561 | CC = R4 == -1; | |
562 | IF CC JUMP .Lno_page_in_table; | |
563 | ||
564 | /* See if failed address > start address */ | |
565 | CC = R4 <= R0(IU); | |
566 | IF !CC JUMP .Ldnext; | |
567 | ||
568 | /* extract page size (17:16)*/ | |
569 | R3 = EXTRACT(R2, R1.L) (Z); | |
570 | ||
571 | /* add page size to addr to get range */ | |
572 | ||
573 | P5 = R3; | |
574 | P5 = P1 + (P5 << 2); | |
575 | R3 = [P5]; | |
576 | R3 = R3 + R4; | |
577 | ||
578 | /* See if failed address < (start address + page size) */ | |
579 | CC = R0 < R3(IU); | |
580 | IF !CC JUMP .Ldnext; | |
581 | ||
582 | /* We've found the CPLB that should be installed, so | |
583 | * write it into CPLB15, masking off any caching bits | |
584 | * if necessary. | |
585 | */ | |
586 | ||
e208f83a MF |
587 | P1.L = LO(DCPLB_DATA15); |
588 | P1.H = HI(DCPLB_DATA15); | |
1394f032 BW |
589 | |
590 | /* If the DCPLB has cache bits set, but caching hasn't | |
591 | * been enabled, then we want to mask off the cache-in-L1 | |
592 | * bit before installing. Moreover, if caching is off, we | |
593 | * also want to ensure that the DCPLB has WT mode set, rather | |
594 | * than WB, since WB pages still trigger first-write exceptions | |
595 | * even when not caching is off, and the page isn't marked as | |
596 | * cachable. Finally, we could mark the page as clean, not dirty, | |
597 | * but we choose to leave that decision to the user; if the user | |
598 | * chooses to have a CPLB pre-defined as dirty, then they always | |
599 | * pay the cost of flushing during eviction, but don't pay the | |
600 | * cost of first-write exceptions to mark the page as dirty. | |
601 | */ | |
602 | ||
3bebca2d | 603 | #ifdef CONFIG_BFIN_WT |
1394f032 BW |
604 | BITSET(R6, 14); /* Set WT*/ |
605 | #endif | |
606 | ||
607 | [P1] = R2; | |
608 | [P1-0x100] = R4; | |
609 | #ifdef CONFIG_CPLB_INFO | |
610 | R3 = [P3]; | |
611 | R3 += 1; | |
612 | [P3] = R3; | |
613 | #endif | |
614 | ||
615 | /* We've installed the CPLB, so re-enable CPLBs. P4 | |
616 | * points to DMEM_CONTROL, and R5 is the value we | |
617 | * last wrote to it, when we were disabling CPLBs. | |
618 | */ | |
619 | ||
620 | BITSET(R5,ENDCPLB_P); | |
621 | CLI R2; | |
622 | .align 8; | |
623 | [P4] = R5; | |
624 | SSYNC; | |
625 | STI R2; | |
626 | ||
627 | ( R7:4,P5:3 ) = [SP++]; | |
628 | R0 = CPLB_RELOADED; | |
629 | RTS; | |
51be24c3 | 630 | ENDPROC(_cplb_mgr) |
1394f032 BW |
631 | |
632 | .data | |
633 | .align 4; | |
634 | _page_size_table: | |
635 | .byte4 0x00000400; /* 1K */ | |
636 | .byte4 0x00001000; /* 4K */ | |
637 | .byte4 0x00100000; /* 1M */ | |
638 | .byte4 0x00400000; /* 4M */ | |
639 | ||
640 | .align 4; | |
641 | _dcplb_preference: | |
642 | .byte4 0x00000001; /* valid bit */ | |
643 | .byte4 0x00000002; /* lock bit */ |