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