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

soundwire: intel: skip suspend/resume/wake when link was not started

The SoundWire Linux devices are created purely based on information
provided by platform firmware (e.g. ACPI DSDT table). When the kernel
finds a matching driver for the device address (_ADR), the probe will
initialize required data structures and initialize pm ops.

When the SoundWire link is started at a later point, the physical
devices will synchronize on the SoundWire frames and report their
attachment status, thereby triggering the enumeration and
initialization of device registers.

This two-step solution was a conscious design decision to allow e.g. a
driver to use sideband mechanisms to turn power rails on. This can
also allow OEMs to describe multiple platforms with the same DSDT
table, the devices that are not physically present in hardware.

The drawback of this approach is a bit of confusion, with more devices
than are actually present in hardware. This results in 'ghost'
devices, for which the driver successfully probes, but that will not
generate any traffic on the bus. suspend-resume transitions are
handled by drivers, and skipped when the devices are not physically
present.

This patch provides a work-around for a second-level of confusion in
platform firmware: some platforms only use HDaudio links, but
nevertheless expose SoundWire 'ghost' devices. This results in error
messages in the Intel driver while trying to suspend/resume these
links. The simplest solution is to add a boolean status flag to skip
all suspend/resume/wake sequences if the link was never started.
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20210818024954.16873-3-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent ea6942da
...@@ -1525,6 +1525,7 @@ int intel_link_startup(struct auxiliary_device *auxdev) ...@@ -1525,6 +1525,7 @@ int intel_link_startup(struct auxiliary_device *auxdev)
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE))
pm_runtime_idle(dev); pm_runtime_idle(dev);
sdw->startup_done = true;
return 0; return 0;
err_interrupt: err_interrupt:
...@@ -1564,8 +1565,9 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) ...@@ -1564,8 +1565,9 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
sdw = dev_get_drvdata(dev); sdw = dev_get_drvdata(dev);
bus = &sdw->cdns.bus; bus = &sdw->cdns.bus;
if (bus->prop.hw_disabled) { if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id); dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id);
return 0; return 0;
} }
...@@ -1602,8 +1604,8 @@ static int __maybe_unused intel_suspend(struct device *dev) ...@@ -1602,8 +1604,8 @@ static int __maybe_unused intel_suspend(struct device *dev)
u32 clock_stop_quirks; u32 clock_stop_quirks;
int ret; int ret;
if (bus->prop.hw_disabled) { if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id); bus->link_id);
return 0; return 0;
} }
...@@ -1656,8 +1658,8 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ...@@ -1656,8 +1658,8 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev)
u32 clock_stop_quirks; u32 clock_stop_quirks;
int ret; int ret;
if (bus->prop.hw_disabled) { if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id); bus->link_id);
return 0; return 0;
} }
...@@ -1721,8 +1723,8 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1721,8 +1723,8 @@ static int __maybe_unused intel_resume(struct device *dev)
bool multi_link; bool multi_link;
int ret; int ret;
if (bus->prop.hw_disabled) { if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id); bus->link_id);
return 0; return 0;
} }
...@@ -1819,8 +1821,8 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1819,8 +1821,8 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
int status; int status;
int ret; int ret;
if (bus->prop.hw_disabled) { if (bus->prop.hw_disabled || !sdw->startup_done) {
dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n",
bus->link_id); bus->link_id);
return 0; return 0;
} }
......
...@@ -41,6 +41,7 @@ struct sdw_intel { ...@@ -41,6 +41,7 @@ struct sdw_intel {
struct sdw_cdns cdns; struct sdw_cdns cdns;
int instance; int instance;
struct sdw_intel_link_res *link_res; struct sdw_intel_link_res *link_res;
bool startup_done;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
#endif #endif
......
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