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