From: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
To: Syed Saba Kareem <syed.sabakareem@amd.com>, vkoul@kernel.org
Cc: broonie@kernel.org, Sunil-kumar.Dommati@amd.com,
vijendar.mukunda@amd.com, Mario.Limonciello@amd.com,
venkataprasad.potturu@amd.com, yung-chuan.liao@linux.intel.com,
anson.tsao@amd.com, "Liam Girdwood" <lgirdwood@gmail.com>,
"Jaroslav Kysela" <perex@perex.cz>,
"Takashi Iwai" <tiwai@suse.com>,
"Peter Ujfalusi" <peter.ujfalusi@linux.intel.com>,
"Daniel Baluta" <daniel.baluta@nxp.com>,
"Kai Vehmanen" <kai.vehmanen@linux.intel.com>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Simon Trimmer" <simont@opensource.cirrus.com>,
"Mario Limonciello (AMD)" <superm1@kernel.org>,
"open list:SOUNDWIRE SUBSYSTEM" <linux-sound@vger.kernel.org>,
"open list" <linux-kernel@vger.kernel.org>,
"moderated list:SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS"
<sound-open-firmware@alsa-project.org>,
"open list:BPF [MISC]:Keyword:(?:\\b|_)bpf(?:\\b|_)"
<bpf@vger.kernel.org>,
"open list:DMA BUFFER SHARING
FRAMEWORK:Keyword:\\bdma_(?:buf|fence|resv)\\b"
<linux-media@vger.kernel.org>,
"open list:DMA BUFFER SHARING
FRAMEWORK:Keyword:\\bdma_(?:buf|fence|resv)\\b"
<dri-devel@lists.freedesktop.org>,
"moderated list:DMA BUFFER SHARING
FRAMEWORK:Keyword:\\bdma_(?:buf|fence|resv)\\b"
<linaro-mm-sig@lists.linaro.org>
Subject: Re: [PATCH v3 4/5] soundwire: amd: Add BRA/BPT firmware download support
Date: Wed, 7 Oct 2026 18:15:02 +0200 [thread overview]
Message-ID: <f6790e78-8432-4bab-8363-501a2fb9783d@linux.dev> (raw)
In-Reply-To: <87dff7bd-fa1d-4153-8dd1-75947a25a466@amd.com>
>> general comment: this patch is quite complex, with code needed for the
>> BTP side as well as the DMA side, only interleaved. Is there a way to
>> have a 'cleaner' split between DMA functionality on the ACP side and BPT
>> on the SoundWire bus side?
>>
>> Likewise the parts dealing with contiguous and non-contiguous parts of
>> the firmware should be handled at a higher level using DMA/BTP support
>> lower-level routines.
>
> Agreed, I'll restructure this into three layers for v5: ACP BRA /DMA/
> primitives (configure descriptor, arm, poll/wait, disarm, deconfigure)
> with no SoundWire-stream knowledge; SoundWire /BPT/ primitives (open/
> close stream, enable/disable);
> and a higher-level orchestrator with a dispatcher for the contiguous
> (single-buffer) vs non-contiguous (per-section loop, with the small-
> section sdw_nwrite/nread fallback) cases.
Sounds good.
> One hardware detail I'll preserve and document along the way: the
> SoundWire bank switch is itself the BRA DMA start trigger,and correct
> teardown requires disarming the DMA before the disable-path bank switch.
That sounds fine, provided that hardware pushes a invalid BPT frame on
the link in the time window between the disarming and bank switch.
Otherwise the peripherals might receive garbage BTP data, no?
> So the orchestrator still sequences an ACP call and a SoundWire call in
> a fixed order — the layering makes each side independently readable and
> testable while keeping that ordering contract explicit.
>
>>> +static int amd_sdw_execute_bra_transfer(struct amd_sdw_manager *amd_manager,
>>> + struct sdw_slave *slave,
>>> + bool *dma_unsafe)
>>> +{
>>> + struct sdw_bus *bus = &amd_manager->bus;
>>> + u32 i2s_err_offset;
>>> + u32 saved_intr_mask;
>>> + u32 reg_addr, len;
>>> + u32 val;
>>> + int ret, ret_disable;
>>> +
>>> + /* Read descriptor regs before enabling the DMA engine. */
>>> + reg_addr = readl(amd_manager->mmio + ACP_SW_BPT_PORT_FIRST_BYTE_ADDR);
>>> + len = readl(amd_manager->mmio + ACP_SW_BRA_TRANSFER_SIZE);
>>> +
>>> + i2s_err_offset = (amd_manager->instance == 0) ?
>>> + ACP_SW_I2S_ERROR_REASON : ACP_P1_SW_I2S_ERROR_REASON;
>>> +
>>> + /*
>>> + * Save and disable the error interrupt mask for manual error
>>> + * checking. acp_bra_lock is held across the whole BPT sequence by
>>> + * amd_sdw_bpt_wait(), which serialises this shared-register
>>> + * read-modify-write against the other manager instance.
>>> + */
>>> + saved_intr_mask = readl(amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
>>> + writel(0, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
>>> + writel(0, amd_manager->acp_mmio + i2s_err_offset);
>>> + writel(0, amd_manager->mmio + ACP_SW_ERROR_REASON1);
>>> +
>>> + /* Arm the ACP BPT DMA engine */
>>> + writel(1, amd_manager->mmio + ACP_SW_BPT_PORT_EN);
>>> +
>>> + /*
>>> + * Use the framework's sdw_enable_stream() to write CHANNELEN and
>>> + * perform a bank switch. The ACP BPT hardware uses the bank switch
>>> + * as the trigger to start the DMA transfer. The framework manages
>> do you mean to say
>> a) the DMA transfer was armed and started ealier, and the bank switch
>> unblocks it, ob
>> b) the DMA starts fetching data from memory when the bank switch happens?
>>
>> the latter case would be quite racy and dependent on the time needed to
>> access memory..
> It's (a). The BRA descriptor (BASE_ADDRESS/TRANSFER_SIZE/FRAME_FORMAT)
> is fully programmed in amd_sdw_config_bra_descriptor(),
> and the engine is armed with ACP_SW_BPT_PORT_EN=1, both before
> sdw_enable_stream().
> The bank switch is only the trigger for the already-armed engine — it
> doesn't start a cold engine, so there's no memory-latency race on the
> switch.
ok
> Once triggered the engine runs autonomously frame by frame, and any
> stall/underrun surfaces as a BRA/I2S error (ACP_SW_I2S_ERROR_REASON /
> ACP_SW_BRA_RESP), not silent corruption.
but then if I follow your explanations above, if you stop the DMA first
don't you get a systematic xrun error before the bank switch happens?
> This is also why, on an aborted or timed-out transfer, the teardown
> clears PORT_EN before the sdw_disable_stream() bank switch — otherwise
> that switch
> could re-trigger the armed engine into a buffer we're about to free.
> I'll reword the comment to say the engine is armed here and the bank
> switch only triggers it.
ok
[...]
>>> + /*
>>> + * The ATU GRP_1 and scratch PTE registers programmed here are
>>> + * ACP-global and shared by both SoundWire manager instances, as is the
>>> + * BRA DMA engine that reads through them. bpt_lock is per-manager and
>>> + * does not serialise across instances, so hold the ACP-wide
>>> + * acp_bra_lock across the whole configure -> transfer -> deconfigure
>>> + * sequence to stop the other instance reprogramming the shared PTEs
>>> + * mid-transfer.
>> In that case, what is the point of having a per-instance btp_lock as well?
>>
>> It seems from the comment that only *one* BTP transfer can take place
>> across all manager instances, which defeats the purpose of a
>> per-instance lock, no?
>> What I am missing?
>
> You're right that the transfer itself is serialized ACP-wide: that's
> acp_bra_lock, held only across configure → transfer → deconfigure,
> because the ATU PTEs and
> the BRA DMA engine are single resources shared by both links. bpt_lock
> is per-link and has a different scope rather than a different transfer
> window:
>
> * It guards bpt_disabled, which is per-link suspend/clock-stop/
> runtime-PM state — each link's amd_suspend()/clock-stop
> sets it and amd_resume_runtime() clears it under bpt_lock. A per-
> link flag doesn't belong under an ACP-global lock.
> * It serializes multiple BPT requests to the same link and lets that
> link's suspend path drain an in-flight transfer, without reaching
> for the global lock.
> * It keeps acp_bra_lock's hold time minimal: the per-link setup/
> teardown (open_stream, dma_alloc, the PM get/put, the bpt_disabled
> check) runs
> under bpt_lock but outside acp_bra_lock, so the other link contends
> for the global lock only during the actual shared-hardware window,
> not the whole sequence.
>
> Folding everything onto acp_bra_lock would mean the global lock has to
> cover each link's full transfer path including its runtime-PM callbacks,
> i.e. one link's PM transitions would serialize against the other link's
> transfer — a scope mismatch and a longer global hold time.
> So the two are intentionally different scopes: bpt_lock = per-link
> lifecycle/PM, acp_bra_lock = ACP-global shared hardware. Today the
> comment only documents acp_bra_lock; I'll expand it to cover both.
The explanation make sense... but I am not fully clear on why you'd need
to protect the BPT state for link-based pm_runtime. Presumably a BPT
transfer would happen with a device reference held to prevent it from
suspending? Something's not right if you need to drain a BPT transfer in
a pm_runtime suspend, that suspend shouldn't happen in the first place...
next prev parent reply other threads:[~2026-10-07 16:39 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20261005091620.1390916-1-syed.sabakareem@amd.com>
2026-10-05 9:15 ` [PATCH v3 1/5] soundwire: intel_ace2x: free master runtime on BPT open error path Syed Saba Kareem
2026-10-05 9:15 ` [PATCH v3 2/5] soundwire: intel_ace2x: order bpt_stream publish/clear against refcount Syed Saba Kareem
2026-10-05 9:15 ` [PATCH v3 3/5] soundwire: stream: allow flagged BPT firmware download while streams are idle Syed Saba Kareem
2026-10-05 11:26 ` Pierre-Louis Bossart
2026-10-06 12:11 ` Syed Saba Kareem
2026-10-05 9:15 ` [PATCH v3 4/5] soundwire: amd: Add BRA/BPT firmware download support Syed Saba Kareem
2026-10-05 12:04 ` Pierre-Louis Bossart
[not found] ` <87dff7bd-fa1d-4153-8dd1-75947a25a466@amd.com>
2026-10-07 16:15 ` Pierre-Louis Bossart [this message]
2026-10-05 9:15 ` [PATCH v3 5/5] soundwire: amd: honor peripheral BRA block alignment Syed Saba Kareem
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f6790e78-8432-4bab-8363-501a2fb9783d@linux.dev \
--to=pierre-louis.bossart@linux.dev \
--cc=Mario.Limonciello@amd.com \
--cc=Sunil-kumar.Dommati@amd.com \
--cc=anson.tsao@amd.com \
--cc=bpf@vger.kernel.org \
--cc=broonie@kernel.org \
--cc=christian.koenig@amd.com \
--cc=daniel.baluta@nxp.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=kai.vehmanen@linux.intel.com \
--cc=lgirdwood@gmail.com \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=peter.ujfalusi@linux.intel.com \
--cc=simont@opensource.cirrus.com \
--cc=sound-open-firmware@alsa-project.org \
--cc=sumit.semwal@linaro.org \
--cc=superm1@kernel.org \
--cc=syed.sabakareem@amd.com \
--cc=tiwai@suse.com \
--cc=venkataprasad.potturu@amd.com \
--cc=vijendar.mukunda@amd.com \
--cc=vkoul@kernel.org \
--cc=yung-chuan.liao@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®