mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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...



  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®