ASoC/soundwire: log actual PING status on resume issues

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

we've been stuck with problems in the dual-amplifier configurations where
one of the two devices seems to become UNATTACHED and never regains sync,
see https://github.com/thesofproject/linux/issues/3638.

This is a rather infrequent issue that may happen once or twice per month,
but still it remains a concern.

One possibility is that the device does lose sync but somehow our hardware
detection fails to see it resync.

This series just adds a basic read directly from the PING frames to help
confirm if yes/no the device regain sync.
This commit is contained in:
Mark Brown 2022-08-17 15:18:47 +01:00
commit 1decead8d7
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
13 changed files with 64 additions and 0 deletions

View File

@ -297,6 +297,38 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
return ret;
}
/**
* sdw_show_ping_status() - Direct report of PING status, to be used by Peripheral drivers
* @bus: SDW bus
* @sync_delay: Delay before reading status
*/
void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay)
{
u32 status;
if (!bus->ops->read_ping_status)
return;
/*
* wait for peripheral to sync if desired. 10-15ms should be more than
* enough in most cases.
*/
if (sync_delay)
usleep_range(10000, 15000);
mutex_lock(&bus->msg_lock);
status = bus->ops->read_ping_status(bus);
mutex_unlock(&bus->msg_lock);
if (!status)
dev_warn(bus->dev, "%s: no peripherals attached\n", __func__);
else
dev_dbg(bus->dev, "PING status: %#x\n", status);
}
EXPORT_SYMBOL(sdw_show_ping_status);
/**
* sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
* @bus: SDW bus

View File

@ -756,6 +756,14 @@ cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num)
}
EXPORT_SYMBOL(cdns_reset_page_addr);
u32 cdns_read_ping_status(struct sdw_bus *bus)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
return cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
}
EXPORT_SYMBOL(cdns_read_ping_status);
/*
* IRQ handling
*/

View File

@ -177,6 +177,8 @@ enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus *bus,
struct sdw_msg *msg, struct sdw_defer *defer);
u32 cdns_read_ping_status(struct sdw_bus *bus);
int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params);
int cdns_set_sdw_stream(struct snd_soc_dai *dai,

View File

@ -1262,6 +1262,7 @@ static struct sdw_master_ops sdw_intel_ops = {
.set_bus_conf = cdns_bus_conf,
.pre_bank_switch = intel_pre_bank_switch,
.post_bank_switch = intel_post_bank_switch,
.read_ping_status = cdns_read_ping_status,
};
static int intel_init(struct sdw_intel *sdw)

View File

@ -839,6 +839,8 @@ struct sdw_defer {
* @set_bus_conf: Set the bus configuration
* @pre_bank_switch: Callback for pre bank switch
* @post_bank_switch: Callback for post bank switch
* @read_ping_status: Read status from PING frames, reported with two bits per Device.
* Bits 31:24 are reserved.
*/
struct sdw_master_ops {
int (*read_prop)(struct sdw_bus *bus);
@ -855,6 +857,7 @@ struct sdw_master_ops {
struct sdw_bus_params *params);
int (*pre_bank_switch)(struct sdw_bus *bus);
int (*post_bank_switch)(struct sdw_bus *bus);
u32 (*read_ping_status)(struct sdw_bus *bus);
};
@ -919,6 +922,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
struct fwnode_handle *fwnode);
void sdw_bus_master_delete(struct sdw_bus *bus);
void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
/**
* sdw_port_config: Master or Slave Port configuration
*

View File

@ -281,6 +281,8 @@ static __maybe_unused int max98373_resume(struct device *dev)
msecs_to_jiffies(MAX98373_PROBE_TIMEOUT));
if (!time) {
dev_err(dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -749,6 +749,8 @@ static int __maybe_unused rt1308_dev_resume(struct device *dev)
msecs_to_jiffies(RT1308_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -734,6 +734,8 @@ static int __maybe_unused rt1316_dev_resume(struct device *dev)
msecs_to_jiffies(RT1316_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -793,6 +793,8 @@ static int __maybe_unused rt5682_dev_resume(struct device *dev)
msecs_to_jiffies(RT5682_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -542,6 +542,8 @@ static int __maybe_unused rt700_dev_resume(struct device *dev)
msecs_to_jiffies(RT700_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -449,6 +449,8 @@ static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
msecs_to_jiffies(RT711_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -244,6 +244,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Enumeration not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}

View File

@ -562,6 +562,8 @@ static int __maybe_unused rt715_dev_resume(struct device *dev)
msecs_to_jiffies(RT715_PROBE_TIMEOUT));
if (!time) {
dev_err(&slave->dev, "Initialization not complete, timed out\n");
sdw_show_ping_status(slave->bus, true);
return -ETIMEDOUT;
}