Skip to content

soundwire: qcom: enumerate in software when hardware auto-enum fails - #1268

Open
nandamajay wants to merge 1 commit into
qualcomm-linux:mainfrom
nandamajay:ak-swenum-autoenum-fix
Open

nandamajay wants to merge 1 commit into
qualcomm-linux:mainfrom
nandamajay:ak-swenum-autoenum-fix

Conversation

@nandamajay

Copy link
Copy Markdown

soundwire: qcom: enumerate in software when hardware auto-enum fails

Problem

On some QCM6490 cold boots the SoundWire sound card fails to come up
("Initialization not complete", -ETIMEDOUT). Root cause is a SoundWire
enumeration failure: the v2.0.0 controller's hardware auto-enumerator does a
one-shot DevID read at ping address 0 that breaks mid-transfer (first byte
latches, the rest return zero). The HW enumeration table is left empty, so
qcom_swrm_enumerate() assigns no device number, the WCD/WSA codecs never
initialise, and no card appears.

The controller signals exactly this via SWRM_INTERRUPT_STATUS_AUTO_ENUM_FAILED
(BIT(11)) — but that interrupt has had no case in qcom_swrm_irq_handler()
since it was introduced in commit 312355a ("soundwire: qcom: add support
for v2.0.0 controller"); it falls through to the "unknown interrupt" default and
nothing recovers.

Fix

The peripheral is awake throughout — a command-FIFO read of SCP_DEVID_0..5
(qcom_swrm_cmd_fifo_rd_cmd(), which retries and flushes the FIFO between tries)
returns the real DevID where the hardware's single-shot read did not. So on
AUTO_ENUM_FAILED, enumerate the peripheral in software over the command
FIFO:

  • qcom_swrm_match_slave_at_zero() reads the DevID with the retrying command-FIFO
    primitive and matches it against the peripherals this bus declares.
  • qcom_swrm_sw_program_device() picks a free number with find_first_zero_bit()
    over bus->assigned (same as the core), writes SCP_DEVNUMBER over the command
    FIFO and records the assignment the same way the hardware path does.
  • The device number is assigned in the driver rather than delegating the
    address-0 program step to the generic sdw_program_device_num(), whose single
    raw re-read of address 0 would underflow on a flaky boot and mint a phantom
    slave ("Slave Entry not found") that steals the real codec's number.
  • A bounded settle-retry (SWRM_SW_ENUM_ATTEMPTS × SWRM_SW_ENUM_SETTLE_MS)
    covers the few-hundred-ms a cold-boot peripheral can take to answer; a clean
    read programs on the first attempt and never sleeps. The whole fallback runs
    from the threaded IRQ handler and is bounded per bring-up by
    SWRM_SW_ENUM_RETRIES.

Also adds the previously-missing SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL
case.

Fixes: 312355a ("soundwire: qcom: add support for v2.0.0 controller")

Related issue

Fixes #1251 — the same cold-boot no-soundcard /
enumeration failure.

Validation

The fix was validated on QCM6490-IDP over repeated cold boots: card comes up on
every boot with a clean 4-device slave list (both WSA883x + both WCD937x,
all Attached and bound), no phantom node and no "Slave Entry not found",
with the capture-path (TX) WCD enumerated as well.

Note on this branch: validation was performed on a linux-next-based image.
This PR targets main (7.3-rc6), which does not carry the SCP_ADDRPAGE
shadow-cache fields; the one functional difference versus the validated tree is
that this variant omits the page-cache invalidation (a no-op on main, whose
hardware set_slave_dev_num() path also lacks it). The enumeration logic is
identical. Builds clean for arm64; checkpatch --strict reports 0/0/0.

The v2.0.0 SoundWire controller support added in commit 312355a
("soundwire: qcom: add support for v2.0.0 controller") left the
SWRM_INTERRUPT_STATUS_AUTO_ENUM_FAILED (BIT(11)) interrupt without a case
in qcom_swrm_irq_handler(); it falls through to the "unknown interrupt"
default.

On some QCM6490 cold boots the hardware auto-enumerator's one-shot DevID
read at ping address 0 breaks mid-transfer: the first byte latches and
the rest return zero. The HW enumeration table is left empty, so
qcom_swrm_enumerate() assigns no device number, the WCD/WSA codecs never
initialise, and the sound card fails to come up ("Initialization not
complete", -ETIMEDOUT). The controller signals exactly this condition via
AUTO_ENUM_FAILED - which, unhandled, means nothing recovers.

The peripheral itself is awake throughout - a command-FIFO read of
SCP_DEVID_0..5 at address 0 (qcom_swrm_cmd_fifo_rd_cmd(), which retries
and flushes the FIFO between tries) returns the real DevID where the
hardware's single-shot read did not. So when AUTO_ENUM_FAILED fires,
enumerate the peripheral in software over the command FIFO.

Assign the device number in the driver rather than delegating the
address-0 program step to the generic sdw_program_device_num(). That
helper re-reads the DevID at address 0 with a single raw transfer; on a
flaky boot the read underflows, the core finds no matching slave and
sdw_slave_add()s a phantom (logging "Slave Entry not found") which is
handed the device number the real codec needs.
qcom_swrm_match_slave_at_zero() instead reads the DevID with the retrying
command-FIFO primitive and matches it against the peripherals this bus
declares; qcom_swrm_sw_program_device() then picks a free number with
find_first_zero_bit() over bus->assigned (the same way the core does),
writes SCP_DEVNUMBER over the command FIFO and records the assignment as
qcom_swrm_set_slave_dev_num() does on the hardware path. Status slot 0 is
never surfaced to sdw_handle_slave_status() as attached, so the core
never reads address 0 and no phantom can be created; the core is invoked
only to initialise devices that have re-attached at their new number.

On a cold boot the peripheral can take a few hundred milliseconds to
answer, so a DevID read that underflows is retried after a bounded settle
delay (SWRM_SW_ENUM_ATTEMPTS attempts, SWRM_SW_ENUM_SETTLE_MS apart)
rather than giving up; a clean read programs on the first attempt and
does not sleep. The fallback runs from the threaded IRQ handler (which
may sleep) and is bounded per bring-up by SWRM_SW_ENUM_RETRIES so a dead
bus cannot loop forever.

Also add a case for SWRM_INTERRUPT_STATUS_AUTO_ENUM_TABLE_IS_FULL,
previously unhandled for the same reason.

Fixes: 312355a ("soundwire: qcom: add support for v2.0.0 controller")
Signed-off-by: Ajay Kumar Nandam <ajay.nandam@oss.qualcomm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audio Failure with 7.3-rc6

1 participant