Skip to content

Commit e1f1ae8

Browse files
geertubebarino
authored andcommitted
clk: renesas: cpg-mssr: Fix reset control race condition
The module reset code in the Renesas CPG/MSSR driver uses read-modify-write (RMW) operations to write to a Software Reset Register (SRCRn), and simple writes to write to a Software Reset Clearing Register (SRSTCLRn), as was mandated by the R-Car Gen2 and Gen3 Hardware User's Manuals. However, this may cause a race condition when two devices are reset in parallel: if the reset for device A completes in the middle of the RMW operation for device B, device A may be reset again, causing subtle failures (e.g. i2c timeouts): thread A thread B -------- -------- val = SRCRn val |= bit A SRCRn = val delay val = SRCRn (bit A is set) SRSTCLRn = bit A (bit A in SRCRn is cleared) val |= bit B SRCRn = val (bit A and B are set) This can be reproduced on e.g. Salvator-XS using: $ while true; do i2cdump -f -y 4 0x6A b > /dev/null; done & $ while true; do i2cdump -f -y 2 0x10 b > /dev/null; done & i2c-rcar e6510000.i2c: error -110 : 40000002 i2c-rcar e66d800.i2c: error -110 : 40000002 According to the R-Car Gen3 Hardware Manual Errata for Rev. 0.80 of Feb 28, 2018, reflected in Rev. 1.00 of the R-Car Gen3 Hardware User's Manual, writes to SRCRn do not require read-modify-write cycles. Note that the R-Car Gen2 Hardware User's Manual has not been updated yet, and still says a read-modify-write sequence is required. According to the hardware team, the reset hardware block is the same on both R-Car Gen2 and Gen3, though. Hence fix the issue by replacing the read-modify-write operations on SRCRn by simple writes. Reported-by: Yao Lihua <[email protected]> Fixes: 6197aa6 ("clk: renesas: cpg-mssr: Add support for reset control") Signed-off-by: Geert Uytterhoeven <[email protected]> Tested-by: Linh Phung <[email protected]> Signed-off-by: Stephen Boyd <[email protected]>
1 parent c9a67cb commit e1f1ae8

File tree

1 file changed

+2
-14
lines changed

1 file changed

+2
-14
lines changed

drivers/clk/renesas/renesas-cpg-mssr.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -572,17 +572,11 @@ static int cpg_mssr_reset(struct reset_controller_dev *rcdev,
572572
unsigned int reg = id / 32;
573573
unsigned int bit = id % 32;
574574
u32 bitmask = BIT(bit);
575-
unsigned long flags;
576-
u32 value;
577575

578576
dev_dbg(priv->dev, "reset %u%02u\n", reg, bit);
579577

580578
/* Reset module */
581-
spin_lock_irqsave(&priv->rmw_lock, flags);
582-
value = readl(priv->base + SRCR(reg));
583-
value |= bitmask;
584-
writel(value, priv->base + SRCR(reg));
585-
spin_unlock_irqrestore(&priv->rmw_lock, flags);
579+
writel(bitmask, priv->base + SRCR(reg));
586580

587581
/* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */
588582
udelay(35);
@@ -599,16 +593,10 @@ static int cpg_mssr_assert(struct reset_controller_dev *rcdev, unsigned long id)
599593
unsigned int reg = id / 32;
600594
unsigned int bit = id % 32;
601595
u32 bitmask = BIT(bit);
602-
unsigned long flags;
603-
u32 value;
604596

605597
dev_dbg(priv->dev, "assert %u%02u\n", reg, bit);
606598

607-
spin_lock_irqsave(&priv->rmw_lock, flags);
608-
value = readl(priv->base + SRCR(reg));
609-
value |= bitmask;
610-
writel(value, priv->base + SRCR(reg));
611-
spin_unlock_irqrestore(&priv->rmw_lock, flags);
599+
writel(bitmask, priv->base + SRCR(reg));
612600
return 0;
613601
}
614602

0 commit comments

Comments
 (0)