[PATCH net-next v20 07/13] rtase: Implement a function to receive packets

Justin Lai posted 13 patches 1 year, 8 months ago
There is a newer version of this series
[PATCH net-next v20 07/13] rtase: Implement a function to receive packets
Posted by Justin Lai 1 year, 8 months ago
Implement rx_handler to read the information of the rx descriptor,
thereby checking the packet accordingly and storing the packet
in the socket buffer to complete the reception of the packet.

Signed-off-by: Justin Lai <justinlai0215@realtek.com>
---
 .../net/ethernet/realtek/rtase/rtase_main.c   | 146 ++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 6bdb4edbfbc1..9ee9f30444f3 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -458,6 +458,152 @@ static void rtase_rx_ring_clear(struct rtase_ring *ring)
 	}
 }
 
+static int rtase_fragmented_frame(u32 status)
+{
+	return (status & (RTASE_RX_FIRST_FRAG | RTASE_RX_LAST_FRAG)) !=
+		(RTASE_RX_FIRST_FRAG | RTASE_RX_LAST_FRAG);
+}
+
+static void rtase_rx_csum(const struct rtase_private *tp, struct sk_buff *skb,
+			  const union rtase_rx_desc *desc)
+{
+	u32 opts2 = le32_to_cpu(desc->desc_status.opts2);
+
+	/* rx csum offload */
+	if (((opts2 & RTASE_RX_V4F) && !(opts2 & RTASE_RX_IPF)) ||
+	    (opts2 & RTASE_RX_V6F)) {
+		if (((opts2 & RTASE_RX_TCPT) && !(opts2 & RTASE_RX_TCPF)) ||
+		    ((opts2 & RTASE_RX_UDPT) && !(opts2 & RTASE_RX_UDPF))) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		} else {
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+	} else {
+		skb->ip_summed = CHECKSUM_NONE;
+	}
+}
+
+static void rtase_rx_vlan_skb(union rtase_rx_desc *desc, struct sk_buff *skb)
+{
+	u32 opts2 = le32_to_cpu(desc->desc_status.opts2);
+
+	if (!(opts2 & RTASE_RX_VLAN_TAG))
+		return;
+
+	__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+			       swab16(opts2 & RTASE_VLAN_TAG_MASK));
+}
+
+static void rtase_rx_skb(const struct rtase_ring *ring, struct sk_buff *skb)
+{
+	struct rtase_int_vector *ivec = ring->ivec;
+
+	napi_gro_receive(&ivec->napi, skb);
+}
+
+static int rx_handler(struct rtase_ring *ring, int budget)
+{
+	const struct rtase_private *tp = ring->ivec->tp;
+	union rtase_rx_desc *desc_base = ring->desc;
+	u32 pkt_size, cur_rx, delta, entry, status;
+	struct net_device *dev = tp->dev;
+	union rtase_rx_desc *desc;
+	struct sk_buff *skb;
+	int workdone = 0;
+
+	cur_rx = ring->cur_idx;
+	entry = cur_rx % RTASE_NUM_DESC;
+	desc = &desc_base[entry];
+
+	do {
+		/* make sure discriptor has been updated */
+		rmb();
+		status = le32_to_cpu(desc->desc_status.opts1);
+
+		if (status & RTASE_DESC_OWN)
+			break;
+
+		if (unlikely(status & RTASE_RX_RES)) {
+			if (net_ratelimit())
+				netdev_warn(dev, "Rx ERROR. status = %08x\n",
+					    status);
+
+			dev->stats.rx_errors++;
+
+			if (status & (RTASE_RX_RWT | RTASE_RX_RUNT))
+				dev->stats.rx_length_errors++;
+
+			if (status & RTASE_RX_CRC)
+				dev->stats.rx_crc_errors++;
+
+			if (dev->features & NETIF_F_RXALL)
+				goto process_pkt;
+
+			rtase_mark_to_asic(desc, tp->rx_buf_sz);
+			goto skip_process_pkt;
+		}
+
+process_pkt:
+		pkt_size = status & RTASE_RX_PKT_SIZE_MASK;
+		if (likely(!(dev->features & NETIF_F_RXFCS)))
+			pkt_size -= ETH_FCS_LEN;
+
+		/* the driver does not support incoming fragmented
+		 * frames. they are seen as a symptom of over-mtu
+		 * sized frames
+		 */
+		if (unlikely(rtase_fragmented_frame(status))) {
+			dev->stats.rx_dropped++;
+			dev->stats.rx_length_errors++;
+			rtase_mark_to_asic(desc, tp->rx_buf_sz);
+			continue;
+		}
+
+		skb = ring->skbuff[entry];
+		dma_sync_single_for_cpu(&tp->pdev->dev,
+					ring->mis.data_phy_addr[entry],
+					tp->rx_buf_sz, DMA_FROM_DEVICE);
+
+		ring->skbuff[entry] = NULL;
+
+		if (dev->features & NETIF_F_RXCSUM)
+			rtase_rx_csum(tp, skb, desc);
+
+		skb->dev = dev;
+		skb_put(skb, pkt_size);
+		skb_mark_for_recycle(skb);
+		skb->protocol = eth_type_trans(skb, dev);
+
+		if (skb->pkt_type == PACKET_MULTICAST)
+			dev->stats.multicast++;
+
+		rtase_rx_vlan_skb(desc, skb);
+		rtase_rx_skb(ring, skb);
+
+		dev_sw_netstats_rx_add(dev, pkt_size);
+
+skip_process_pkt:
+		workdone++;
+		cur_rx++;
+		entry = cur_rx % RTASE_NUM_DESC;
+		desc = ring->desc + sizeof(union rtase_rx_desc) * entry;
+		prefetch(desc);
+	} while (workdone != budget);
+
+	ring->cur_idx = cur_rx;
+	delta = rtase_rx_ring_fill(ring, ring->dirty_idx, ring->cur_idx, 1);
+
+	if (!delta && workdone)
+		netdev_info(dev, "no Rx buffer allocated\n");
+
+	ring->dirty_idx += delta;
+
+	if ((ring->dirty_idx + RTASE_NUM_DESC) == ring->cur_idx)
+		netdev_emerg(dev, "Rx buffers exhausted\n");
+
+	return workdone;
+}
+
 static void rtase_rx_desc_init(struct rtase_private *tp, u16 idx)
 {
 	struct rtase_ring *ring = &tp->rx_ring[idx];
-- 
2.34.1
Re: [PATCH net-next v20 07/13] rtase: Implement a function to receive packets
Posted by Jakub Kicinski 1 year, 8 months ago
On Fri, 7 Jun 2024 16:43:15 +0800 Justin Lai wrote:
> +static int rx_handler(struct rtase_ring *ring, int budget)
> +{
> +	const struct rtase_private *tp = ring->ivec->tp;
> +	union rtase_rx_desc *desc_base = ring->desc;
> +	u32 pkt_size, cur_rx, delta, entry, status;
> +	struct net_device *dev = tp->dev;
> +	union rtase_rx_desc *desc;
> +	struct sk_buff *skb;
> +	int workdone = 0;
> +
> +	cur_rx = ring->cur_idx;
> +	entry = cur_rx % RTASE_NUM_DESC;
> +	desc = &desc_base[entry];
> +
> +	do {
> +		/* make sure discriptor has been updated */
> +		rmb();

Barriers are between things. What is this barrier between?

> +		status = le32_to_cpu(desc->desc_status.opts1);
> +
> +		if (status & RTASE_DESC_OWN)
> +			break;
RE: [PATCH net-next v20 07/13] rtase: Implement a function to receive packets
Posted by Justin Lai 1 year, 8 months ago
> On Fri, 7 Jun 2024 16:43:15 +0800 Justin Lai wrote:
> > +static int rx_handler(struct rtase_ring *ring, int budget) {
> > +     const struct rtase_private *tp = ring->ivec->tp;
> > +     union rtase_rx_desc *desc_base = ring->desc;
> > +     u32 pkt_size, cur_rx, delta, entry, status;
> > +     struct net_device *dev = tp->dev;
> > +     union rtase_rx_desc *desc;
> > +     struct sk_buff *skb;
> > +     int workdone = 0;
> > +
> > +     cur_rx = ring->cur_idx;
> > +     entry = cur_rx % RTASE_NUM_DESC;
> > +     desc = &desc_base[entry];
> > +
> > +     do {
> > +             /* make sure discriptor has been updated */
> > +             rmb();
> 
> Barriers are between things. What is this barrier between?

At the end of this do while loop, it fetches the next descriptor. This
barrier is mainly used between fetching the next descriptor and using
the next descriptor, to ensure that the content of the next descriptor is
completely fetched before using it.

> 
> > +             status = le32_to_cpu(desc->desc_status.opts1);
> > +
> > +             if (status & RTASE_DESC_OWN)
> > +                     break;
Re: [PATCH net-next v20 07/13] rtase: Implement a function to receive packets
Posted by Jakub Kicinski 1 year, 8 months ago
On Mon, 17 Jun 2024 06:44:55 +0000 Justin Lai wrote:
> > > +             /* make sure discriptor has been updated */
> > > +             rmb();  
> > 
> > Barriers are between things. What is this barrier between?  
> 
> At the end of this do while loop, it fetches the next descriptor. This
> barrier is mainly used between fetching the next descriptor and using
> the next descriptor, to ensure that the content of the next descriptor is
> completely fetched before using it.

What does it mean to "fetch the next descriptor"? The prefetch?
Prefetches are not ordered at all.
RE: [PATCH net-next v20 07/13] rtase: Implement a function to receive packets
Posted by Justin Lai 1 year, 7 months ago
> On Mon, 17 Jun 2024 06:44:55 +0000 Justin Lai wrote:
> > > > +             /* make sure discriptor has been updated */
> > > > +             rmb();
> > >
> > > Barriers are between things. What is this barrier between?
> >
> > At the end of this do while loop, it fetches the next descriptor. This
> > barrier is mainly used between fetching the next descriptor and using
> > the next descriptor, to ensure that the content of the next descriptor
> > is completely fetched before using it.
> 
> What does it mean to "fetch the next descriptor"? The prefetch?
> Prefetches are not ordered at all.

Let me explain again, at the end of the do while loop in rx_handler, we
have changed the address pointed by desc to the next descriptor.
Therefore, the main purpose of this barrier is to ensure that both desc
and cur_rx have been updated to the next entry.