Skip to content

Commit 4729f0c

Browse files
committed
fuspi: Fix 'sleepable after non-sleepable' lock
With WITNESS enabled we see the following warning: lock order reversal: (sleepable after non-sleepable) 1st 0xffffffd0847c7210 fu540spi0 (fu540spi0) @ /usr/home/kp/axiado/hornet-freebsd/src/sys/riscv/sifive/fu540_spi.c:297 2nd 0xffffffc00372bb30 Clock topology lock (Clock topology lock) @ /usr/home/kp/axiado/hornet-freebsd/src/sys/dev/extres/clk/clk.c:1137 stack backtrace: #0 0xffffffc0002a579e at witness_checkorder+0xb72 #1 0xffffffc0002a5556 at witness_checkorder+0x92a #2 0xffffffc000254c7a at _sx_slock_int+0x66 #3 0xffffffc00025537a at _sx_slock+0x8 #4 0xffffffc000123022 at clk_get_freq+0x38 #5 0xffffffc0005463e4 at __clzdi2+0x2bb8 #6 0xffffffc00014af58 at randomdev_getkey+0x76e #7 0xffffffc0001278b0 at simplebus_add_device+0x7ee #8 0xffffffc00027c9a8 at device_attach+0x2e6 #9 0xffffffc00027c634 at device_probe_and_attach+0x7a #10 0xffffffc00027d76a at bus_generic_attach+0x10 #11 0xffffffc00014aab0 at randomdev_getkey+0x2c6 #12 0xffffffc00027c9a8 at device_attach+0x2e6 #13 0xffffffc00027c634 at device_probe_and_attach+0x7a #14 0xffffffc00027d76a at bus_generic_attach+0x10 #15 0xffffffc000278bd2 at config_intrhook_oneshot+0x52 #16 0xffffffc000278b3e at config_intrhook_establish+0x146 #17 0xffffffc000278cf2 at config_intrhook_disestablish+0xfe The clock topology lock can sleep, which means we cannot attempt to acquire it while holding the non-sleepable mutex. Fix that by retrieving the clock speed once, during attach and not every time during SPI transaction setup. Submitted by: kp Sponsored by: Axiado
1 parent 52c9404 commit 4729f0c

File tree

1 file changed

+8
-9
lines changed

1 file changed

+8
-9
lines changed

sys/riscv/sifive/fu540_spi.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct fuspi_softc {
8080
void *ih;
8181

8282
clk_t clk;
83+
uint64_t freq;
8384
uint32_t cs_max;
8485
};
8586

@@ -207,22 +208,14 @@ fuspi_setup(struct fuspi_softc *sc, uint32_t cs, uint32_t mode,
207208
uint32_t freq)
208209
{
209210
uint32_t csmode, fmt, sckdiv, sckmode;
210-
uint64_t clock;
211-
int ret;
212211

213212
FUSPI_ASSERT_LOCKED(sc);
214213

215-
ret = clk_get_freq(sc->clk, &clock);
216-
if (ret) {
217-
device_printf(sc->dev, "Cannot get clock frequency: %d\n", ret);
218-
return (ret);
219-
}
220-
221214
/*
222215
* Fsck = Fin / 2 * (div + 1)
223216
* -> div = Fin / (2 * Fsck) - 1
224217
*/
225-
sckdiv = (howmany(clock >> 1, freq) - 1) & FUSPI_SCKDIV_MASK;
218+
sckdiv = (howmany(sc->freq >> 1, freq) - 1) & FUSPI_SCKDIV_MASK;
226219
FUSPI_WRITE(sc, FUSPI_REG_SCKDIV, sckdiv);
227220

228221
switch (mode) {
@@ -331,6 +324,12 @@ fuspi_attach(device_t dev)
331324
goto fail;
332325
}
333326

327+
error = clk_get_freq(sc->clk, &sc->freq);
328+
if (error) {
329+
device_printf(sc->dev, "Couldn't get frequency: %d\n", error);
330+
goto fail;
331+
}
332+
334333
/*
335334
* From Sifive-Unleashed-FU540-C000-v1.0.pdf page 103:
336335
* csdef is cs_width bits wide and all ones on reset.

0 commit comments

Comments
 (0)