Linux cryptographic layer development
 help / color / mirror / Atom feed
From: Stephan Gerhold <stephan.gerhold@linaro.org>
To: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Cc: Vinod Koul <vkoul@kernel.org>, Jonathan Corbet <corbet@lwn.net>,
	Thara Gopinath <thara.gopinath@gmail.com>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	"David S. Miller" <davem@davemloft.net>,
	Udit Tiwari <quic_utiwari@quicinc.com>,
	Md Sadre Alam <mdalam@qti.qualcomm.com>,
	Dmitry Baryshkov <lumag@kernel.org>,
	Manivannan Sadhasivam <mani@kernel.org>,
	Bjorn Andersson <andersson@kernel.org>,
	Mukesh Kumar Savaliya <mukesh.savaliya@oss.qualcomm.com>,
	Peter Ujfalusi <peter.ujfalusi@gmail.com>,
	Michal Simek <michal.simek@amd.com>,
	Frank Li <Frank.Li@kernel.org>,
	Neil Armstrong <neil.armstrong@linaro.org>,
	Vignesh Raghavendra <vigneshr@ti.com>,
	dmaengine@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
	linux-crypto@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, brgl@kernel.org
Subject: Re: [PATCH v24 06/14] dmaengine: qcom: bam_dma: add support for BAM locking
Date: Fri, 24 Jul 2026 14:52:27 +0200	[thread overview]
Message-ID: <amNf-bljjasmTKn_@linaro.org> (raw)
In-Reply-To: <20260723-qcom-qce-cmd-descr-v24-6-4f87bb4d9938@oss.qualcomm.com>

On Thu, Jul 23, 2026 at 07:09:12PM +0200, Bartosz Golaszewski wrote:
> Add support for BAM pipe locking. To that end: when starting DMA on a TX
> channel (DMA_MEM_TO_DEV) - prepend the existing queue of issued
> descriptors with an additional "dummy" command descriptor with the LOCK
> bit set. Once the transaction is done (no more issued descriptors),
> issue one more dummy descriptor with the UNLOCK bit.
> 
> We *must* wait until the transaction is signalled as done because we
> must not perform any writes into config registers while the engine is
> busy.
> 
> The dummy writes must be issued into a scratchpad register of the client
> so provide a mechanism to communicate the right address via slave
> config.
> 
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
> [Stephan: came up with the solution to write lock/unlock descriptors
> directly into the FIFO]
> Co-developed-by: Stephan Gerhold <stephan.gerhold@linaro.org>
> Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
>  drivers/dma/qcom/bam_dma.c       | 146 ++++++++++++++++++++++++++++++++++-----
>  include/linux/dma/qcom_bam_dma.h |  13 ++++
>  2 files changed, 142 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
> index f3e713a5259c2c7c24cfdcec094814eb1202971a..373569c36a94e149d54ef041974b11018e634669 100644
> --- a/drivers/dma/qcom/bam_dma.c
> +++ b/drivers/dma/qcom/bam_dma.c
> [...]
> @@ -676,10 +697,51 @@ static void bam_free_chan(struct dma_chan *chan)
>  static int bam_slave_config(struct dma_chan *chan,
>  			    struct dma_slave_config *cfg)
>  {
> +	struct bam_config *peripheral_cfg = cfg->peripheral_config;
>  	struct bam_chan *bchan = to_bam_chan(chan);
> +	const struct bam_device_data *bdata = bchan->bdev->dev_data;
> +
> +	if (peripheral_cfg && cfg->peripheral_size != sizeof(*peripheral_cfg))
> +		return -EINVAL;
>  
>  	guard(spinlock_irqsave)(&bchan->vc.lock);
>  
> +	/*
> +	 * This is required to setup the pipe locking and must be done even
> +	 * before the first call to bam_start_dma().
> +	 */
> +	if (bdata->pipe_lock_supported && peripheral_cfg) {
> +		if (cfg->direction != DMA_MEM_TO_DEV)
> +			return -EINVAL;
> +
> +		if (bchan->bam_locked)
> +			return -EBUSY;
> +
> +		if (!bchan->lock_ce) {
> +			bchan->lock_ce = kmalloc_obj(*bchan->lock_ce, GFP_ATOMIC);
> +			if (!bchan->lock_ce)
> +				return -ENOMEM;
> +
> +			bchan->lock_ce_phys = dma_map_single(bchan->bdev->dev, bchan->lock_ce,
> +							     sizeof(*bchan->lock_ce),
> +							     DMA_TO_DEVICE);
> +			if (dma_mapping_error(bchan->bdev->dev, bchan->lock_ce_phys)) {
> +				kfree(bchan->lock_ce);
> +				bchan->lock_ce = NULL;
> +				return -ENOMEM;
> +			}
> +		}
> +
> +		bam_prep_ce_le32(bchan->lock_ce, peripheral_cfg->lock_scratchpad_addr,
> +				 BAM_WRITE_COMMAND, 0);
> +		dma_sync_single_for_device(bchan->bdev->dev, bchan->lock_ce_phys,
> +					   sizeof(*bchan->lock_ce), DMA_TO_DEVICE);

Nitpick: The sync is redundant if you just called dma_map_single()
above. It doesn't hurt to sync again for the one-time setup though.

> +		bchan->locking_enabled = true;
> +	} else {
> +		/* Don't touch lock_ce here, it might still be used by issued descriptors */
> +		bchan->locking_enabled = false;
> +	}
> +
>  	memcpy(&bchan->slave, cfg, sizeof(*cfg));
>  	bchan->reconfigure = 1;
>  
> @@ -802,6 +864,7 @@ static int bam_dma_terminate_all(struct dma_chan *chan)
>  		}
>  
>  		vchan_get_all_descriptors(&bchan->vc, &head);
> +		bchan->bam_locked = false;
>  	}

I think this needs some more thought. I put this assignment into
bam_reset_channel(), because presumably that's the only operation that
would really reset the lock status without processing an unlock
descriptor.

bam_dma_terminate_all() does not always reset the BAM channel. It does
that only if (!list_empty(&bchan->desc_list)) {
	bam_chan_init_hw(bchan, async_desc->dir);
}

I _think_ it is possible that we have no in-flight descriptors
(bchan->desc_list), but the unlock is still pending (or not even written
to the FIFO yet). In that case, bchan->bam_locked should not be reset
here.

I would put the bchan->bam_locked = false; into bam_reset_channel() like
in my diff.

Then, you could either leave this as-is (and assume the unlock
descriptor will still be finished/written even after cancelling the
descriptors).

Or, you add some more checks to this if statement to reset the BAM. This
could work I think:

	if (!list_empty(&bchan->desc_list)) {
		async_desc = list_first_entry(&bchan->desc_list,
					      struct bam_async_desc, desc_node);
		bam_chan_init_hw(bchan, async_desc->dir);
	} else if (bchan->bam_locked || bchan->head != bchan->tail) {
		/* BAM still locked or unlock still pending */
		bam_chan_init_hw(bchan, DMA_MEM_TO_DEV);
	}

Unfortunately, bchan->bam_locked alone doesn't tell us if the BAM is
locked, only if we haven't written the UNLOCK descriptor yet. It may be
pending in the FIFO. head != tail should tell us that the FIFO is not
empty (which should be the UNLOCK descriptor if desc_list is empty)...

>  
>  	vchan_dma_desc_free_list(&bchan->vc, &head);
> @@ -869,7 +932,7 @@ static int bam_resume(struct dma_chan *chan)
>  static u32 process_channel_irqs(struct bam_device *bdev)
>  {
>  	u32 i, srcs, pipe_stts, offset, avail;
> -	struct bam_async_desc *async_desc, *tmp;
> +	struct bam_async_desc *async_desc;
>  
>  	srcs = readl_relaxed(bam_addr(bdev, 0, BAM_IRQ_SRCS_EE));
>  
> [...]
> @@ -919,13 +991,12 @@ static u32 process_channel_irqs(struct bam_device *bdev)
>  			 * push back to front of desc_issued so that
>  			 * it gets restarted by the work queue.
>  			 */
> -			if (!async_desc->num_desc) {
> +			list_del(&async_desc->desc_node);
> +			if (!async_desc->num_desc)
>  				vchan_cookie_complete(&async_desc->vd);
> -			} else {
> +			else
>  				list_add(&async_desc->vd.node,
>  					 &bchan->vc.desc_issued);
> -			}
> -			list_del(&async_desc->desc_node);
>  		}

I think this is an unneeded/unrelated formatting change now. Drop?

>  	}
>  
> [...]
>  /**
>   * bam_start_dma - start next transaction
>   * @bchan: bam dma channel
>   */
>  static void bam_start_dma(struct bam_chan *bchan)
>  {
> -	struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
> +	struct virt_dma_desc *vd;
>  	struct bam_device *bdev = bchan->bdev;
>  	struct bam_async_desc *async_desc = NULL;
>  	struct bam_desc_hw *desc;
> @@ -1064,22 +1145,34 @@ static void bam_start_dma(struct bam_chan *bchan)
>  
>  	lockdep_assert_held(&bchan->vc.lock);
>  
> -	if (!vd)
> +	vd = vchan_next_desc(&bchan->vc);
> +	if (IS_BUSY(bchan) || (!vd && !bchan->bam_locked))
>  		return;
>  
>  	ret = pm_runtime_get_sync(bdev->dev);
>  	if (ret < 0)
>  		return;
>  
> +	if (!bchan->initialized)
> +		bam_chan_init_hw(bchan, container_of(vd, struct bam_async_desc, vd)->dir);

Okay yeah, that was my bug. Thanks for moving it :-)

> +
> +	if (bchan->locking_enabled && !bchan->bam_locked) {
> +		/* Defer locking until we also have space for a data descriptor */
> +		avail = CIRC_SPACE(bchan->tail, bchan->head, MAX_DESCRIPTORS + 1);
> +		if (avail < 2) {
> +			queue_work(system_bh_highpri_wq, &bdev->work);
> +			goto out;
> +		}
> +
> +		bam_fifo_write_lock(bchan, DESC_FLAG_LOCK);
> +		bchan->bam_locked = true;
> +	}
> +
>  	while (vd && !IS_BUSY(bchan)) {
>  		list_del(&vd->node);
>  
>  		async_desc = container_of(vd, struct bam_async_desc, vd);
>  
> -		/* on first use, initialize the channel hardware */
> -		if (!bchan->initialized)
> -			bam_chan_init_hw(bchan, async_desc->dir);
> -
>  		/* apply new slave config changes, if necessary */
>  		if (bchan->reconfigure)
>  			bam_apply_new_config(bchan, async_desc->dir);
> @@ -1135,11 +1228,24 @@ static void bam_start_dma(struct bam_chan *bchan)
>  		list_add_tail(&async_desc->desc_node, &bchan->desc_list);
>  	}
>  
> +	/*
> +	 * Close the bracket once there is no more client work queued. The
> +	 * UNLOCK is flagged for an interrupt so process_channel_irqs() is
> +	 * guaranteed to observe its completion and retire it from the FIFO
> +	 * promptly, instead of leaving bchan->head to lag until a later
> +	 * bracket's skip-loop catches up with it.
> +	 */

Fair enough, I was a bit lazy here and omitted the DESC_FLAG_INT. It
should help with the head!=tail check I mentioned for
bam_dma_terminate_all() though.

> +	if (bchan->bam_locked && !vd && !IS_BUSY(bchan)) {
> +		bam_fifo_write_lock(bchan, DESC_FLAG_UNLOCK | DESC_FLAG_INT);
> +		bchan->bam_locked = false;
> +	}
> +
>  	/* ensure descriptor writes and dma start not reordered */
>  	wmb();
>  	writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
>  			bam_addr(bdev, bchan->id, BAM_P_EVNT_REG));
>  
> +out:
>  	pm_runtime_mark_last_busy(bdev->dev);
>  	pm_runtime_put_autosuspend(bdev->dev);
>  }
> @@ -1162,7 +1268,13 @@ static void bam_dma_work(struct work_struct *work)
>  
>  		guard(spinlock_irqsave)(&bchan->vc.lock);
>  
> -		if (!list_empty(&bchan->vc.desc_issued) && !IS_BUSY(bchan))
> +		/*
> +		 * A channel also needs kicking if a bracket is still open
> +		 * (bam_locked) with no further client work queued: closing
> +		 * the UNLOCK requires a fresh call into bam_start_dma().
> +		 */
> +		if ((!list_empty(&bchan->vc.desc_issued) || bchan->bam_locked) &&
> +		    !IS_BUSY(bchan))
>  			bam_start_dma(bchan);

The if statement is redundant, bam_start_dma() now checks all of that
internally. 

	if (IS_BUSY(bchan) || (!vd && !bchan->bam_locked))
		return;

list_empty(desc_issed) == !vd

Same for !IS_BUSY() in bam_issue_pending().

Thanks,
Stephan

  parent reply	other threads:[~2026-07-24 12:52 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23 17:09 [PATCH v24 00/14] crypto/dmaengine: qce: introduce BAM locking and use DMA for register I/O Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 01/14] dmaengine: constify struct dma_descriptor_metadata_ops Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 02/14] dmaengine: qcom: bam_dma: free interrupt before the clock in error path Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 03/14] dmaengine: qcom: bam_dma: convert tasklet to a BH workqueue Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 04/14] dmaengine: qcom: bam_dma: Extend the driver's device match data Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 05/14] dmaengine: qcom: bam_dma: Add pipe_lock_supported flag support Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 06/14] dmaengine: qcom: bam_dma: add support for BAM locking Bartosz Golaszewski
     [not found]   ` <20260723172814.661591F000E9@smtp.kernel.org>
2026-07-24 10:53     ` Stephan Gerhold
2026-07-24 12:52   ` Stephan Gerhold [this message]
2026-07-23 17:09 ` [PATCH v24 07/14] crypto: qce - Cancel work on device detach Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 08/14] crypto: qce - Include algapi.h in the core.h header Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 09/14] crypto: qce - Remove unused ignore_buf Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 10/14] crypto: qce - Simplify arguments of devm_qce_dma_request() Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 11/14] crypto: qce - Use existing devres APIs in devm_qce_dma_request() Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 12/14] crypto: qce - Map crypto memory for DMA Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 13/14] crypto: qce - Add BAM DMA support for crypto register I/O Bartosz Golaszewski
2026-07-23 17:09 ` [PATCH v24 14/14] crypto: qce - Communicate the base physical address to the dmaengine Bartosz Golaszewski
2026-07-23 17:27 ` [PATCH v24 00/14] crypto/dmaengine: qce: introduce BAM locking and use DMA for register I/O Eric Biggers

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=amNf-bljjasmTKn_@linaro.org \
    --to=stephan.gerhold@linaro.org \
    --cc=Frank.Li@kernel.org \
    --cc=andersson@kernel.org \
    --cc=bartosz.golaszewski@oss.qualcomm.com \
    --cc=brgl@kernel.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=dmaengine@vger.kernel.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lumag@kernel.org \
    --cc=mani@kernel.org \
    --cc=mdalam@qti.qualcomm.com \
    --cc=michal.simek@amd.com \
    --cc=mukesh.savaliya@oss.qualcomm.com \
    --cc=neil.armstrong@linaro.org \
    --cc=peter.ujfalusi@gmail.com \
    --cc=quic_utiwari@quicinc.com \
    --cc=thara.gopinath@gmail.com \
    --cc=vigneshr@ti.com \
    --cc=vkoul@kernel.org \
    /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