ARC: fix build warnings
[linux-2.6-microblaze.git] / arch / arc / mm / tlb.c
index 8ceefbf..fa18c00 100644 (file)
@@ -762,21 +762,23 @@ void read_decode_mmu_bcr(void)
        tmp = read_aux_reg(ARC_REG_MMU_BCR);
        mmu->ver = (tmp >> 24);
 
-       if (mmu->ver <= 2) {
-               mmu2 = (struct bcr_mmu_1_2 *)&tmp;
-               mmu->pg_sz_k = TO_KB(0x2000);
-               mmu->sets = 1 << mmu2->sets;
-               mmu->ways = 1 << mmu2->ways;
-               mmu->u_dtlb = mmu2->u_dtlb;
-               mmu->u_itlb = mmu2->u_itlb;
-       } else if (mmu->ver == 3) {
-               mmu3 = (struct bcr_mmu_3 *)&tmp;
-               mmu->pg_sz_k = 1 << (mmu3->pg_sz - 1);
-               mmu->sets = 1 << mmu3->sets;
-               mmu->ways = 1 << mmu3->ways;
-               mmu->u_dtlb = mmu3->u_dtlb;
-               mmu->u_itlb = mmu3->u_itlb;
-               mmu->sasid = mmu3->sasid;
+       if (is_isa_arcompact()) {
+               if (mmu->ver <= 2) {
+                       mmu2 = (struct bcr_mmu_1_2 *)&tmp;
+                       mmu->pg_sz_k = TO_KB(0x2000);
+                       mmu->sets = 1 << mmu2->sets;
+                       mmu->ways = 1 << mmu2->ways;
+                       mmu->u_dtlb = mmu2->u_dtlb;
+                       mmu->u_itlb = mmu2->u_itlb;
+               } else {
+                       mmu3 = (struct bcr_mmu_3 *)&tmp;
+                       mmu->pg_sz_k = 1 << (mmu3->pg_sz - 1);
+                       mmu->sets = 1 << mmu3->sets;
+                       mmu->ways = 1 << mmu3->ways;
+                       mmu->u_dtlb = mmu3->u_dtlb;
+                       mmu->u_itlb = mmu3->u_itlb;
+                       mmu->sasid = mmu3->sasid;
+               }
        } else {
                mmu4 = (struct bcr_mmu_4 *)&tmp;
                mmu->pg_sz_k = 1 << (mmu4->sz0 - 1);
@@ -818,8 +820,9 @@ int pae40_exist_but_not_enab(void)
 
 void arc_mmu_init(void)
 {
-       char str[256];
        struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+       char str[256];
+       int compat = 0;
 
        pr_info("%s", arc_mmu_mumbojumbo(0, str, sizeof(str)));
 
@@ -834,15 +837,21 @@ void arc_mmu_init(void)
         */
        BUILD_BUG_ON(!IS_ALIGNED(STACK_TOP, PMD_SIZE));
 
-       /* For efficiency sake, kernel is compile time built for a MMU ver
-        * This must match the hardware it is running on.
-        * Linux built for MMU V2, if run on MMU V1 will break down because V1
-        *  hardware doesn't understand cmds such as WriteNI, or IVUTLB
-        * On the other hand, Linux built for V1 if run on MMU V2 will do
-        *   un-needed workarounds to prevent memcpy thrashing.
-        * Similarly MMU V3 has new features which won't work on older MMU
+       /*
+        * Ensure that MMU features assumed by kernel exist in hardware.
+        * For older ARC700 cpus, it has to be exact match, since the MMU
+        * revisions were not backwards compatible (MMUv3 TLB layout changed
+        * so even if kernel for v2 didn't use any new cmds of v3, it would
+        * still not work.
+        * For HS cpus, MMUv4 was baseline and v5 is backwards compatible
+        * (will run older software).
         */
-       if (mmu->ver != CONFIG_ARC_MMU_VER) {
+       if (is_isa_arcompact() && mmu->ver == CONFIG_ARC_MMU_VER)
+               compat = 1;
+       else if (is_isa_arcv2() && mmu->ver >= CONFIG_ARC_MMU_VER)
+               compat = 1;
+
+       if (!compat) {
                panic("MMU ver %d doesn't match kernel built for %d...\n",
                      mmu->ver, CONFIG_ARC_MMU_VER);
        }
@@ -902,9 +911,11 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
                          struct pt_regs *regs)
 {
        struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
-       unsigned int pd0[mmu->ways];
        unsigned long flags;
-       int set;
+       int set, n_ways = mmu->ways;
+
+       n_ways = min(n_ways, 4);
+       BUG_ON(mmu->ways > 4);
 
        local_irq_save(flags);
 
@@ -912,9 +923,10 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
        for (set = 0; set < mmu->sets; set++) {
 
                int is_valid, way;
+               unsigned int pd0[4];
 
                /* read out all the ways of current set */
-               for (way = 0, is_valid = 0; way < mmu->ways; way++) {
+               for (way = 0, is_valid = 0; way < n_ways; way++) {
                        write_aux_reg(ARC_REG_TLBINDEX,
                                          SET_WAY_TO_IDX(mmu, set, way));
                        write_aux_reg(ARC_REG_TLBCOMMAND, TLBRead);
@@ -928,14 +940,14 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
                        continue;
 
                /* Scan the set for duplicate ways: needs a nested loop */
-               for (way = 0; way < mmu->ways - 1; way++) {
+               for (way = 0; way < n_ways - 1; way++) {
 
                        int n;
 
                        if (!pd0[way])
                                continue;
 
-                       for (n = way + 1; n < mmu->ways; n++) {
+                       for (n = way + 1; n < n_ways; n++) {
                                if (pd0[way] != pd0[n])
                                        continue;