]> err.no Git - linux-2.6/blobdiff - arch/blackfin/mach-common/cplbmgr.S
[Blackfin] arch: do not use hard coded addresses
[linux-2.6] / arch / blackfin / mach-common / cplbmgr.S
index 946703ef48ffc912a45b93c7c10a05d0ccb848bc..f5cf3accef378fadae792b6660edf13eb76c284b 100644 (file)
@@ -73,7 +73,16 @@ ENTRY(_cplb_mgr)
        /* ICPLB Miss Exception. We need to choose one of the
        * currently-installed CPLBs, and replace it with one
        * from the configuration table.
-       */
+       */
+
+       /* A multi-word instruction can cross a page boundary. This means the
+        * first part of the instruction can be in a valid page, but the
+        * second part is not, and hence generates the instruction miss.
+        * However, the fault address is for the start of the instruction,
+        * not the part that's in the bad page. Therefore, we have to check
+        * whether the fault address applies to a page that is already present
+        * in the table.
+        */
 
        P4.L = LO(ICPLB_FAULT_ADDR);
        P4.H = HI(ICPLB_FAULT_ADDR);
@@ -87,7 +96,7 @@ ENTRY(_cplb_mgr)
        R4 = [P4];              /* Get faulting address*/
        R6 = 64;                /* Advance past the fault address, which*/
        R6 = R6 + R4;           /* we'll use if we find a match*/
-       R3 = ((16 << 8) | 2);   /* Extract mask, bits 16 and 17.*/
+       R3 = ((16 << 8) | 2);   /* Extract mask, two bits at posn 16 */
 
        R5 = 0;
 .Lisearch:
@@ -125,7 +134,9 @@ ENTRY(_cplb_mgr)
        P4.L = LO(IMEM_CONTROL);
        P4.H = HI(IMEM_CONTROL);
 
-       /* disable cplbs */
+       /* Turn off CPLBs while we work, necessary according to HRM before
+        * modifying CPLB descriptors
+        */
        R5 = [P4];              /* Control Register*/
        BITCLR(R5,ENICPLB_P);
        CLI R1;
@@ -179,7 +190,14 @@ ENTRY(_cplb_mgr)
        [P0 - 4] = R0;
        R0 = [P0 - 0x100];
        [P0-0x104] = R0;
-.Lie_move:P0+=4;
+.Lie_move:
+       P0+=4;
+
+       /* Clear ICPLB_DATA15, in case we don't find a replacement
+        * otherwise, we would have a duplicate entry, and will crash
+        */
+       R0 = 0;
+       [P0 - 4] = R0;
 
        /* We've made space in the ICPLB table, so that ICPLB15
         * is now free to be overwritten. Next, we have to determine
@@ -222,7 +240,7 @@ ENTRY(_cplb_mgr)
 
        /* See if failed address > start address */
        CC = R4 <= R0(IU);
-       IF !CC JUMP .Linext;
+       IF !CC JUMP .Linext;
 
        /* extract page size (17:16)*/
        R3 = EXTRACT(R2, R1.L) (Z);
@@ -271,16 +289,27 @@ ENTRY(_cplb_mgr)
 
 /* FAILED CASES*/
 .Lno_page_in_table:
-       ( R7:4,P5:3 ) = [SP++];
        R0 = CPLB_NO_ADDR_MATCH;
-       RTS;
+       JUMP .Lfail_ret;
+
 .Lall_locked:
-       ( R7:4,P5:3 ) = [SP++];
        R0 = CPLB_NO_UNLOCKED;
-       RTS;
+       JUMP .Lfail_ret;
+
 .Lprot_violation:
-       ( R7:4,P5:3 ) = [SP++];
        R0 = CPLB_PROT_VIOL;
+
+.Lfail_ret:
+       /* Make sure we turn protection/cache back on, even in the failing case */
+       BITSET(R5,ENICPLB_P);
+       CLI R2;
+       SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */
+       .align 8;
+       [P4] = R5;
+       SSYNC;
+       STI R2;
+
+       ( R7:4,P5:3 ) = [SP++];
        RTS;
 
 .Ldcplb_write:
@@ -493,14 +522,23 @@ ENTRY(_cplb_mgr)
        R0 = [P0++];    /* move data */
        [P0 - 8] = R0;
        R0 = [P0-0x104] /* move address */
-.Lde_move: [P0-0x108] = R0;
+.Lde_move:
+        [P0-0x108] = R0;
+
+.Lde_moved:
+       NOP;
+
+       /* Clear DCPLB_DATA15, in case we don't find a replacement
+        * otherwise, we would have a duplicate entry, and will crash
+        */
+       R0 = 0;
+       [P0 - 0x4] = R0;
 
        /* We've now made space in DCPLB15 for the new CPLB to be
         * installed. The next stage is to locate a CPLB in the
         * config table that covers the faulting address.
         */
 
-.Lde_moved:NOP;
        R0 = I0;                /* Our faulting address */
 
        P2.L = _dpdt_table;