mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
sdhci: Do not reprogram an unchanged clock
sdhci_set_clock() compared the requested clock with slot->clock, which holds the rate that the host driver actually applied. Some drivers do not apply the requested rate: the RK3568 one maps the 400kHz identification frequency to 375kHz. The two values then never match and every update_ios call goes through SDHCI_SET_CLOCK() again, even when the clock did not change. That ends in clk_set_freq(), which takes a sleepable lock, from the done context of the mmc probe with the CAM locks held. With another thread holding the clock topology lock this panics with "sleeping thread holds CAM device lock". Remember the last requested clock in a new field and compare against it. Clear it wherever slot->clock is cleared so that a reset still forces an update. Tested on a Quartz64 Model A with an NVMe drive on the PCIe slot, where the panic was seen: 5 cold boots out of 5 attached everything. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D61012
This commit is contained in:
1 parent
40363144e8
commit
3e9ff26d2a
2 files changed
+5
-1
No files matched your search
@@ -416,8 +416,9 @@ sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
|
||||
uint16_t div;
|
||||
int timeout;
|
||||
|
||||
if (clock == slot->clock)
|
||||
if (clock == slot->req_clock)
|
||||
return;
|
||||
slot->req_clock = clock;
|
||||
clock = SDHCI_SET_CLOCK(slot->bus, slot, clock);
|
||||
slot->clock = clock;
|
||||
|
||||
@@ -1275,11 +1276,13 @@ sdhci_generic_reset(device_t brdev __unused, struct sdhci_slot *slot,
|
||||
/* This is to force an update */
|
||||
clock = slot->clock;
|
||||
slot->clock = 0;
|
||||
slot->req_clock = 0;
|
||||
sdhci_set_clock(slot, clock);
|
||||
}
|
||||
|
||||
if (mask & SDHCI_RESET_ALL) {
|
||||
slot->clock = 0;
|
||||
slot->req_clock = 0;
|
||||
slot->power = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,6 +392,7 @@ struct sdhci_slot {
|
||||
uint32_t retune_ticks; /* Re-tuning callout ticks [hz] */
|
||||
uint32_t intmask; /* Current interrupt mask */
|
||||
uint32_t clock; /* Current clock freq. */
|
||||
uint32_t req_clock; /* Last requested clock freq. */
|
||||
size_t offset; /* Data buffer offset */
|
||||
uint8_t hostctrl; /* Current host control register */
|
||||
uint8_t retune_count; /* Controller re-tuning count [s] */
|
||||
|
||||
Reference in new issue
Block a user