Commit c40d6b32 authored by Johan Hovold's avatar Johan Hovold Committed by Vinod Koul

soundwire: fix enumeration completion

The soundwire subsystem uses two completion structures that allow
drivers to wait for soundwire device to become enumerated on the bus and
initialised by their drivers, respectively.

The code implementing the signalling is currently broken as it does not
signal all current and future waiters and also uses the wrong
reinitialisation function, which can potentially lead to memory
corruption if there are still waiters on the queue.

Not signalling future waiters specifically breaks sound card probe
deferrals as codec drivers can not tell that the soundwire device is
already attached when being reprobed. Some codec runtime PM
implementations suffer from similar problems as waiting for enumeration
during resume can also timeout despite the device already having been
enumerated.

Fixes: fb9469e5 ("soundwire: bus: fix race condition with enumeration_complete signaling")
Fixes: a90def06 ("soundwire: bus: fix race condition with initialization_complete signaling")
Cc: stable@vger.kernel.org      # 5.7
Cc: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Cc: Rander Wang <rander.wang@linux.intel.com>
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20230705123018.30903-2-johan+linaro@kernel.orgSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 06c2afb8
...@@ -922,8 +922,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, ...@@ -922,8 +922,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
"initializing enumeration and init completion for Slave %d\n", "initializing enumeration and init completion for Slave %d\n",
slave->dev_num); slave->dev_num);
init_completion(&slave->enumeration_complete); reinit_completion(&slave->enumeration_complete);
init_completion(&slave->initialization_complete); reinit_completion(&slave->initialization_complete);
} else if ((status == SDW_SLAVE_ATTACHED) && } else if ((status == SDW_SLAVE_ATTACHED) &&
(slave->status == SDW_SLAVE_UNATTACHED)) { (slave->status == SDW_SLAVE_UNATTACHED)) {
...@@ -931,7 +931,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, ...@@ -931,7 +931,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
"signaling enumeration completion for Slave %d\n", "signaling enumeration completion for Slave %d\n",
slave->dev_num); slave->dev_num);
complete(&slave->enumeration_complete); complete_all(&slave->enumeration_complete);
} }
slave->status = status; slave->status = status;
mutex_unlock(&bus->bus_lock); mutex_unlock(&bus->bus_lock);
...@@ -1951,7 +1951,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1951,7 +1951,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
"signaling initialization completion for Slave %d\n", "signaling initialization completion for Slave %d\n",
slave->dev_num); slave->dev_num);
complete(&slave->initialization_complete); complete_all(&slave->initialization_complete);
/* /*
* If the manager became pm_runtime active, the peripherals will be * If the manager became pm_runtime active, the peripherals will be
......
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