diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-03-15 19:08:11 +0000 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2014-05-30 00:48:19 +0100 |
commit | ebd4219f10fbe3938cd36443e240eb6076b811ab (patch) | |
tree | b5f33dcf501072d11a593962ef7b70b88db2b1cb /arch/arm/mm | |
parent | 99ca1772e52d8825172100a24e461a0ffe11e125 (diff) |
ARM: l2c: implement L2C-310 erratum 588369 as a method override
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>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r-- | arch/arm/mm/cache-l2x0.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 6161232c8a8..79ff08db204 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -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) { |