ARM: l2c: implement L2C-310 erratum 588369 as a method override
authorRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 15 Mar 2014 19:08:11 +0000 (19:08 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 29 May 2014 23:48:19 +0000 (00:48 +0100)
Implement L2C-310 erratum 588369 by overriding the invalidate range
and flush range methods in the outer_cache operations structure.
This allows us to sensibly contain the erratum code in one place
without affecting other locations/implemetations.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mm/cache-l2x0.c

index 6161232c8a850f46268dadfd73ee3dd28aa9578c..79ff08db204d97c161d1032e2d14f7a1d1c9d497 100644 (file)
@@ -522,6 +522,65 @@ static void l2c310_set_debug(unsigned long val)
        writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
 }
 
+static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
+{
+       void __iomem *base = l2x0_base;
+
+       if ((start | end) & (CACHE_LINE_SIZE - 1)) {
+               unsigned long flags;
+
+               /* Erratum 588369 for both clean+invalidate operations */
+               raw_spin_lock_irqsave(&l2x0_lock, flags);
+               l2c_set_debug(base, 0x03);
+
+               if (start & (CACHE_LINE_SIZE - 1)) {
+                       start &= ~(CACHE_LINE_SIZE - 1);
+                       writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
+                       writel_relaxed(start, base + L2X0_INV_LINE_PA);
+                       start += CACHE_LINE_SIZE;
+               }
+
+               if (end & (CACHE_LINE_SIZE - 1)) {
+                       end &= ~(CACHE_LINE_SIZE - 1);
+                       writel_relaxed(end, base + L2X0_CLEAN_LINE_PA);
+                       writel_relaxed(end, base + L2X0_INV_LINE_PA);
+               }
+
+               l2c_set_debug(base, 0x00);
+               raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+       }
+
+       __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
+       __l2c210_cache_sync(base);
+}
+
+static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)
+{
+       raw_spinlock_t *lock = &l2x0_lock;
+       unsigned long flags;
+       void __iomem *base = l2x0_base;
+
+       raw_spin_lock_irqsave(lock, flags);
+       while (start < end) {
+               unsigned long blk_end = start + min(end - start, 4096UL);
+
+               l2c_set_debug(base, 0x03);
+               while (start < blk_end) {
+                       writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
+                       writel_relaxed(start, base + L2X0_INV_LINE_PA);
+                       start += CACHE_LINE_SIZE;
+               }
+               l2c_set_debug(base, 0x00);
+
+               if (blk_end < end) {
+                       raw_spin_unlock_irqrestore(lock, flags);
+                       raw_spin_lock_irqsave(lock, flags);
+               }
+       }
+       raw_spin_unlock_irqrestore(lock, flags);
+       __l2c210_cache_sync(base);
+}
+
 static void l2c310_flush_all_erratum(void)
 {
        void __iomem *base = l2x0_base;
@@ -600,9 +659,19 @@ static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
        const char *errata[4];
        unsigned n = 0;
 
+       /* For compatibility */
        if (revision <= L310_CACHE_ID_RTL_R3P0)
                fns->set_debug = l2c310_set_debug;
 
+       if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
+           revision < L310_CACHE_ID_RTL_R2P0 &&
+           /* For bcm compatibility */
+           fns->inv_range == l2x0_inv_range) {
+               fns->inv_range = l2c310_inv_range_erratum;
+               fns->flush_range = l2c310_flush_range_erratum;
+               errata[n++] = "588369";
+       }
+
        if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) &&
            revision >= L310_CACHE_ID_RTL_R2P0 &&
            revision < L310_CACHE_ID_RTL_R3P1) {