On 14/04/2024 14:59, Niklas Söderlund wrote: > Add initial support for Renesas Ethernet-TSN End-station device of R-Car > V4H. The Ethernet End-station can connect to an Ethernet network using a > 10 Mbps, 100 Mbps, or 1 Gbps full-duplex link via MII/GMII/RMII/RGMII. > Depending on the connected PHY. > > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@xxxxxxxxxxxx> > --- > * Changes since RFC > - Fix issues in MDIO communication. > - Use a dedicated OF node for the MDIO bus. > --- > MAINTAINERS | 8 + > drivers/net/ethernet/renesas/Kconfig | 11 + > drivers/net/ethernet/renesas/Makefile | 2 + > drivers/net/ethernet/renesas/rtsn.c | 1421 +++++++++++++++++++++++++ > drivers/net/ethernet/renesas/rtsn.h | 464 ++++++++ > 5 files changed, 1906 insertions(+) > create mode 100644 drivers/net/ethernet/renesas/rtsn.c > create mode 100644 drivers/net/ethernet/renesas/rtsn.h <snip> > diff --git a/drivers/net/ethernet/renesas/rtsn.c b/drivers/net/ethernet/renesas/rtsn.c > new file mode 100644 > index 000000000000..291ab421d68f > --- /dev/null > +++ b/drivers/net/ethernet/renesas/rtsn.c <snip> > +static bool rtsn_rx(struct net_device *ndev, int *quota) > +{ > + struct rtsn_ext_ts_desc *desc; > + struct rtsn_private *priv; > + struct sk_buff *skb; > + dma_addr_t dma_addr; > + int boguscnt; I find the variable name `boguscnt` very unclear, I'm not sure if it means the count is bogus, or it is counting bogus items? I don't think you need to match what I've done in ravb_main.c exactly, but I'd prefer to see a better variable name here. > + u16 pkt_len; > + u32 get_ts; > + int entry; > + int limit; > + > + priv = netdev_priv(ndev); > + > + entry = priv->cur_rx % priv->num_rx_ring; > + desc = &priv->rx_ring[entry]; > + > + boguscnt = priv->dirty_rx + priv->num_rx_ring - priv->cur_rx; > + boguscnt = min(boguscnt, *quota); > + limit = boguscnt; > + > + while ((desc->die_dt & DT_MASK) != DT_FEMPTY) { > + dma_rmb(); > + pkt_len = le16_to_cpu(desc->info_ds) & RX_DS; > + if (--boguscnt < 0) > + break; > + > + skb = priv->rx_skb[entry]; > + priv->rx_skb[entry] = NULL; > + dma_addr = le32_to_cpu(desc->dptr); > + dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, > + DMA_FROM_DEVICE); > + > + get_ts = priv->ptp_priv->tstamp_rx_ctrl & > + RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT; > + if (get_ts) { > + struct skb_shared_hwtstamps *shhwtstamps; > + struct timespec64 ts; > + > + shhwtstamps = skb_hwtstamps(skb); > + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); > + > + ts.tv_sec = (u64)le32_to_cpu(desc->ts_sec); > + ts.tv_nsec = le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff)); > + > + shhwtstamps->hwtstamp = timespec64_to_ktime(ts); > + } > + > + skb_put(skb, pkt_len); > + skb->protocol = eth_type_trans(skb, ndev); > + netif_receive_skb(skb); > + ndev->stats.rx_packets++; > + ndev->stats.rx_bytes += pkt_len; > + > + entry = (++priv->cur_rx) % priv->num_rx_ring; > + desc = &priv->rx_ring[entry]; > + } > + > + /* Refill the RX ring buffers */ > + for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) { > + entry = priv->dirty_rx % priv->num_rx_ring; > + desc = &priv->rx_ring[entry]; > + desc->info_ds = cpu_to_le16(PKT_BUF_SZ); > + > + if (!priv->rx_skb[entry]) { > + skb = netdev_alloc_skb(ndev, > + PKT_BUF_SZ + RTSN_ALIGN - 1); I'll send my work using a page pool today as an RFC so you can see if it would be beneficial to use that here as well. I was going to hold off until the bugfix patches have merged so that I don't need to go through another RFC round, but it will be good to get some more review on the series anyway. > + if (!skb) > + break; > + skb_reserve(skb, NET_IP_ALIGN); > + dma_addr = dma_map_single(ndev->dev.parent, skb->data, > + le16_to_cpu(desc->info_ds), > + DMA_FROM_DEVICE); > + if (dma_mapping_error(ndev->dev.parent, dma_addr)) > + desc->info_ds = cpu_to_le16(0); > + desc->dptr = cpu_to_le32(dma_addr); > + skb_checksum_none_assert(skb); > + priv->rx_skb[entry] = skb; > + } > + dma_wmb(); > + desc->die_dt = DT_FEMPTY | D_DIE; > + } > + > + desc = &priv->rx_ring[priv->num_rx_ring]; > + desc->die_dt = DT_LINK; > + > + *quota -= limit - (++boguscnt); > + > + return boguscnt <= 0; > +} > + > +static int rtsn_poll(struct napi_struct *napi, int budget) > +{ > + struct rtsn_private *priv; > + struct net_device *ndev; > + unsigned long flags; > + int quota = budget; > + > + ndev = napi->dev; > + priv = netdev_priv(ndev); > + > + /* Processing RX Descriptor Ring */ > + if (rtsn_rx(ndev, "a)) > + goto out; > + > + /* Processing TX Descriptor Ring */ > + spin_lock_irqsave(&priv->lock, flags); > + rtsn_tx_free(ndev, true); > + netif_wake_subqueue(ndev, 0); > + spin_unlock_irqrestore(&priv->lock, flags); > + > + napi_complete(napi); We should use napi_complete_done() here as described in Documentation/networking/napi.rst. That will require rtsn_rx() to return the number of packets received so that it can be passed as the work_done argument to napi_complete_done(). > + > + /* Re-enable TX/RX interrupts */ > + spin_lock_irqsave(&priv->lock, flags); > + rtsn_ctrl_data_irq(priv, true); > + __iowmb(); > + spin_unlock_irqrestore(&priv->lock, flags); > +out: > + return budget - quota; > +} <snip> > +static int rtsn_probe(struct platform_device *pdev) > +{ > + struct rtsn_private *priv; > + struct net_device *ndev; > + struct resource *res; > + int ret; > + > + ndev = alloc_etherdev_mqs(sizeof(struct rtsn_private), TX_NUM_CHAINS, > + RX_NUM_CHAINS); > + if (!ndev) > + return -ENOMEM; > + > + priv = netdev_priv(ndev); > + priv->pdev = pdev; > + priv->ndev = ndev; > + priv->ptp_priv = rcar_gen4_ptp_alloc(pdev); > + > + spin_lock_init(&priv->lock); > + platform_set_drvdata(pdev, priv); > + > + priv->clk = devm_clk_get(&pdev->dev, NULL); > + if (IS_ERR(priv->clk)) { > + ret = -PTR_ERR(priv->clk); > + goto error_alloc; > + } > + > + priv->reset = devm_reset_control_get(&pdev->dev, NULL); > + if (IS_ERR(priv->reset)) { > + ret = -PTR_ERR(priv->reset); > + goto error_alloc; > + } > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tsnes"); > + if (!res) { > + dev_err(&pdev->dev, "Can't find tsnes resource\n"); > + ret = -EINVAL; > + goto error_alloc; > + } > + > + priv->base = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(priv->base)) { > + ret = PTR_ERR(priv->base); > + goto error_alloc; > + } > + > + SET_NETDEV_DEV(ndev, &pdev->dev); > + ether_setup(ndev); > + > + ndev->features = NETIF_F_RXCSUM; > + ndev->hw_features = NETIF_F_RXCSUM; A quick skim of the datasheet suggests that TX checksum calculation is also supported. It's probably worth listing which hardware features this driver supports/does not support in the commit message. Thanks, -- Paul Barker
Attachment:
OpenPGP_0x27F4B3459F002257.asc
Description: OpenPGP public key
Attachment:
OpenPGP_signature.asc
Description: OpenPGP digital signature