mmc: fix a race between card-detect rescan and clock-gate work instances

Currently there is a race in the MMC core between a card-detect
rescan work and the clock-gating work, scheduled from a command
completion. Fix it by removing the dedicated clock-gating mutex
and using the MMC standard locking mechanism instead.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Cc: Simon Horman <horms@verge.net.au>
Cc: Magnus Damm <damm@opensource.se>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Cc: <stable@kernel.org>
Signed-off-by: Chris Ball <cjb@laptop.org>

authored by Guennadi Liakhovetski and committed by Chris Ball 26fc8775 f6947514

+4 -6
+4 -5
drivers/mmc/core/host.c
··· 94 spin_unlock_irqrestore(&host->clk_lock, flags); 95 return; 96 } 97 - mutex_lock(&host->clk_gate_mutex); 98 spin_lock_irqsave(&host->clk_lock, flags); 99 if (!host->clk_requests) { 100 spin_unlock_irqrestore(&host->clk_lock, flags); ··· 104 pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); 105 } 106 spin_unlock_irqrestore(&host->clk_lock, flags); 107 - mutex_unlock(&host->clk_gate_mutex); 108 } 109 110 /* ··· 130 { 131 unsigned long flags; 132 133 - mutex_lock(&host->clk_gate_mutex); 134 spin_lock_irqsave(&host->clk_lock, flags); 135 if (host->clk_gated) { 136 spin_unlock_irqrestore(&host->clk_lock, flags); ··· 140 } 141 host->clk_requests++; 142 spin_unlock_irqrestore(&host->clk_lock, flags); 143 - mutex_unlock(&host->clk_gate_mutex); 144 } 145 146 /** ··· 215 host->clk_gated = false; 216 INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); 217 spin_lock_init(&host->clk_lock); 218 - mutex_init(&host->clk_gate_mutex); 219 } 220 221 /**
··· 94 spin_unlock_irqrestore(&host->clk_lock, flags); 95 return; 96 } 97 + mmc_claim_host(host); 98 spin_lock_irqsave(&host->clk_lock, flags); 99 if (!host->clk_requests) { 100 spin_unlock_irqrestore(&host->clk_lock, flags); ··· 104 pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); 105 } 106 spin_unlock_irqrestore(&host->clk_lock, flags); 107 + mmc_release_host(host); 108 } 109 110 /* ··· 130 { 131 unsigned long flags; 132 133 + mmc_claim_host(host); 134 spin_lock_irqsave(&host->clk_lock, flags); 135 if (host->clk_gated) { 136 spin_unlock_irqrestore(&host->clk_lock, flags); ··· 140 } 141 host->clk_requests++; 142 spin_unlock_irqrestore(&host->clk_lock, flags); 143 + mmc_release_host(host); 144 } 145 146 /** ··· 215 host->clk_gated = false; 216 INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); 217 spin_lock_init(&host->clk_lock); 218 } 219 220 /**
-1
include/linux/mmc/host.h
··· 183 struct work_struct clk_gate_work; /* delayed clock gate */ 184 unsigned int clk_old; /* old clock value cache */ 185 spinlock_t clk_lock; /* lock for clk fields */ 186 - struct mutex clk_gate_mutex; /* mutex for clock gating */ 187 #endif 188 189 /* host specific block data */
··· 183 struct work_struct clk_gate_work; /* delayed clock gate */ 184 unsigned int clk_old; /* old clock value cache */ 185 spinlock_t clk_lock; /* lock for clk fields */ 186 #endif 187 188 /* host specific block data */