Re: [PATCH] i2c: jz4780: Cache clock rate at probe to prevent CCF prepare_lock deadlock
"H. Nikolaus Schaller" <[email protected]> Sun, 19 Jul 2026 17:38:15 +0200
| Newsgroups | org.kernel.vger.linux-mips,org.kernel.vger.linux-i2c,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
> Am 19.07.2026 um 17:07 schrieb Paul Cercueil <[email protected]>: > > Hi Nikolaus, > > Le vendredi 10 juillet 2026 à 08:58 +0200, H. Nikolaus Schaller a > écrit : >> Fix a severe AB/BA deadlock between the Common Clock Framework (CCF) >> and the I2C adapter lock, which triggers when an I2C-controlled clock >> generator (like the Si5351) is registered or modified under the CCF. >> >> During a clock frequency change, the CCF acquires its global >> 'prepare_lock' >> mutex and calls i2c_transfer() to update the chip registers, stalling >> for the adapter's I2C bus lock. >> >> Concurrently, a parallel transfer on the same bus (e.g., a GPIO >> expander >> handling LEDs) can hold the I2C adapter lock. Inside the transfer >> path, >> jz4780_i2c_set_speed() calls clk_get_rate() to dynamically calculate >> timings. This call attempts to acquire the blocked CCF >> 'prepare_lock', >> creating a circular dependency that freezes the system or at least >> the involved processes and workers. >> >> Eliminate the synchronous clk_get_rate() call from the active >> transfer >> path by caching the peripheral clock rate once - inside the private >> jz4780_i2c structure during jz4780_i2c_probe(). Update >> jz4780_i2c_set_speed() to use this cached value, decoupling active >> I2C >> transactions from the CCF internal locks. >> >> Assisted-by web based Google AI. >> >> Fixes: ba92222ed63a12 ("i2c: jz4780: Add i2c bus controller driver >> for Ingenic JZ4780") >> Cc: [email protected] >> Signed-off-by: H. Nikolaus Schaller <[email protected]> >> --- >> drivers/i2c/busses/i2c-jz4780.c | 5 ++++- >> 1 file changed, 4 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/i2c/busses/i2c-jz4780.c >> b/drivers/i2c/busses/i2c-jz4780.c >> index 664a5471d9335..d729cec9cdf2c 100644 >> --- a/drivers/i2c/busses/i2c-jz4780.c >> +++ b/drivers/i2c/busses/i2c-jz4780.c >> @@ -141,6 +141,7 @@ struct jz4780_i2c { >> void __iomem *iomem; >> int irq; >> struct clk *clk; >> + unsigned long clk_rate; > > That's a weird spacing. Should probably be "unsigned long" on the left > side. indeed a typo - should be TAB unsigned long TAB clk_rate; Interestingly checkpatch.pl did not complain... > >> struct i2c_adapter adap; >> const struct ingenic_i2c_config *cdata; >> >> @@ -246,7 +247,7 @@ static int jz4780_i2c_set_target(struct >> jz4780_i2c *i2c, unsigned char address) >> >> static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c) >> { >> - int dev_clk_khz = clk_get_rate(i2c->clk) / 1000; >> + int dev_clk_khz = i2c->clk_rate / 1000; > > You cache `i2c->clk_rate` but only use it divided by 1000, so maybe > cache `clk_rate_khz` instead? Yes, that is more precise. I can update and send a V2 with a revised commit message. BR and thanks, Nikolaus