Skip to content

Commit fe63a7d

Browse files
ujfalusibardliao
authored andcommitted
Fixup: soundwire: bus: add CLOCK_STOP_MODE1 support back
sdw_get_clk_stop_mode() converts slave->dev.driver with drv_to_sdw_driver() and dereferences the result unconditionally. A Peripheral can be attached and enumerated on the bus while it has no driver bound to it, for example after its codec driver module has been removed, and in that case slave->dev.driver is NULL. sdw_bus_prep_clk_stop() walks every Peripheral which has a device number and is in ATTACHED or ALERT state, so the Manager's runtime suspend reaches such an unbound Peripheral and the container_of() arithmetic turns the NULL pointer into a small negative offset: BUG: unable to handle page fault for address: fffffffffffffff8 RIP: 0010:sdw_bus_prep_clk_stop+0x93/0x1d0 [soundwire_bus] Call Trace: sdw_cdns_clock_stop+0xbe/0x1d0 [soundwire_cadence] intel_stop_bus+0xc1/0x100 [soundwire_intel] intel_suspend_runtime+0x7b/0x160 [soundwire_intel] __rpm_callback+0x57/0x210 rpm_suspend+0xfc/0x660 pm_runtime_work+0xa4/0xb0 Take sdw_dev_lock and check slave->probed before looking at the driver, the same way sdw_slave_clk_stop_callback() and the other clock stop helpers do, and fall back to the mode advertised by the Peripheral property when no driver is bound. Fixes: 922ebc4 ("soundwire: bus: add CLOCK_STOP_MODE1 support back") Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 60efcc4 commit fe63a7d

1 file changed

Lines changed: 14 additions & 5 deletions

File tree

drivers/soundwire/bus.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -957,17 +957,26 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
957957

958958
static enum sdw_clk_stop_mode sdw_get_clk_stop_mode(struct sdw_slave *slave)
959959
{
960-
struct device *dev = &slave->dev;
961-
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
960+
enum sdw_clk_stop_mode mode;
961+
962+
mode = slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0;
963+
964+
mutex_lock(&slave->sdw_dev_lock);
962965

963966
/*
964967
* Query for clock stop mode if Slave implements
965968
* ops->get_clk_stop_mode, else read from property.
966969
*/
967-
if (drv->ops && drv->ops->get_clk_stop_mode)
968-
return drv->ops->get_clk_stop_mode(slave);
970+
if (slave->probed) {
971+
struct sdw_driver *drv = drv_to_sdw_driver(slave->dev.driver);
972+
973+
if (drv->ops && drv->ops->get_clk_stop_mode)
974+
mode = drv->ops->get_clk_stop_mode(slave);
975+
}
976+
977+
mutex_unlock(&slave->sdw_dev_lock);
969978

970-
return slave->prop.clk_stop_mode1 ? SDW_CLK_STOP_MODE1 : SDW_CLK_STOP_MODE0;
979+
return mode;
971980
}
972981

973982
static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,

0 commit comments

Comments
 (0)