summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBard Liao <yung-chuan.liao@linux.intel.com>2024-04-10 05:34:38 +0300
committerVinod Koul <vkoul@kernel.org>2024-04-11 20:22:51 +0300
commit4cd5ea6de156850d555e1af8244a530812ae6ff6 (patch)
tree45ec00a3d2ba4effe47314dc3182d3328ffe2893
parentf2fa6865566483582aed4511ef603b44239b227b (diff)
downloadlinux-4cd5ea6de156850d555e1af8244a530812ae6ff6.tar.xz
soundwire: intel_init: resume all devices on exit.
When the manager becomes pm_runtime active in the remove procedure, peripherals will become attached, and do the initialization process. We have to wait until all the devices are fully resumed before the cleanup, otherwise there is a possible race condition where asynchronous workqueues initiate transfers on the bus that cannot complete. This will ensure there are no SoundWire registers accessed after the bus is powered-down. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20240410023438.487017-5-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
-rw-r--r--drivers/soundwire/intel_init.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index 534c8795e7e8..a09134b97cd6 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_intel.h>
#include "cadence_master.h"
+#include "bus.h"
#include "intel.h"
#include "intel_auxdevice.h"
@@ -356,6 +357,19 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
*/
void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{
+ struct sdw_intel_link_res *link;
+
+ /* we first resume links and devices and wait synchronously before the cleanup */
+ list_for_each_entry(link, &ctx->link_list, list) {
+ struct sdw_bus *bus = &link->cdns->bus;
+ int ret;
+
+ ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device);
+ if (ret < 0)
+ dev_err(bus->dev, "%s: intel_resume_child_device failed: %d\n",
+ __func__, ret);
+ }
+
sdw_intel_cleanup(ctx);
kfree(ctx->ids);
kfree(ctx->ldev);