[PATCH 2/3] ASoC: sdw_utils: skip endpoints of a peripheral that is not on the bus

Sergey Lebedev <[email protected]> Tue, 04 Aug 2026 22:59:34 +0000
Newsgroups org.kernel.vger.linux-sound,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
asoc_sdw_parse_sdw_endpoints() builds DAI links for every endpoint of
every _ADR entry the firmware declares. If a declared peripheral never
enumerates, its links are still created and later fail to prepare, which
takes the whole link down rather than degrading it:

  sof_sdw sof_sdw: ASoC: error at snd_soc_link_startup on
    SDW0-Playback-SmartAmp: -61

The Microsoft Surface Pro 11 (Intel) declares one physical RT1320 twice,
as two _ADR entries on link 0 differing only in SDCA class id:

  SWRA  _ADR 0x000030025D132000   class 0
  SWRB  _ADR 0x000030025D132001   class 1

Same link, same manufacturer, part and version, same unique id 0. The
part reports class 1, so only SWRB enumerates. SWRA is a phantom and
stays UNATTACHED across every boot and every firmware version tested,
including the November 2025 bundle.

The existing is_sdca_endpoint_present() check cannot filter it out.
Setting aside that it is gated on a non-zero class id and the phantom is
the class-0 entry, the deeper problem is that the BIOS describes both
entries identically: each declares the same two SDCA functions, so the
check matches for either. Bus presence is what distinguishes them, so
test that.

The check is by nature a runtime one, and its correctness depends on the
peripheral having enumerated by the time the card probes. That holds
here: the real device is Attached and the phantom has no device number
at all whenever this runs. It is a weaker property than the surrounding
BIOS-driven checks, and a suggestion for something stronger would be
welcome, but the firmware offers nothing else to key on.

Signed-off-by: Sergey Lebedev <[email protected]>
---
 sound/soc/sdw_utils/soc_sdw_utils.c | 46 +++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index d8db8fc53..12ca4bdd4 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -1909,6 +1909,46 @@ int asoc_sdw_get_dai_type(u32 type)
 }
 EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS");
 
+/*
+ * Some firmware describes one physical peripheral with two _ADR entries that
+ * differ only in SDCA class id, on the same link and with the same unique id.
+ * Only the entry whose class id matches the part ever enumerates; the other is
+ * a phantom. Building DAI links for it fails the whole link rather than
+ * degrading it, so the endpoints have to be skipped.
+ *
+ * This cannot be decided from the BIOS description: on the machine that
+ * prompted this, both entries declare an identical set of SDCA functions, so
+ * is_sdca_endpoint_present() below matches for either. Bus presence is the only
+ * thing that distinguishes them.
+ */
+static bool is_peripheral_attached(struct device *dev,
+				   const struct snd_soc_acpi_link_adr *adr_link,
+				   int adr_index)
+{
+	const char *sdw_codec_name;
+	struct device *sdw_dev;
+	struct sdw_slave *slave;
+	bool attached;
+
+	sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
+	if (!sdw_codec_name)
+		return true;
+
+	sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
+	if (!sdw_dev)
+		return true;
+
+	slave = dev_to_sdw_dev(sdw_dev);
+	attached = slave->status != SDW_SLAVE_UNATTACHED;
+	if (!attached)
+		dev_dbg(dev, "%s not present on the bus, skipping its endpoints\n",
+			sdw_codec_name);
+
+	put_device(sdw_dev);
+
+	return attached;
+}
+
 /**
  * is_sdca_endpoint_present - Check if an SDCA endpoint is present on the SDW peripheral
  * @dev: Device pointer
@@ -2065,6 +2105,12 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
 				dai_info = &codec_info->dais[adr_end->num];
 				soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
 
+				/* skip a peripheral that is not on the bus at all */
+				if (!is_peripheral_attached(dev, adr_link, i)) {
+					(*num_devs)--;
+					continue;
+				}
+
 				/*
 				 * quirk should have higher priority than the sdca properties
 				 * in the BIOS. We can't always check the DAI quirk because we
-- 
2.50.1 (Apple Git-155)