Skip to content

Commit

Permalink
ARM: 6987/1: l2x0: fix disabling function to avoid deadlock
Browse files Browse the repository at this point in the history
The l2x0_disable function attempts to writel with the l2x0_lock held.
This results in deadlock when the writel contains an outer_sync call
for the platform since the l2x0_lock is already held by the disable
function. A further problem is that disabling the L2 without flushing it
first can lead to the spin_lock operation becoming visible after the
spin_unlock, causing any subsequent L2 maintenance to deadlock.

This patch replaces the writel with a call to writel_relaxed in the
disabling code and adds a flush before disabling in the control
register, preventing livelock from occurring.

Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Will Deacon authored and Russell King committed Jul 6, 2011
1 parent 186dcaa commit 38a8914
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions arch/arm/mm/cache-l2x0.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,22 @@ static void l2x0_cache_sync(void)
spin_unlock_irqrestore(&l2x0_lock, flags);
}

static void l2x0_flush_all(void)
static void __l2x0_flush_all(void)
{
unsigned long flags;

/* clean all ways */
spin_lock_irqsave(&l2x0_lock, flags);
debug_writel(0x03);
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
cache_sync();
debug_writel(0x00);
}

static void l2x0_flush_all(void)
{
unsigned long flags;

/* clean all ways */
spin_lock_irqsave(&l2x0_lock, flags);
__l2x0_flush_all();
spin_unlock_irqrestore(&l2x0_lock, flags);
}

Expand Down Expand Up @@ -266,7 +271,9 @@ static void l2x0_disable(void)
unsigned long flags;

spin_lock_irqsave(&l2x0_lock, flags);
writel(0, l2x0_base + L2X0_CTRL);
__l2x0_flush_all();
writel_relaxed(0, l2x0_base + L2X0_CTRL);
dsb();
spin_unlock_irqrestore(&l2x0_lock, flags);
}

Expand Down

0 comments on commit 38a8914

Please sign in to comment.