All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Srinivas Neeli" <srinivas.neeli@amd.com>
Cc: devicetree@vger.kernel.org, linux-rt-devel@lists.linux.dev,
	robh@kernel.org, conor+dt@kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v4 7/8] net: xilinx: tsn: add the endpoint TX data path
Date: Sat, 14 Nov 2026 12:05:15 +0000	[thread overview]
Message-ID: <sashiko-outbox-214491@kernel.org> (raw)
In-Reply-To: <20261113-patches_v2_external-v4-7-56bb26f042a4@amd.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issues to consider:
- [High] net: xilinx: tsn: ep_stop() terminates TX DMA before
  netif_tx_disable()
- [Medium] net: xilinx: tsn: missing TX DMA error recovery in
  ep_start_xmit()
- [Medium] net: xilinx: tsn: ep_start_xmit() TX flow control ignores DMA
  segment limit
--

commit a8a4f14fcbe22e1b33cd5c8b571aab05e71576de
Author: Srinivas Neeli <srinivas.neeli@amd.com>

net: xilinx: tsn: add the endpoint TX data path

This commit adds the transmit path and TX DMA completion handling for the
Xilinx TSN endpoint driver.

> diff --git a/drivers/net/ethernet/xilinx/tsn/xilinx_tsn_ep.c b/drivers/net/ethernet/xilinx/tsn/xilinx_tsn_ep.c
> index f179062c7d148..6e2721a74f287 100644
> --- a/drivers/net/ethernet/xilinx/tsn/xilinx_tsn_ep.c
> +++ b/drivers/net/ethernet/xilinx/tsn/xilinx_tsn_ep.c

[ ... ]

> @@ -311,8 +316,151 @@ static void ep_dma_rx_cb(void *data, const struct dmaengine_result *result)
>  	ep_rx_refill(xchan, true);
>  }
>  
> +static void ep_dma_tx_cb(void *data, const struct dmaengine_result *result)
> +{
> +	struct xlnx_tsn_ep_dma_chan *xchan = data;
> +	struct skbuf_dma_descriptor *skbuf_dma;
> +	struct netdev_queue *txq;
> +	struct net_device *ndev;
> +	struct scatterlist *sgl;
> +	struct sk_buff *skb;
> +	int sg_len;
> +	int len;
> +
> +	scoped_guard(spinlock_bh, &xchan->tx_lock) {
> +		skbuf_dma = ep_get_desc(xchan,
> +					xchan->ring_tail & (xchan->ring_size - 1));
> +		if (!skbuf_dma || !skbuf_dma->skb)
> +			return;
> +
> +		skb = skbuf_dma->skb;
> +		sgl = skbuf_dma->sgl;
> +		sg_len = skbuf_dma->sg_len;
> +
> +		dma_unmap_sg(xchan->dma_dev, sgl, sg_len, DMA_TO_DEVICE);
> +
> +		skbuf_dma->skb = NULL;
> +		WRITE_ONCE(xchan->ring_tail, xchan->ring_tail + 1);
> +	}
> +
> +	ndev = skb->dev;
> +	txq = netdev_get_tx_queue(ndev, skb_get_queue_mapping(skb));
> +	len = skb->len;
> +
> +	if (unlikely(result->result != DMA_TRANS_NOERROR)) {
> +		DEV_STATS_INC(ndev, tx_errors);
> +		dev_kfree_skb_any(skb);
> +	} else {
> +		DEV_STATS_INC(ndev, tx_packets);
> +		DEV_STATS_ADD(ndev, tx_bytes, len);
> +		dev_consume_skb_any(skb);
> +	}
> +
> +	__netif_txq_completed_wake(txq, 1, len,
> +				   CIRC_SPACE(READ_ONCE(xchan->ring_head),
> +					      READ_ONCE(xchan->ring_tail),
> +					      xchan->ring_size), 2,
> +				   READ_ONCE(xchan->ep->closing));
> +}

[Severity: Medium]
Can an AXI MCDMA channel error leave a stopped TX queue permanently
wedged?

When xilinx_mcdma_irq_handler() handles XILINX_MCDMA_IRQ_ERR_MASK, it sets
chan->err = true, and xilinx_dma_complete_descriptor() only moves
descriptors to done_list when XILINX_DMA_BD_COMP_MASK is set.  In-flight
descriptors that do not complete never invoke ep_dma_tx_cb(), so
xchan->ring_tail does not advance and __netif_txq_completed_wake() is
never called.  If the subqueue was stopped by netif_txq_maybe_stop() or
BQL, ep_start_xmit() will not run again to reset the channel via
xilinx_dma_tx_submit(), and ep_netdev_ops defines no ndo_tx_timeout
callback to recover the channel and drain xchan->skb_ring.

> +
> +static netdev_tx_t ep_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> +{
> +	struct dma_async_tx_descriptor *dma_tx_desc;
> +	struct xlnx_tsn_ep *ep = netdev_priv(ndev);
> +	struct skbuf_dma_descriptor *skbuf_dma;
> +	int queue = skb_get_queue_mapping(skb);
> +	struct xlnx_tsn_ep_dma_chan *xchan;
> +	struct netdev_queue *txq;
> +	int sg_len, nents, ret;
> +	dma_cookie_t cookie;
> +
> +	if (unlikely(queue >= ep->num_tx_queues)) {
> +		if (net_ratelimit())
> +			netdev_warn(ndev, "Invalid TX queue %d (max %u)\n",
> +				    queue, ep->num_tx_queues);
> +		goto err_drop_skb;
> +	}
> +
> +	if (ep->tx_dma_chan_map[queue] == TSN_DMA_CH_INVALID) {
> +		if (net_ratelimit())
> +			netdev_warn(ndev, "Logical TX queue %d has invalid DMA mapping\n",
> +				    queue);
> +		goto err_drop_skb;
> +	}
> +
> +	xchan = ep->tx_chans[queue];
> +
> +	sg_len = skb_shinfo(skb)->nr_frags + 1;
> +	txq = netdev_get_tx_queue(ndev, queue);
> +
> +	spin_lock_bh(&xchan->tx_lock);
> +	if (CIRC_SPACE(xchan->ring_head, READ_ONCE(xchan->ring_tail),
> +		       xchan->ring_size) <= 1) {
> +		netif_txq_try_stop(txq,
> +				   CIRC_SPACE(xchan->ring_head,
> +					      READ_ONCE(xchan->ring_tail),
> +					      xchan->ring_size),
> +				   2);
> +		spin_unlock_bh(&xchan->tx_lock);
> +		if (net_ratelimit())
> +			netdev_warn(ndev, "TSN TX ring full\n");
> +
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	skbuf_dma = ep_get_desc(xchan, xchan->ring_head & (xchan->ring_size - 1));
> +	if (!skbuf_dma) {
> +		spin_unlock_bh(&xchan->tx_lock);
> +		goto err_drop_skb;
> +	}
> +	spin_unlock_bh(&xchan->tx_lock);
> +
> +	sg_init_table(skbuf_dma->sgl, sg_len);
> +	ret = skb_to_sgvec(skb, skbuf_dma->sgl, 0, skb->len);
> +	if (ret < 0)
> +		goto err_drop_skb;
> +	sg_len = ret;
> +
> +	nents = dma_map_sg(xchan->dma_dev, skbuf_dma->sgl, sg_len, DMA_TO_DEVICE);
> +	if (!nents)
> +		goto err_drop_skb;
> +
> +	dma_tx_desc = dmaengine_prep_slave_sg(xchan->chan, skbuf_dma->sgl,
> +					      nents, DMA_MEM_TO_DEV,
> +					      DMA_PREP_INTERRUPT);
> +	if (!dma_tx_desc)
> +		goto err_unmap_sg;

[Severity: Medium]
Can dmaengine_prep_slave_sg() exhaust the MCDMA channel's segment pool and
drop frames while the software ring still has space?

The driver advertises NETIF_F_SG and allows up to MAX_SKB_FRAGS + 1 (18)
scatterlist entries per frame, while queue flow control only checks
CIRC_SPACE() on the 64-frame software ring (up to 62 frames in flight).
In drivers/dma/xilinx/xilinx_dma.c, each MCDMA channel has a pool of
XILINX_DMA_NUM_DESCS (512) segments in chan->free_seg_list.  When
multi-fragment frames in flight consume all 512 segments before 62 frames
are queued, dmaengine_prep_slave_sg() returns NULL and ep_start_xmit()
drops the packet instead of stopping the TX queue.

[ ... ]

> @@ -343,10 +491,16 @@ static int ep_open(struct net_device *ndev)
>  static int ep_stop(struct net_device *ndev)
>  {
>  	struct xlnx_tsn_ep *ep = netdev_priv(ndev);
> +	unsigned int i;
>  
> -	netif_tx_disable(ndev);
>  	WRITE_ONCE(ep->closing, true);
> +	for (i = 0; i < ep->num_tx_queues; i++)
> +		dmaengine_terminate_sync(ep->tx_chans[i]->chan);
> +
> +	netif_tx_disable(ndev);
>  	ep_exit_dmaengine(ep);
> +	for (i = 0; i < ndev->num_tx_queues; i++)
> +		netdev_tx_reset_subqueue(ndev, i);
>  
>  	return 0;
>  }

[Severity: High]
Can ep_start_xmit() race with dmaengine_terminate_sync() when ep_stop()
terminates the TX channels before calling netif_tx_disable()?

Until netif_tx_disable() acquires HARD_TX_LOCK and sets
__QUEUE_STATE_DRV_XOFF, transmit paths that bypass qdisc deactivation
(such as AF_PACKET with PACKET_QDISC_BYPASS via __dev_direct_xmit(), or a
queue using noqueue) can still enter ep_start_xmit(), which does not check
ep->closing:

CPU0                              CPU1
ep_stop()                         __dev_direct_xmit()
  WRITE_ONCE(ep->closing, true)     ep_start_xmit()
  dmaengine_terminate_sync()
    xilinx_dma_terminate_all()
      xilinx_dma_chan_reset()
      chan->terminating = true
      xilinx_dma_free_descriptors()
                                      dmaengine_prep_slave_sg()
                                      dmaengine_submit()
                                        xilinx_dma_tx_submit()
                                          chan->terminating = false
                                      WRITE_ONCE(xchan->ring_head, ...)
                                      dma_async_issue_pending()
  netif_tx_disable()

Calling dma_async_issue_pending() concurrently with
dmaengine_terminate_sync() violates the dmaengine_synchronize() API
contract and races with the unlocked channel reset and descriptor freeing
in xilinx_dma_terminate_all().  In addition, because
xilinx_dma_terminate_all() discards earlier in-flight descriptors without
running ep_dma_tx_cb(), their SKBs remain at xchan->ring_tail; if the
newly issued transfer completes before ep_exit_dmaengine() frees the
channel, ep_dma_tx_cb() pops the stale slot at ring_tail, unmapping and
freeing the wrong skb and passing its length to
__netif_txq_completed_wake().

Calling netif_tx_disable(ndev) after WRITE_ONCE(ep->closing, true) and
before the dmaengine_terminate_sync() loop would serialize against
ep_start_xmit() while still preventing any concurrent ep_dma_tx_cb() from
waking a stopped queue.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-patches_v2_external-v4-0-56bb26f042a4@amd.com?part=7

  reply	other threads:[~2026-11-14 12:05 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-12 18:46 [PATCH net-next v4 0/8] Add Xilinx TSN Endpoint Ethernet MAC driver Srinivas Neeli
2026-11-12 18:46 ` [PATCH net-next v4 1/8] dt-bindings: net: add Xilinx TSN Endpoint Ethernet MAC Srinivas Neeli
2026-11-13 13:20   ` Andrew Lunn
2026-11-13 14:56     ` Neeli, Srinivas
2026-11-13 13:23   ` Andrew Lunn
2026-11-12 18:46 ` [PATCH net-next v4 2/8] net: xilinx: tsn: add TSN endpoint wrapper driver Srinivas Neeli
2026-11-14 12:05   ` sashiko-bot
2026-11-12 18:46 ` [PATCH net-next v4 3/8] net: xilinx: tsn: add endpoint MAC driver skeleton Srinivas Neeli
2026-11-12 18:46 ` [PATCH net-next v4 4/8] net: xilinx: tsn: parse endpoint DMA channel configuration Srinivas Neeli
2026-11-12 18:46 ` [PATCH net-next v4 5/8] net: xilinx: tsn: bring up the endpoint MCDMA channels Srinivas Neeli
2026-11-12 18:46 ` [PATCH net-next v4 6/8] net: xilinx: tsn: add the endpoint RX data path Srinivas Neeli
2026-11-14 12:05   ` sashiko-bot
2026-11-12 18:46 ` [PATCH net-next v4 7/8] net: xilinx: tsn: add the endpoint TX " Srinivas Neeli
2026-11-14 12:05   ` sashiko-bot [this message]
2026-11-12 18:46 ` [PATCH net-next v4 8/8] net: xilinx: tsn: deliver endpoint RX frames to DSA user ports Srinivas Neeli

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=sashiko-outbox-214491@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=srinivas.neeli@amd.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.