netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Justin Lai <justinlai0215@realtek.com>
To: Hariprasad Kelam <hkelam@marvell.com>,
	"kuba@kernel.org" <kuba@kernel.org>
Cc: "davem@davemloft.net" <davem@davemloft.net>,
	"edumazet@google.com" <edumazet@google.com>,
	"pabeni@redhat.com" <pabeni@redhat.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"andrew@lunn.ch" <andrew@lunn.ch>,
	"jiri@resnulli.us" <jiri@resnulli.us>,
	"horms@kernel.org" <horms@kernel.org>,
	Ratheesh Kannoth <rkannoth@marvell.com>,
	Ping-Ke Shih <pkshih@realtek.com>,
	Larry Chiu <larry.chiu@realtek.com>
Subject: RE: [PATCH net-next v20 06/13] rtase: Implement .ndo_start_xmit function
Date: Wed, 12 Jun 2024 04:35:13 +0000	[thread overview]
Message-ID: <89c92725271a4fa28dbf1e37f3fd5e99@realtek.com> (raw)
In-Reply-To: <PH0PR18MB44745E2CFEA3CC1D9ADC5AC0DEFB2@PH0PR18MB4474.namprd18.prod.outlook.com>

> > Implement .ndo_start_xmit function to fill the information of the
> > packet to be transmitted into the tx descriptor, and then the hardware
> > will transmit the packet using the information in the tx descriptor.
> > In addition, we also implemented the tx_handler function to enable the
> > tx descriptor to be reused.
> >
> > Signed-off-by: Justin Lai <justinlai0215@realtek.com>
> > ---
> >  .../net/ethernet/realtek/rtase/rtase_main.c   | 285 ++++++++++++++++++
> >  1 file changed, 285 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > b/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > index 23406c195cff..6bdb4edbfbc1 100644
> > --- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > @@ -256,6 +256,68 @@ static void rtase_mark_to_asic(union
> > rtase_rx_desc *desc, u32 rx_buf_sz)
> >                  cpu_to_le32(RTASE_DESC_OWN | eor | rx_buf_sz));  }
> >
> > +static u32 rtase_tx_avail(struct rtase_ring *ring) {
> > +     return READ_ONCE(ring->dirty_idx) + RTASE_NUM_DESC -
> > +            READ_ONCE(ring->cur_idx); }
> > +
> > +static int tx_handler(struct rtase_ring *ring, int budget) {
> > +     const struct rtase_private *tp = ring->ivec->tp;
> > +     struct net_device *dev = tp->dev;
> > +     u32 dirty_tx, tx_left;
> > +     u32 bytes_compl = 0;
> > +     u32 pkts_compl = 0;
> > +     int workdone = 0;
> > +
> > +     dirty_tx = ring->dirty_idx;
> > +     tx_left = READ_ONCE(ring->cur_idx) - dirty_tx;
> > +
> > +     while (tx_left > 0) {
> > +             u32 entry = dirty_tx % RTASE_NUM_DESC;
> > +             struct rtase_tx_desc *desc = ring->desc +
> > +                                    sizeof(struct rtase_tx_desc) *
> entry;
> > +             u32 status;
> > +
> > +             status = le32_to_cpu(desc->opts1);
> > +
> > +             if (status & RTASE_DESC_OWN)
> > +                     break;
> > +
> > +             rtase_unmap_tx_skb(tp->pdev, ring->mis.len[entry], desc);
> > +             ring->mis.len[entry] = 0;
> > +             if (ring->skbuff[entry]) {
> > +                     pkts_compl++;
> > +                     bytes_compl += ring->skbuff[entry]->len;
> > +                     napi_consume_skb(ring->skbuff[entry], budget);
> > +                     ring->skbuff[entry] = NULL;
> > +             }
> > +
> > +             dirty_tx++;
> > +             tx_left--;
> > +             workdone++;
> > +
> > +             if (workdone == RTASE_TX_BUDGET_DEFAULT)
> > +                     break;
> > +     }
> > +
> > +     if (ring->dirty_idx != dirty_tx) {
> > +             dev_sw_netstats_tx_add(dev, pkts_compl, bytes_compl);
> > +             WRITE_ONCE(ring->dirty_idx, dirty_tx);
> > +
> > +             netif_subqueue_completed_wake(dev, ring->index,
> > pkts_compl,
> > +                                           bytes_compl,
> > +                                           rtase_tx_avail(ring),
> > +
> RTASE_TX_START_THRS);
> > +
> > +             if (ring->cur_idx != dirty_tx)
> > +                     rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index));
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> >  static void rtase_tx_desc_init(struct rtase_private *tp, u16 idx)  {
> >       struct rtase_ring *ring = &tp->tx_ring[idx]; @@ -1014,6
> > +1076,228 @@ static int rtase_close(struct net_device *dev)
> >       return 0;
> >  }
> >
> > +static u32 rtase_tx_vlan_tag(const struct rtase_private *tp,
> > +                          const struct sk_buff *skb) {
> > +     return (skb_vlan_tag_present(skb)) ?
> > +             (RTASE_TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb))) :
> > 0x00; }
> > +
>                Vlan protocol can be either 0x8100 or 0x88A8, how does
> hardware know which header to insert?
> Thanks,
> Hariprasad k

We only allow the hardware to add 0x8100, the VLAN must at least have
0x8100 to potentially have 0x88a8, skb_vlan_tag_present indicates that
VLAN exists, hence at least the 0x8100 VLAN would exist.
> 
> > +static u32 rtase_tx_csum(struct sk_buff *skb, const struct net_device
> > +*dev) {
> > +     u32 csum_cmd = 0;
> > +     u8 ip_protocol;
> > +
> > +     switch (vlan_get_protocol(skb)) {
> > +     case htons(ETH_P_IP):
> > +             csum_cmd = RTASE_TX_IPCS_C;
> > +             ip_protocol = ip_hdr(skb)->protocol;
> > +             break;
> > +
> > +     case htons(ETH_P_IPV6):
> > +             csum_cmd = RTASE_TX_IPV6F_C;
> > +             ip_protocol = ipv6_hdr(skb)->nexthdr;
> > +             break;
> > +
> > +     default:
> > +             ip_protocol = IPPROTO_RAW;
> > +             break;
> > +     }
> > +
> > +     if (ip_protocol == IPPROTO_TCP)
> > +             csum_cmd |= RTASE_TX_TCPCS_C;
> > +     else if (ip_protocol == IPPROTO_UDP)
> > +             csum_cmd |= RTASE_TX_UDPCS_C;
> > +
> > +     csum_cmd |= u32_encode_bits(skb_transport_offset(skb),
> > +                                 RTASE_TCPHO_MASK);
> > +
> > +     return csum_cmd;
> > +}
> > +
> > +static int rtase_xmit_frags(struct rtase_ring *ring, struct sk_buff *skb,
> > +                         u32 opts1, u32 opts2) {
> > +     const struct skb_shared_info *info = skb_shinfo(skb);
> > +     const struct rtase_private *tp = ring->ivec->tp;
> > +     const u8 nr_frags = info->nr_frags;
> > +     struct rtase_tx_desc *txd = NULL;
> > +     u32 cur_frag, entry;
> > +
> > +     entry = ring->cur_idx;
> > +     for (cur_frag = 0; cur_frag < nr_frags; cur_frag++) {
> > +             const skb_frag_t *frag = &info->frags[cur_frag];
> > +             dma_addr_t mapping;
> > +             u32 status, len;
> > +             void *addr;
> > +
> > +             entry = (entry + 1) % RTASE_NUM_DESC;
> > +
> > +             txd = ring->desc + sizeof(struct rtase_tx_desc) * entry;
> > +             len = skb_frag_size(frag);
> > +             addr = skb_frag_address(frag);
> > +             mapping = dma_map_single(&tp->pdev->dev, addr, len,
> > +                                      DMA_TO_DEVICE);
> > +
> > +             if (unlikely(dma_mapping_error(&tp->pdev->dev,
> > + mapping)))
> > {
> > +                     if (unlikely(net_ratelimit()))
> > +                             netdev_err(tp->dev,
> > +                                        "Failed to map TX
> fragments
> > DMA!\n");
> > +
> > +                     goto err_out;
> > +             }
> > +
> > +             if (((entry + 1) % RTASE_NUM_DESC) == 0)
> > +                     status = (opts1 | len | RTASE_RING_END);
> > +             else
> > +                     status = opts1 | len;
> > +
> > +             if (cur_frag == (nr_frags - 1)) {
> > +                     ring->skbuff[entry] = skb;
> > +                     status |= RTASE_TX_LAST_FRAG;
> > +             }
> > +
> > +             ring->mis.len[entry] = len;
> > +             txd->addr = cpu_to_le64(mapping);
> > +             txd->opts2 = cpu_to_le32(opts2);
> > +
> > +             /* make sure the operating fields have been updated */
> > +             dma_wmb();
> > +             txd->opts1 = cpu_to_le32(status);
> > +     }
> > +
> > +     return cur_frag;
> > +
> > +err_out:
> > +     rtase_tx_clear_range(ring, ring->cur_idx + 1, cur_frag);
> > +     return -EIO;
> > +}
> > +
> > +static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
> > +                                 struct net_device *dev) {
> > +     struct skb_shared_info *shinfo = skb_shinfo(skb);
> > +     struct rtase_private *tp = netdev_priv(dev);
> > +     u32 q_idx, entry, len, opts1, opts2;
> > +     struct netdev_queue *tx_queue;
> > +     bool stop_queue, door_bell;
> > +     u32 mss = shinfo->gso_size;
> > +     struct rtase_tx_desc *txd;
> > +     struct rtase_ring *ring;
> > +     dma_addr_t mapping;
> > +     int frags;
> > +
> > +     /* multiqueues */
> > +     q_idx = skb_get_queue_mapping(skb);
> > +     ring = &tp->tx_ring[q_idx];
> > +     tx_queue = netdev_get_tx_queue(dev, q_idx);
> > +
> > +     if (unlikely(!rtase_tx_avail(ring))) {
> > +             if (net_ratelimit())
> > +                     netdev_err(dev, "BUG! Tx Ring full when queue
> > awake!\n");
> > +             goto err_stop;
> > +     }
> > +
> > +     entry = ring->cur_idx % RTASE_NUM_DESC;
> > +     txd = ring->desc + sizeof(struct rtase_tx_desc) * entry;
> > +
> > +     opts1 = RTASE_DESC_OWN;
> > +     opts2 = rtase_tx_vlan_tag(tp, skb);
> > +
> > +     /* tcp segmentation offload (or tcp large send) */
> > +     if (mss) {
> > +             if (shinfo->gso_type & SKB_GSO_TCPV4) {
> > +                     opts1 |= RTASE_GIANT_SEND_V4;
> > +             } else if (shinfo->gso_type & SKB_GSO_TCPV6) {
> > +                     if (skb_cow_head(skb, 0))
> > +                             goto err_dma_0;
> > +
> > +                     tcp_v6_gso_csum_prep(skb);
> > +                     opts1 |= RTASE_GIANT_SEND_V6;
> > +             } else {
> > +                     WARN_ON_ONCE(1);
> > +             }
> > +
> > +             opts1 |= u32_encode_bits(skb_transport_offset(skb),
> > +                                      RTASE_TCPHO_MASK);
> > +             opts2 |= u32_encode_bits(mss, RTASE_MSS_MASK);
> > +     } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
> > +             opts2 |= rtase_tx_csum(skb, dev);
> > +     }
> > +
> > +     frags = rtase_xmit_frags(ring, skb, opts1, opts2);
> > +     if (unlikely(frags < 0))
> > +             goto err_dma_0;
> > +
> > +     if (frags) {
> > +             len = skb_headlen(skb);
> > +             opts1 |= RTASE_TX_FIRST_FRAG;
> > +     } else {
> > +             len = skb->len;
> > +             ring->skbuff[entry] = skb;
> > +             opts1 |= RTASE_TX_FIRST_FRAG | RTASE_TX_LAST_FRAG;
> > +     }
> > +
> > +     if (((entry + 1) % RTASE_NUM_DESC) == 0)
> > +             opts1 |= (len | RTASE_RING_END);
> > +     else
> > +             opts1 |= len;
> > +
> > +     mapping = dma_map_single(&tp->pdev->dev, skb->data, len,
> > +                              DMA_TO_DEVICE);
> > +
> > +     if (unlikely(dma_mapping_error(&tp->pdev->dev, mapping))) {
> > +             if (unlikely(net_ratelimit()))
> > +                     netdev_err(dev, "Failed to map TX DMA!\n");
> > +
> > +             goto err_dma_1;
> > +     }
> > +
> > +     ring->mis.len[entry] = len;
> > +     txd->addr = cpu_to_le64(mapping);
> > +     txd->opts2 = cpu_to_le32(opts2);
> > +     txd->opts1 = cpu_to_le32(opts1 & ~RTASE_DESC_OWN);
> > +
> > +     /* make sure the operating fields have been updated */
> > +     dma_wmb();
> > +
> > +     door_bell = __netdev_tx_sent_queue(tx_queue, skb->len,
> > +                                        netdev_xmit_more());
> > +
> > +     txd->opts1 = cpu_to_le32(opts1);
> > +
> > +     skb_tx_timestamp(skb);
> > +
> > +     /* tx needs to see descriptor changes before updated cur_idx */
> > +     smp_wmb();
> > +
> > +     WRITE_ONCE(ring->cur_idx, ring->cur_idx + frags + 1);
> > +
> > +     stop_queue = !netif_subqueue_maybe_stop(dev, ring->index,
> > +                                             rtase_tx_avail(ring),
> > +
> RTASE_TX_STOP_THRS,
> > +
> RTASE_TX_START_THRS);
> > +
> > +     if (door_bell || stop_queue)
> > +             rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index));
> > +
> > +     return NETDEV_TX_OK;
> > +
> > +err_dma_1:
> > +     ring->skbuff[entry] = NULL;
> > +     rtase_tx_clear_range(ring, ring->cur_idx + 1, frags);
> > +
> > +err_dma_0:
> > +     dev->stats.tx_dropped++;
> > +     dev_kfree_skb_any(skb);
> > +     return NETDEV_TX_OK;
> > +
> > +err_stop:
> > +     netif_stop_queue(dev);
> > +     dev->stats.tx_dropped++;
> > +     return NETDEV_TX_BUSY;
> > +}
> > +
> >  static void rtase_enable_eem_write(const struct rtase_private *tp)  {
> >       u8 val;
> > @@ -1065,6 +1349,7 @@ static void rtase_netpoll(struct net_device
> > *dev) static const struct net_device_ops rtase_netdev_ops = {
> >       .ndo_open = rtase_open,
> >       .ndo_stop = rtase_close,
> > +     .ndo_start_xmit = rtase_start_xmit,
> >  #ifdef CONFIG_NET_POLL_CONTROLLER
> >       .ndo_poll_controller = rtase_netpoll,  #endif
> > --
> > 2.34.1
> >


  reply	other threads:[~2024-06-12  4:39 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-07  8:43 [PATCH net-next v20 00/13] Add Realtek automotive PCIe driver Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 01/13] rtase: Add pci table supported in this module Justin Lai
2024-06-13  9:01   ` Markus Elfring
2024-06-17  8:14     ` Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 02/13] rtase: Implement the .ndo_open function Justin Lai
2024-06-13  7:50   ` Markus Elfring
2024-06-17  9:25     ` Justin Lai
2024-06-17 10:07       ` [v20 " Markus Elfring
2024-06-17 13:28         ` Justin Lai
2024-06-17 18:59           ` Simon Horman
2024-06-17 20:22             ` Markus Elfring
2024-06-18  7:51             ` Justin Lai
     [not found]             ` <202406181007.45IA7eWxA3305754@rtits1.realtek.com.tw>
2024-06-18 11:01               ` Justin Lai
2024-06-18 11:30                 ` Markus Elfring
2024-06-07  8:43 ` [PATCH net-next v20 03/13] rtase: Implement the rtase_down function Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 04/13] rtase: Implement the interrupt routine and rtase_poll Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 05/13] rtase: Implement hardware configuration function Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 06/13] rtase: Implement .ndo_start_xmit function Justin Lai
2024-06-07  9:03   ` Hariprasad Kelam
2024-06-12  4:35     ` Justin Lai [this message]
2024-06-12 10:36       ` Hariprasad Kelam
2024-06-13  3:38         ` Justin Lai
2024-06-13  7:24           ` Hariprasad Kelam
2024-06-07 15:54   ` Ratheesh Kannoth
2024-06-12  4:20     ` Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 07/13] rtase: Implement a function to receive packets Justin Lai
2024-06-13  0:43   ` Jakub Kicinski
2024-06-17  6:44     ` Justin Lai
2024-06-17 15:02       ` Jakub Kicinski
2024-06-18  3:40         ` Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 08/13] rtase: Implement net_device_ops Justin Lai
2024-06-13  0:39   ` Jakub Kicinski
2024-06-13  3:16     ` Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 09/13] rtase: Implement pci_driver suspend and resume function Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 10/13] rtase: Implement ethtool function Justin Lai
2024-06-13  0:35   ` Jakub Kicinski
2024-06-17  6:54     ` Justin Lai
2024-06-17 14:07       ` Andrew Lunn
2024-06-18  9:56         ` Justin Lai
2024-06-17 15:10       ` Jakub Kicinski
2024-06-18  7:28         ` Justin Lai
2024-06-18 14:24           ` Jakub Kicinski
2024-06-19  3:40             ` Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 11/13] rtase: Add a Makefile in the rtase folder Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 12/13] realtek: Update the Makefile and Kconfig in the realtek folder Justin Lai
2024-06-07  8:43 ` [PATCH net-next v20 13/13] MAINTAINERS: Add the rtase ethernet driver entry Justin Lai

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=89c92725271a4fa28dbf1e37f3fd5e99@realtek.com \
    --to=justinlai0215@realtek.com \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=hkelam@marvell.com \
    --cc=horms@kernel.org \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=larry.chiu@realtek.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pkshih@realtek.com \
    --cc=rkannoth@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;
as well as URLs for NNTP newsgroup(s).