mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: rkannoth@marvell.com
Cc: davem@davemloft.net, gakula@marvell.com,
	linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
	sgoutham@marvell.com, andrew+netdev@lunn.ch, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, leon@kernel.org
Subject: Re: [PATCH v8 net-next] octeontx2-af: switch qmem from coherent DMA alloc to streaming DMA mapping
Date: Fri, 11 Sep 2026 09:36:07 +0000	[thread overview]
Message-ID: <178911936770.219967.4327734860588306431@kernel.org> (raw)
In-Reply-To: <20260908063411.257228-1-rkannoth@marvell.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider:

Critical: 0 · High: 3 (1) · Medium: 0 · Low: 0

- [High] otx2_dma_alloc_coherent()
  (drivers/net/ethernet/marvell/octeontx2/af/common.h:51-69) creates a…
- [High] dma_map_single() is not guaranteed to return an address that
  aliases the caller's buffer, and the new helper accepts any successful…
- [High] The newly added check in qmem_alloc() (af/common.h:95) 'if
  (get_order(PAGE_ALIGN(qmem->alloc_sz)) > MAX_PAGE_ORDER) return…

Pre-existing issues:
- [High] qmem_alloc() computes 'qmem->alloc_sz = (qsize * entry_sz) +
  OTX2_ALIGN' (af/common.h:93) in int from mailbox-supplied, unbounded…

--

octeontx2-af: switch qmem from coherent DMA alloc to streaming DMA mapping

This replaces the dma_alloc_attrs(DMA_ATTR_FORCE_CONTIGUOUS) backing of
qmem with kmalloc() plus dma_map_single(), wrapped in new
otx2_dma_alloc_coherent()/otx2_dma_free_coherent() helpers. qmem_alloc()
and qmem_free() are wired through the new helpers, and a
get_order()/MAX_PAGE_ORDER size check is added to qmem_alloc().

> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h
> index 779413a383b74..0569b6d9f03b5 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h

[ ... ]

> +static inline void *otx2_dma_alloc_coherent(struct device *dev, size_t size,
> +					    dma_addr_t *dma_handle)
> +{
> +	dma_addr_t dma_addr;
> +	void *vaddr;
> +
> +	vaddr = kmalloc(size, GFP_KERNEL | __GFP_ZERO);
> +	if (!vaddr)
> +		return NULL;
> +
> +	dma_addr = dma_map_single(dev, vaddr, size, DMA_BIDIRECTIONAL);
> +	if (dma_mapping_error(dev, dma_addr)) {
> +		kfree(vaddr);
> +		return NULL;
> +	}

[Severity: High]
The v8 changelog says "Retain dev_is_dma_coherent() guard in
otx2_dma_alloc_coherent()", but is that guard actually present here?  A
grep of drivers/net/ethernet/marvell/octeontx2/ for
dev_is_dma_coherent|dma_sync_single|dma_max_mapping_size returns nothing at
this commit, so the coherency premise of the changelog does not appear to
be expressed anywhere in the code.

Does this matter for the qmem consumers?  They use the buffer in the
dma_alloc_coherent() model, not the streaming model.  For example
nix_aq_enqueue_wait() in af/rvu_nix.c:

	memcpy((void *)(aq->inst->base + (head * aq->inst->entry_sz)),
	       (void *)inst, aq->inst->entry_sz);
	memset(result, 0, sizeof(*result));
	/* sync into memory */
	wmb();
	/* Ring the doorbell and wait for result */
	rvu_write64(rvu, block->addr, NIX_AF_AQ_DOOR, 1);
	while (result->compcode == NIX_AQ_COMP_NOTDONE) {

The CPU writes the instruction, the device DMA-writes result->compcode, and
the only barrier is wmb() with no dma_sync_single_for_device()/for_cpu()
ownership transfer.  npa_aq_enqueue_wait() and the NIX CQ rings do the
same.

On a device that is not IO-coherent, can the CPU-written contexts stay in
dirty cache lines while the device fetches stale data, and can the
device-written result words never be invalidated so the poll loop spins on
a stale compcode until it times out?

The kernel already has DMA_ATTR_REQUIRE_COHERENT for exactly this, in
include/linux/dma-mapping.h:

	/*
	 * DMA_ATTR_REQUIRE_COHERENT: Indicates that DMA coherency is required.
	 * All mappings that carry this attribute can't work with SWIOTLB and cache
	 * flushing.
	 */

The v8 changelog states this attribute was dropped.  Would using it (or an
explicit dev_is_dma_coherent() bail-out) make the requirement enforced
rather than assumed?

[Severity: High]
Separately, this helper accepts any non-error dma_addr and returns the
kmalloc pointer to the caller.  Is dma_map_single() guaranteed to return an
address that aliases that buffer?

In dma_direct_map_phys() (kernel/dma/direct.c):

	if (is_swiotlb_force_bounce(dev)) {
		if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))
			return DMA_MAPPING_ERROR;
		return swiotlb_map(dev, phys, size, dir, attrs);
	}

and later the dma_capable()/dma_kmalloc_needs_bounce() path also falls back
to swiotlb_map() when DMA_ATTR_REQUIRE_COHERENT is absent.
dma_kmalloc_needs_bounce() in include/linux/dma-map-ops.h is:

	return !dma_kmalloc_safe(dev, dir) && !dma_kmalloc_size_aligned(size);

which is true for a non-coherent device with DMA_BIDIRECTIONAL when the
kmalloc size is neither >= 2*ARCH_DMA_MINALIGN nor cache-line rounded --
for instance qmem_alloc(dev, &sq->sqe, 1, 64) in nic/otx2_common.c gives
alloc_sz = 192.

If the mapping is bounced, the IOVA programmed into NIX_AF_LFX_*_BASE,
NPA_AF_LFX_*_BASE, RVU_PF_VF_MBOX_ADDR and the LMT map table refers to a
bounce slot that receives one all-zero copy, while the driver keeps reading
and writing the original kmalloc buffer with no dma_sync_* to reconcile
them.  Can this leave the device armed with memory the driver never
updates?  dma_alloc_attrs()/dma_alloc_coherent() did not have this
property.

Also, under SWIOTLB the largest streaming mapping is
IO_TLB_SEGSIZE * IO_TLB_SIZE (256 KiB).  Do the multi-hundred-KiB qmem
regions (the CN10K LMT region sized num_online_cpus() * 32 * 128, CQ rings,
aura/pool context tables) simply fail to map and abort queue init in that
configuration?

> +
> +	*dma_handle = dma_addr;
> +	return vaddr;
> +}

[ ... ]

> @@ -60,8 +91,11 @@ static inline int qmem_alloc(struct device *dev, struct qmem **q,
>  
>  	qmem->entry_sz = entry_sz;
>  	qmem->alloc_sz = (qsize * entry_sz) + OTX2_ALIGN;
> -	qmem->base = dma_alloc_attrs(dev, qmem->alloc_sz, &qmem->iova,
> -				     GFP_KERNEL, DMA_ATTR_FORCE_CONTIGUOUS);
> +
> +	if (get_order(PAGE_ALIGN(qmem->alloc_sz)) > MAX_PAGE_ORDER)
> +		return -ENOMEM;

[Severity: High]
Does this new check, combined with the switch to kmalloc(), introduce a
hard size ceiling that the old CMA-backed path did not have?

KMALLOC_MAX_SIZE in include/linux/slab.h is:

	#define KMALLOC_SHIFT_MAX	(MAX_PAGE_ORDER + PAGE_SHIFT)
	/* Maximum allocatable size */
	#define KMALLOC_MAX_SIZE	(1UL << KMALLOC_SHIFT_MAX)

i.e. 4 MiB on a 4 KiB-page kernel.  Some existing callers ask for more.
cn20k_pfvf_mbox_alloc() in nic/otx2_pf.c does:

	err = qmem_alloc(&pf->pdev->dev, &mbox_addr, numvfs, MBOX_SIZE);

with MBOX_SIZE == SZ_64K, so at numvfs == 64 alloc_sz is 4 MiB + 128,
PAGE_ALIGN gives 0x401000 and get_order() returns 11 > MAX_PAGE_ORDER (10).
qmem_alloc() then returns -ENOMEM before attempting any allocation and
otx2_pfvf_mbox_init()/otx2_sriov_enable() fail, even though the same driver
handles numvfs > 64 elsewhere.  Does 'echo 64 > .../sriov_numvfs' still
work on CN20K after this change?

rvu_alloc_mbox_memory() in af/cn20k/mbox_init.c requests ndevs * MBOX_SIZE
scaling with the hardware PF/VF count, and rvu_mbox_handler_npa_lf_alloc()
in af/rvu_npa.c requests NPA_AURA_COUNT(aura_sz) * hwctx_size, which for
the mailbox-legal aura_sz == NPA_AURA_SZ_1M is 1M * 128 = 128 MiB.  Do
those now fail too?

Two smaller points on the same branch: get_order(PAGE_ALIGN(x)) equals
get_order(x), so the PAGE_ALIGN() adds nothing, and the branch returns
-ENOMEM with no dev_err() where the previous path produced a visible
allocation warning.  Could the new size ceiling and the changed failure
characteristics (plain GFP_KERNEL order-9/10 buddy allocations, no
__GFP_NOWARN or __GFP_RETRY_MAYFAIL) be mentioned in the changelog, given
the Fixes: tag makes this a stable-backport candidate?

[Severity: High]
This isn't a bug introduced by this patch, but the value being validated
here has already wrapped.  qmem->alloc_sz is an int and the multiplication
'qsize * entry_sz' is done in int on mailbox-supplied counts, so the new
get_order() check bounds the wrapped size rather than the requested one.

rvu_mbox_handler_npa_lf_alloc() in af/rvu_npa.c rejects only !req->nr_pools
(a u32 mailbox field) before calling:

	err = qmem_alloc(rvu->dev, &pfvf->pool_ctx, req->nr_pools, hwctx_size);

With nr_pools = 0x2000000 and hwctx_size = 128 the product is 2^32, which
wraps to 0, so alloc_sz = 128, get_order(PAGE_ALIGN(128)) = 0 passes the
new check and kmalloc(128) succeeds -- while pool_ctx->qsize keeps the full
33554432.  rvu_npa_aq_enq_inst() then only checks against that qsize:

	if (req->aura.pool_addr >= pfvf->pool_ctx->qsize) {
		rc = NPA_AF_ERR_AQ_FULL;
		break;
	}
	/* Set pool's context address */
	req->aura.pool_addr = pfvf->pool_ctx->iova +
	(req->aura.pool_addr * pfvf->pool_ctx->entry_sz);

so the device is handed an IOVA up to 4 GiB past a 128-byte mapping.  The
NIX path has the same shape with the u32 req->rq_cnt/sq_cnt/cq_cnt fields
in rvu_mbox_handler_nix_lf_alloc(), whose values are also programmed into
NIX_AF_LFX_*_BASE.

Since this patch adds a size-validation step at exactly this point, would
it make sense to do the arithmetic in size_t with size_mul()-style
overflow-checked helpers before validating, so the check bounds the real
request?

> +
> +	qmem->base = otx2_dma_alloc_coherent(dev, qmem->alloc_sz, &qmem->iova);
>  	if (!qmem->base)
>  		return -ENOMEM;
>  

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260908063411.257228-1-rkannoth%40marvell.com

      parent reply	other threads:[~2026-09-11  9:36 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08  6:34 Ratheesh Kannoth
2026-09-10 15:00 ` Leon Romanovsky
2026-09-11  9:36 ` netdev-bot+sashiko [this message]

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=178911936770.219967.4327734860588306431@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gakula@marvell.com \
    --cc=kuba@kernel.org \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=rkannoth@marvell.com \
    --cc=sgoutham@marvell.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®