Re: [net-next v13 05/11] net: mtip: Add net_device_ops functions to the L2 switch driver
From: Lukasz Majewski <lukma@denx.de>
Date: 2025-06-24 21:33:49
Also in:
imx, linux-arm-kernel, linux-devicetree, lkml
Hi Paolo,
On 6/22/25 11:37 AM, Lukasz Majewski wrote:quoted
This patch provides callbacks for struct net_device_ops for MTIP L2 switch. Signed-off-by: Lukasz Majewski <lukma@denx.de> --- Changes for v13: - New patch - created by excluding some code from large (i.e. v12 and earlier) MTIP driver --- .../net/ethernet/freescale/mtipsw/mtipl2sw.c | 273 ++++++++++++++++++ 1 file changed, 273 insertions(+)diff --git a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.cb/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c index 5142f647d939..813cd39d6d56 100644 --- a/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c +++ b/drivers/net/ethernet/freescale/mtipsw/mtipl2sw.c @@ -43,6 +43,15@@ #include "mtipl2sw.h" +static void swap_buffer(void *bufaddr, int len) +{ + int i; + unsigned int *buf = bufaddr; + + for (i = 0; i < len; i += 4, buf++) + swab32s(buf); +} + /* Set the last buffer to wrap */ static void mtip_set_last_buf_to_wrap(struct cbd_t *bdp) {@@ -444,6 +453,128 @@ static void mtip_config_switch(structswitch_enet_private *fep) fep->hwp + ESW_IMR); } +static netdev_tx_t mtip_start_xmit_port(struct sk_buff *skb, + struct net_device *dev, int port) +{ + struct mtip_ndev_priv *priv = netdev_priv(dev); + struct switch_enet_private *fep = priv->fep; + unsigned short status; + struct cbd_t *bdp; + void *bufaddr; + + spin_lock_bh(&fep->hw_lock); + + if (!fep->link[0] && !fep->link[1]) { + /* Link is down or autonegotiation is in progress. */ + netif_stop_queue(dev); + spin_unlock_bh(&fep->hw_lock); + return NETDEV_TX_BUSY; + } + + /* Fill in a Tx ring entry */ + bdp = fep->cur_tx; + + status = bdp->cbd_sc; + + if (status & BD_ENET_TX_READY) { + /* All transmit buffers are full. Bail out. + * This should not happen, since dev->tbusy should be set. + */ + netif_stop_queue(dev); + dev_err(&fep->pdev->dev, "%s: tx queue full!.\n", dev->name); + spin_unlock_bh(&fep->hw_lock); + return NETDEV_TX_BUSY; + } + + /* Clear all of the status flags */ + status &= ~BD_ENET_TX_STATS; + + /* Set buffer length and buffer pointer */ + bufaddr = skb->data; + bdp->cbd_datlen = skb->len; + + /* On some FEC implementations data must be aligned on + * 4-byte boundaries. Use bounce buffers to copy data + * and get it aligned.spin + */ + if ((unsigned long)bufaddr & MTIP_ALIGNMENT) { + unsigned int index; + + index = bdp - fep->tx_bd_base; + memcpy(fep->tx_bounce[index], + (void *)skb->data, skb->len); + bufaddr = fep->tx_bounce[index]; + } + + if (fep->quirks & FEC_QUIRK_SWAP_FRAME) + swap_buffer(bufaddr, skb->len); + + /* Save skb pointer. */ + fep->tx_skbuff[fep->skb_cur] = skb; + + fep->skb_cur = (fep->skb_cur + 1) & TX_RING_MOD_MASK; + + /* Push the data cache so the CPM does not get stale memory + * data. + */ + bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, + MTIP_SWITCH_TX_FRSIZE, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr))) { + dev_err(&fep->pdev->dev, + "Failed to map descriptor tx buffer\n"); + dev->stats.tx_errors++; + dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + goto err; + } + + /* Send it on its way. Tell FEC it's ready, interrupt when done, + * it's the last BD of the frame, and to put the CRC on the end. + */ + + status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR + | BD_ENET_TX_LAST | BD_ENET_TX_TC); + + /* Synchronize all descriptor writes */ + wmb(); + bdp->cbd_sc = status; + + netif_trans_update(dev); + skb_tx_timestamp(skb); + + /* Trigger transmission start */ + writel(MCF_ESW_TDAR_X_DES_ACTIVE, fep->hwp + ESW_TDAR); + + dev->stats.tx_bytes += skb->len; + /* If this was the last BD in the ring, + * start at the beginning again. + */ + if (status & BD_ENET_TX_WRAP) + bdp = fep->tx_bd_base; + else + bdp++; + + if (bdp == fep->dirty_tx) { + fep->tx_full = 1; + netif_stop_queue(dev);You may want to stop the queue earlier, i.e. when 75% or the like of the tx ring is full. Also you can use netif_txq_maybe_stop() - with txq == netdev_get_tx_queue(dev, 0)
There are two main reasons why the netif queue management is so rugged: 1. Due to simplicity - this driver is not using txq (queues), so I cannot use APIs using as input argument queues. That is why functions accepting only struct netdev pointer are used. 2. My feeling is that I would need to use queues abstraction only for one queue - so this would be extra code overhead. I'm trying to upstream driver which in fact has very simple internals (i.e. ringbuf with 16 descriptors for tx/rx).
[...]quoted
+static void mtip_timeout(struct net_device *dev, unsigned int txqueue) +{ + struct mtip_ndev_priv *priv = netdev_priv(dev); + struct switch_enet_private *fep = priv->fep; + struct cbd_t *bdp; + int i; + + dev->stats.tx_errors++; + + if (IS_ENABLED(CONFIG_SWITCH_DEBUG)) { + dev_info(&dev->dev, "%s: transmit timed out.\n", dev->name); + dev_info(&dev->dev, + "Ring data: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", + (unsigned long)fep->cur_tx, + fep->tx_full ? " (full)" : "", + (unsigned long)fep->dirty_tx, + (unsigned long)fep->cur_rx); + + bdp = fep->tx_bd_base; + dev_info(&dev->dev, " tx: %u buffers\n", TX_RING_SIZE); + for (i = 0; i < TX_RING_SIZE; i++) { + dev_info(&dev->dev, " %08lx: %04x %04x %08x\n", + (kernel_ulong_t)bdp, bdp->cbd_sc, + bdp->cbd_datlen, (int)bdp->cbd_bufaddr); + bdp++; + } + + bdp = fep->rx_bd_base; + dev_info(&dev->dev, " rx: %lu buffers\n", + (unsigned long)RX_RING_SIZE); + for (i = 0 ; i < RX_RING_SIZE; i++) { + dev_info(&dev->dev, " %08lx: %04x %04x %08x\n", + (kernel_ulong_t)bdp, + bdp->cbd_sc, bdp->cbd_datlen, + (int)bdp->cbd_bufaddr); + bdp++; + }Here you are traversing both rings without any lock, which looks race prone.
I will add spin_{un}lock_bh(&fep->hw_lock); (this is only code used
for debugging, not production)
/P
Best regards, Lukasz Majewski -- DENX Software Engineering GmbH, Managing Director: Erika Unter HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Attachments
- (unnamed) [application/pgp-signature] 488 bytes