sh: Replace unsafe manipulation of MMUCR
authorMatt Fleming <matt@console-pimps.org>
Sun, 21 Mar 2010 19:51:52 +0000 (19:51 +0000)
committerPaul Mundt <lethal@linux-sh.org>
Tue, 23 Mar 2010 04:36:21 +0000 (13:36 +0900)
Setting the TI in MMUCR causes all the TLB bits in MMUCR to be
cleared. Unfortunately, the TLB wired bits are also cleared when setting
the TI bit, causing any wired TLB entries to become unwired.

Use local_flush_tlb_all() which implements TLB flushing in a safer
manner by using the memory-mapped TLB registers. As each CPU has its own
PMB the modifications in pmb_init() only affect the local CPU, so only
flush the local CPU's TLB.

Signed-off-by: Matt Fleming <matt@console-pimps.org>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/mm/pmb.c
arch/sh/mm/tlbflush_32.c

index a4662e2782c3fd84c8743dfb56394fdce971fe95..0b14dcf05da73603a4ad3679e0ba9ef23f2cd3e4 100644 (file)
@@ -802,7 +802,7 @@ void __init pmb_init(void)
        writel_uncached(0, PMB_IRMCR);
 
        /* Flush out the TLB */
-       __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
+       local_flush_tlb_all();
        ctrl_barrier();
 }
 
index 004bb3f25b5f5f7e080505e967fea140328d480b..77dc5efa712718552d3de59d8104a56a0cea67a9 100644 (file)
@@ -123,18 +123,27 @@ void local_flush_tlb_mm(struct mm_struct *mm)
 void local_flush_tlb_all(void)
 {
        unsigned long flags, status;
+       int i;
 
        /*
         * Flush all the TLB.
-        *
-        * Write to the MMU control register's bit:
-        *      TF-bit for SH-3, TI-bit for SH-4.
-        *      It's same position, bit #2.
         */
        local_irq_save(flags);
+       jump_to_uncached();
+
        status = __raw_readl(MMUCR);
-       status |= 0x04;
-       __raw_writel(status, MMUCR);
+       status = ((status & MMUCR_URB) >> MMUCR_URB_SHIFT);
+
+       if (status == 0)
+               status = MMUCR_URB_NENTRIES;
+
+       for (i = 0; i < status; i++)
+               __raw_writel(0x0, MMU_UTLB_ADDRESS_ARRAY | (i << 8));
+
+       for (i = 0; i < 4; i++)
+               __raw_writel(0x0, MMU_ITLB_ADDRESS_ARRAY | (i << 8));
+
+       back_to_cached();
        ctrl_barrier();
        local_irq_restore(flags);
 }