Commit b50bb8ba authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Vinod Koul

soundwire: bus: handle -ENODATA errors in clock stop/start sequences

If a device lost sync and can no longer ACK a command, it may not be
able to enter a lower-power state but it will still be able to resync
when the clock restarts. In those cases, we want to continue with the
clock stop sequence.

This patch modifies the behavior during clock stop sequences to only
log errors unrelated to -ENODATA/Command_Ignored. The flow is also
modified so that loops continue to prepare/deprepare other devices
even when one seems to have lost sync.

When resuming the clocks, all issues are logged with a dev_warn(),
previously only some of them were checked. This is the only part that
now differs between the clock stop entry and clock stop exit
sequences: while we don't want to stop the suspend flow, we do want
information on potential issues while resuming, as they may have
ripple effects.

For consistency the log messages are also modified to be unique and
self-explanatory. Errors in sdw_slave_clk_stop_callback() were
removed, they are now handled in the caller.
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: default avatarRander Wang <rander.wang@intel.com>
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20210511030048.25622-4-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 448df2d8
...@@ -829,11 +829,8 @@ static int sdw_slave_clk_stop_callback(struct sdw_slave *slave, ...@@ -829,11 +829,8 @@ static int sdw_slave_clk_stop_callback(struct sdw_slave *slave,
if (slave->ops && slave->ops->clk_stop) { if (slave->ops && slave->ops->clk_stop) {
ret = slave->ops->clk_stop(slave, mode, type); ret = slave->ops->clk_stop(slave, mode, type);
if (ret < 0) { if (ret < 0)
dev_err(&slave->dev,
"Clk Stop type =%d failed: %d\n", type, ret);
return ret; return ret;
}
} }
return 0; return 0;
...@@ -860,7 +857,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, ...@@ -860,7 +857,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
} else { } else {
ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL);
if (ret < 0) { if (ret < 0) {
dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret); if (ret != -ENODATA)
dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret);
return ret; return ret;
} }
val = ret; val = ret;
...@@ -869,9 +867,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, ...@@ -869,9 +867,8 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val);
if (ret < 0) if (ret < 0 && ret != -ENODATA)
dev_err(&slave->dev, dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL write failed:%d\n", ret);
"Clock Stop prepare failed for slave: %d", ret);
return ret; return ret;
} }
...@@ -922,6 +919,9 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -922,6 +919,9 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
* In order to save on transition time, prepare * In order to save on transition time, prepare
* each Slave and then wait for all Slave(s) to be * each Slave and then wait for all Slave(s) to be
* prepared for clock stop. * prepared for clock stop.
* If one of the Slave devices has lost sync and
* replies with Command Ignored/-ENODATA, we continue
* the loop
*/ */
list_for_each_entry(slave, &bus->slaves, node) { list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num) if (!slave->dev_num)
...@@ -937,9 +937,8 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -937,9 +937,8 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
ret = sdw_slave_clk_stop_callback(slave, ret = sdw_slave_clk_stop_callback(slave,
SDW_CLK_STOP_MODE0, SDW_CLK_STOP_MODE0,
SDW_CLK_PRE_PREPARE); SDW_CLK_PRE_PREPARE);
if (ret < 0) { if (ret < 0 && ret != -ENODATA) {
dev_err(&slave->dev, dev_err(&slave->dev, "clock stop pre-prepare cb failed:%d\n", ret);
"pre-prepare failed:%d", ret);
return ret; return ret;
} }
...@@ -950,9 +949,8 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -950,9 +949,8 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
ret = sdw_slave_clk_stop_prepare(slave, ret = sdw_slave_clk_stop_prepare(slave,
SDW_CLK_STOP_MODE0, SDW_CLK_STOP_MODE0,
true); true);
if (ret < 0) { if (ret < 0 && ret != -ENODATA) {
dev_err(&slave->dev, dev_err(&slave->dev, "clock stop prepare failed:%d\n", ret);
"pre-prepare failed:%d", ret);
return ret; return ret;
} }
} }
...@@ -960,7 +958,7 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -960,7 +958,7 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
/* Skip remaining clock stop preparation if no Slave is attached */ /* Skip remaining clock stop preparation if no Slave is attached */
if (!is_slave) if (!is_slave)
return ret; return 0;
/* /*
* Don't wait for all Slaves to be ready if they follow the simple * Don't wait for all Slaves to be ready if they follow the simple
...@@ -969,6 +967,12 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -969,6 +967,12 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
if (!simple_clk_stop) { if (!simple_clk_stop) {
ret = sdw_bus_wait_for_clk_prep_deprep(bus, ret = sdw_bus_wait_for_clk_prep_deprep(bus,
SDW_BROADCAST_DEV_NUM); SDW_BROADCAST_DEV_NUM);
/*
* if there are no Slave devices present and the reply is
* Command_Ignored/-ENODATA, we don't need to continue with the
* flow and can just return here. The error code is not modified
* and its handling left as an exercise for the caller.
*/
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -986,13 +990,13 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) ...@@ -986,13 +990,13 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus)
SDW_CLK_STOP_MODE0, SDW_CLK_STOP_MODE0,
SDW_CLK_POST_PREPARE); SDW_CLK_POST_PREPARE);
if (ret < 0) { if (ret < 0 && ret != -ENODATA) {
dev_err(&slave->dev, dev_err(&slave->dev, "clock stop post-prepare cb failed:%d\n", ret);
"post-prepare failed:%d", ret); return ret;
} }
} }
return ret; return 0;
} }
EXPORT_SYMBOL(sdw_bus_prep_clk_stop); EXPORT_SYMBOL(sdw_bus_prep_clk_stop);
...@@ -1015,12 +1019,8 @@ int sdw_bus_clk_stop(struct sdw_bus *bus) ...@@ -1015,12 +1019,8 @@ int sdw_bus_clk_stop(struct sdw_bus *bus)
ret = sdw_bwrite_no_pm(bus, SDW_BROADCAST_DEV_NUM, ret = sdw_bwrite_no_pm(bus, SDW_BROADCAST_DEV_NUM,
SDW_SCP_CTRL, SDW_SCP_CTRL_CLK_STP_NOW); SDW_SCP_CTRL, SDW_SCP_CTRL_CLK_STP_NOW);
if (ret < 0) { if (ret < 0) {
if (ret == -ENODATA) if (ret != -ENODATA)
dev_dbg(bus->dev, dev_err(bus->dev, "ClockStopNow Broadcast msg failed %d\n", ret);
"ClockStopNow Broadcast msg ignored %d", ret);
else
dev_err(bus->dev,
"ClockStopNow Broadcast msg failed %d", ret);
return ret; return ret;
} }
...@@ -1063,8 +1063,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) ...@@ -1063,8 +1063,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0, ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
SDW_CLK_PRE_DEPREPARE); SDW_CLK_PRE_DEPREPARE);
if (ret < 0) if (ret < 0)
dev_warn(&slave->dev, dev_warn(&slave->dev, "clock stop pre-deprepare cb failed:%d\n", ret);
"clk stop deprep failed:%d", ret);
/* Only de-prepare a Slave device if needed */ /* Only de-prepare a Slave device if needed */
if (!slave->prop.simple_clk_stop_capable) { if (!slave->prop.simple_clk_stop_capable) {
...@@ -1074,8 +1073,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) ...@@ -1074,8 +1073,7 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
false); false);
if (ret < 0) if (ret < 0)
dev_warn(&slave->dev, dev_warn(&slave->dev, "clock stop deprepare failed:%d\n", ret);
"clk stop deprep failed:%d", ret);
} }
} }
...@@ -1087,8 +1085,11 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) ...@@ -1087,8 +1085,11 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
* Don't wait for all Slaves to be ready if they follow the simple * Don't wait for all Slaves to be ready if they follow the simple
* state machine * state machine
*/ */
if (!simple_clk_stop) if (!simple_clk_stop) {
sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM); ret = sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM);
if (ret < 0)
dev_warn(&slave->dev, "clock stop deprepare wait failed:%d\n", ret);
}
list_for_each_entry(slave, &bus->slaves, node) { list_for_each_entry(slave, &bus->slaves, node) {
if (!slave->dev_num) if (!slave->dev_num)
...@@ -1098,8 +1099,10 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) ...@@ -1098,8 +1099,10 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus)
slave->status != SDW_SLAVE_ALERT) slave->status != SDW_SLAVE_ALERT)
continue; continue;
sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0, ret = sdw_slave_clk_stop_callback(slave, SDW_CLK_STOP_MODE0,
SDW_CLK_POST_DEPREPARE); SDW_CLK_POST_DEPREPARE);
if (ret < 0)
dev_warn(&slave->dev, "clock stop post-deprepare cb failed:%d\n", ret);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment