Skip to content

Commit e1bbcb2

Browse files
committed
soundwire: stream: restore bus_params of each bus
Restore_params restores bus->params and bus->bpt_hstop from single backups that are overwritten in the first master_list loop. If failure happens later (e.g. do_bank_switch() or port prepare in the second loop), the current bus may not match the saved snapshot, so multi-link streams can restore the wrong state into the wrong bus and leave other buses partially reconfigured. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
1 parent 91aa327 commit e1bbcb2

1 file changed

Lines changed: 38 additions & 4 deletions

File tree

drivers/soundwire/stream.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,19 +1479,37 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
14791479
struct sdw_master_runtime *m_rt;
14801480
struct sdw_bus *bus;
14811481
struct sdw_master_prop *prop;
1482-
struct sdw_bus_params params;
14831482
int ret;
14841483

1484+
/* Local structure to store backup params for error recovery */
1485+
struct {
1486+
struct list_head list_node;
1487+
struct sdw_bus *bus;
1488+
struct sdw_bus_params params;
1489+
} *params_entry, *temp_entry;
1490+
1491+
LIST_HEAD(params_backup_list);
1492+
14851493
/* Prepare Master(s) and Slave(s) port(s) associated with stream */
14861494
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
14871495
bus = m_rt->bus;
14881496
prop = &bus->prop;
1489-
memcpy(&params, &bus->params, sizeof(params));
1497+
1498+
/* Allocate and save current params for error recovery */
1499+
params_entry = kzalloc_obj(*params_entry);
1500+
if (!params_entry) {
1501+
ret = -ENOMEM;
1502+
goto restore_params;
1503+
}
1504+
params_entry->bus = bus;
1505+
memcpy(&params_entry->params, &bus->params, sizeof(params_entry->params));
1506+
list_add_tail(&params_entry->list_node, &params_backup_list);
14901507

14911508
/* TODO: Support Asynchronous mode */
14921509
if ((prop->max_clk_freq % stream->params.rate) != 0) {
14931510
dev_err(bus->dev, "Async mode not supported\n");
1494-
return -EINVAL;
1511+
ret = -EINVAL;
1512+
goto restore_params;
14951513
}
14961514

14971515
if (update_params) {
@@ -1539,10 +1557,26 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
15391557

15401558
stream->state = SDW_STREAM_PREPARED;
15411559

1560+
/* Free the backup list on success */
1561+
list_for_each_entry_safe(params_entry, temp_entry, &params_backup_list, list_node) {
1562+
list_del(&params_entry->list_node);
1563+
kfree(params_entry);
1564+
}
1565+
15421566
return ret;
15431567

15441568
restore_params:
1545-
memcpy(&bus->params, &params, sizeof(params));
1569+
/* Restore all bus params from the backup list */
1570+
list_for_each_entry(params_entry, &params_backup_list, list_node) {
1571+
memcpy(&params_entry->bus->params, &params_entry->params,
1572+
sizeof(params_entry->params));
1573+
}
1574+
1575+
/* Free the backup list on error */
1576+
list_for_each_entry_safe(params_entry, temp_entry, &params_backup_list, list_node) {
1577+
list_del(&params_entry->list_node);
1578+
kfree(params_entry);
1579+
}
15461580
return ret;
15471581
}
15481582

0 commit comments

Comments
 (0)