2 * File: arch/blackfin/mach-common/cplbmgtr.S
4 * Author: LG Soft India
7 * Description: CPLB replacement routine for CPLB mismatch
10 * Copyright 2004-2006 Analog Devices Inc.
12 * Bugs: Enter bugs at http://blackfin.uclinux.org/
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.
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.
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
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.
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
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.
52 #include <linux/linkage.h>
53 #include <asm/blackfin.h>
56 #ifdef CONFIG_EXCPT_IRQ_SYSC_L1
68 IF CC JUMP .Ldcplb_write;
71 IF !CC JUMP .Ldcplb_miss_compare;
73 /* ICPLB Miss Exception. We need to choose one of the
74 * currently-installed CPLBs, and replace it with one
75 * from the configuration table.
78 P4.L = (ICPLB_FAULT_ADDR & 0xFFFF);
79 P4.H = (ICPLB_FAULT_ADDR >> 16);
82 P5.L = _page_size_table;
83 P5.H = _page_size_table;
85 P0.L = (ICPLB_DATA0 & 0xFFFF);
86 P0.H = (ICPLB_DATA0 >> 16);
87 R4 = [P4]; /* Get faulting address*/
88 R6 = 64; /* Advance past the fault address, which*/
89 R6 = R6 + R4; /* we'll use if we find a match*/
90 R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/
95 R1 = [P0-0x100]; /* Address for this CPLB */
97 R0 = [P0++]; /* Info for this CPLB*/
98 CC = BITTST(R0,0); /* Is the CPLB valid?*/
99 IF !CC JUMP .Lnomatch; /* Skip it, if not.*/
100 CC = R4 < R1(IU); /* If fault address less than page start*/
101 IF CC JUMP .Lnomatch; /* then skip this one.*/
102 R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/
104 P1 = P5 + (P1<<2); /* index into page-size table*/
105 R2 = [P1]; /* Get the page size*/
106 R1 = R1 + R2; /* and add to page start, to get page end*/
107 CC = R4 < R1(IU); /* and see whether fault addr is in page.*/
108 IF !CC R4 = R6; /* If so, advance the address and finish loop.*/
109 IF !CC JUMP .Lisearch_done;
113 CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/
114 IF !CC JUMP .Lisearch;
117 I0 = R4; /* Fault address we'll search for*/
119 /* set up pointers */
120 P0.L = (ICPLB_DATA0 & 0xFFFF);
121 P0.H = (ICPLB_DATA0 >> 16);
123 /* The replacement procedure for ICPLBs */
125 P4.L = (IMEM_CONTROL & 0xFFFF);
126 P4.H = (IMEM_CONTROL >> 16);
129 R5 = [P4]; /* Control Register*/
130 BITCLR(R5,ENICPLB_P);
132 SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
138 R1 = -1; /* end point comparison */
139 R3 = 16; /* counter */
141 /* Search through CPLBs for first non-locked entry */
142 /* Overwrite it by moving everyone else up by 1 */
147 IF CC JUMP .Lall_locked;
148 CC = BITTST(R0, 0); /* an invalid entry is good */
149 IF !CC JUMP .Lifound_victim;
150 CC = BITTST(R0,1); /* but a locked entry isn't */
151 IF CC JUMP .Licheck_lock;
154 #ifdef CONFIG_CPLB_INFO
158 P3.L = _ipdt_swapcount_table;
159 P3.H = _ipdt_swapcount_table;
162 R2 = [P2]; /* address from config table */
166 IF CC JUMP .Licount_done;
168 IF !CC JUMP .Licount;
176 LSETUP(.Lis_move,.Lie_move) LC0;
184 /* We've made space in the ICPLB table, so that ICPLB15
185 * is now free to be overwritten. Next, we have to determine
186 * which CPLB we need to install, from the configuration
187 * table. This is a matter of getting the start-of-page
188 * addresses and page-lengths from the config table, and
189 * determining whether the fault address falls within that
195 #ifdef CONFIG_CPLB_INFO
196 P3.L = _ipdt_swapcount_table;
197 P3.H = _ipdt_swapcount_table;
200 P0.L = _page_size_table;
201 P0.H = _page_size_table;
203 /* Retrieve our fault address (which may have been advanced
204 * because the faulting instruction crossed a page boundary).
209 /* An extraction pattern, to get the page-size bits from
210 * the CPLB data entry. Bits 16-17, so two bits at posn 16.
214 .Linext: R4 = [P2++]; /* address from config table */
215 R2 = [P2++]; /* data from config table */
216 #ifdef CONFIG_CPLB_INFO
220 CC = R4 == -1; /* End of config table*/
221 IF CC JUMP .Lno_page_in_table;
223 /* See if failed address > start address */
227 /* extract page size (17:16)*/
228 R3 = EXTRACT(R2, R1.L) (Z);
230 /* add page size to addr to get range */
233 P5 = P0 + (P5 << 2); /* scaled, for int access*/
237 /* See if failed address < (start address + page size) */
241 /* We've found a CPLB in the config table that covers
242 * the faulting address, so install this CPLB into the
243 * last entry of the table.
246 P1.L = (ICPLB_DATA15 & 0xFFFF); /* ICPLB_DATA15 */
247 P1.H = (ICPLB_DATA15 >> 16);
250 #ifdef CONFIG_CPLB_INFO
256 /* P4 points to IMEM_CONTROL, and R5 contains its old
257 * value, after we disabled ICPLBS. Re-enable them.
260 BITSET(R5,ENICPLB_P);
262 SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
268 ( R7:4,P5:3 ) = [SP++];
274 ( R7:4,P5:3 ) = [SP++];
275 R0 = CPLB_NO_ADDR_MATCH;
278 ( R7:4,P5:3 ) = [SP++];
279 R0 = CPLB_NO_UNLOCKED;
282 ( R7:4,P5:3 ) = [SP++];
288 /* if a DCPLB is marked as write-back (CPLB_WT==0), and
289 * it is clean (CPLB_DIRTY==0), then a write to the
290 * CPLB's page triggers a protection violation. We have to
291 * mark the CPLB as dirty, to indicate that there are
292 * pending writes associated with the CPLB.
295 P4.L = (DCPLB_STATUS & 0xFFFF);
296 P4.H = (DCPLB_STATUS >> 16);
297 P3.L = (DCPLB_DATA0 & 0xFFFF);
298 P3.H = (DCPLB_DATA0 >> 16);
301 /* A protection violation can be caused by more than just writes
302 * to a clean WB page, so we have to ensure that:
304 * - to a clean WB page
305 * - and is allowed in the mode the access occurred.
308 CC = BITTST(R5, 16); /* ensure it was a write*/
309 IF !CC JUMP .Lprot_violation;
311 /* to check the rest, we have to retrieve the DCPLB.*/
313 /* The low half of DCPLB_STATUS is a bit mask*/
315 R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
316 R3 = 30; /* so we can use this to determine the offset*/
318 R2 = R2.L (Z); /* into the DCPLB table.*/
322 R3 = [P3]; /* Retrieve the CPLB*/
324 /* Now we can check whether it's a clean WB page*/
326 CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
327 IF CC JUMP .Lprot_violation;
328 CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
329 IF CC JUMP .Lprot_violation;
331 /* Check whether the write is allowed in the mode that was active.*/
333 R2 = 1<<3; /* checking write in user mode*/
334 CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
336 R2 <<= R5; /* if was super, check write in super mode*/
339 IF CC JUMP .Lprot_violation;
341 /* It's a genuine write-to-clean-page.*/
343 BITSET(R3, 7); /* mark as dirty*/
344 [P3] = R3; /* and write back.*/
347 ( R7:4,P5:3 ) = [SP++];
351 .Ldcplb_miss_compare:
353 /* Data CPLB Miss event. We need to choose a CPLB to
354 * evict, and then locate a new CPLB to install from the
355 * config table, that covers the faulting address.
358 P1.L = (DCPLB_DATA15 & 0xFFFF);
359 P1.H = (DCPLB_DATA15 >> 16);
361 P4.L = (DCPLB_FAULT_ADDR & 0xFFFF);
362 P4.H = (DCPLB_FAULT_ADDR >> 16);
366 /* The replacement procedure for DCPLBs*/
368 R6 = R1; /* Save for later*/
370 /* Turn off CPLBs while we work.*/
371 P4.L = (DMEM_CONTROL & 0xFFFF);
372 P4.H = (DMEM_CONTROL >> 16);
374 BITCLR(R5,ENDCPLB_P);
376 SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
382 /* Start looking for a CPLB to evict. Our order of preference
383 * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
387 I1.L = (DCPLB_DATA0 & 0xFFFF);
388 I1.H = (DCPLB_DATA0 >> 16);
391 I2.L = _dcplb_preference;
392 I2.H = _dcplb_preference;
393 LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
395 R0 = [I2++]; /* Get the bits we're interested in*/
396 P0 = I1; /* Go back to start of table*/
397 LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
399 R1 = [P0++]; /* Fetch each installed CPLB in turn*/
400 R2 = R1 & R0; /* and test for interesting bits.*/
401 CC = R2 == 0; /* If none are set, it'll do.*/
402 IF !CC JUMP .Lskip_stack_check;
404 R2 = [P0 - 0x104]; /* R2 - PageStart */
405 P3.L = _page_size_table; /* retrieve end address */
406 P3.H = _page_size_table; /* retrieve end address */
407 R3 = 0x1002; /* 16th - position, 2 bits -length */
408 #ifdef ANOMALY_05000209
409 nop; /* Anomaly 05000209 */
411 R7 = EXTRACT(R1,R3.l);
412 R7 = R7 << 2; /* Page size index offset */
415 R7 = [P3]; /* page size in bytes */
417 R7 = R2 + R7; /* R7 - PageEnd */
418 R4 = SP; /* Test SP is in range */
420 CC = R7 < R4; /* if PageEnd < SP */
421 IF CC JUMP .Ldfound_victim;
422 R3 = 0x284; /* stack length from start of trap till
424 * 20 stack locations for future modifications
427 CC = R4 < R2; /* if SP + stacklen < PageStart */
428 IF CC JUMP .Ldfound_victim;
434 /* If we got here, we didn't find a DCPLB we considered
435 * replacable, which means all of them were locked.
441 #ifdef CONFIG_CPLB_INFO
445 P3.L = _dpdt_swapcount_table;
446 P3.H = _dpdt_swapcount_table;
453 IF CC JUMP .Ldicount_done;
455 IF !CC JUMP .Ldicount;
462 /* Clean down the hardware loops*/
467 /* There's a suitable victim in [P0-4] (because we've
473 /* [P0-4] is a suitable victim CPLB, so we want to
474 * overwrite it by moving all the following CPLBs
475 * one space closer to the start.
478 R1.L = (DCPLB_DATA16 & 0xFFFF); /* DCPLB_DATA15 + 4 */
479 R1.H = (DCPLB_DATA16 >> 16);
482 /* If the victim happens to be in DCPLB15,
483 * we don't need to move anything.
487 IF CC JUMP .Lde_moved;
491 LSETUP(.Lds_move, .Lde_move) LC0=P1;
493 R0 = [P0++]; /* move data */
495 R0 = [P0-0x104] /* move address */
496 .Lde_move: [P0-0x108] = R0;
498 /* We've now made space in DCPLB15 for the new CPLB to be
499 * installed. The next stage is to locate a CPLB in the
500 * config table that covers the faulting address.
504 R0 = I0; /* Our faulting address */
508 #ifdef CONFIG_CPLB_INFO
509 P3.L = _dpdt_swapcount_table;
510 P3.H = _dpdt_swapcount_table;
514 P1.L = _page_size_table;
515 P1.H = _page_size_table;
517 /* An extraction pattern, to retrieve bits 17:16.*/
520 .Ldnext: R4 = [P2++]; /* address */
521 R2 = [P2++]; /* data */
522 #ifdef CONFIG_CPLB_INFO
527 IF CC JUMP .Lno_page_in_table;
529 /* See if failed address > start address */
533 /* extract page size (17:16)*/
534 R3 = EXTRACT(R2, R1.L) (Z);
536 /* add page size to addr to get range */
543 /* See if failed address < (start address + page size) */
547 /* We've found the CPLB that should be installed, so
548 * write it into CPLB15, masking off any caching bits
552 P1.L = (DCPLB_DATA15 & 0xFFFF);
553 P1.H = (DCPLB_DATA15 >> 16);
555 /* If the DCPLB has cache bits set, but caching hasn't
556 * been enabled, then we want to mask off the cache-in-L1
557 * bit before installing. Moreover, if caching is off, we
558 * also want to ensure that the DCPLB has WT mode set, rather
559 * than WB, since WB pages still trigger first-write exceptions
560 * even when not caching is off, and the page isn't marked as
561 * cachable. Finally, we could mark the page as clean, not dirty,
562 * but we choose to leave that decision to the user; if the user
563 * chooses to have a CPLB pre-defined as dirty, then they always
564 * pay the cost of flushing during eviction, but don't pay the
565 * cost of first-write exceptions to mark the page as dirty.
568 #ifdef CONFIG_BLKFIN_WT
569 BITSET(R6, 14); /* Set WT*/
574 #ifdef CONFIG_CPLB_INFO
580 /* We've installed the CPLB, so re-enable CPLBs. P4
581 * points to DMEM_CONTROL, and R5 is the value we
582 * last wrote to it, when we were disabling CPLBs.
585 BITSET(R5,ENDCPLB_P);
592 ( R7:4,P5:3 ) = [SP++];
599 .byte4 0x00000400; /* 1K */
600 .byte4 0x00001000; /* 4K */
601 .byte4 0x00100000; /* 1M */
602 .byte4 0x00400000; /* 4M */
606 .byte4 0x00000001; /* valid bit */
607 .byte4 0x00000002; /* lock bit */