Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3cd9657 authored by Stanislaw Gruszka's avatar Stanislaw Gruszka Committed by David S. Miller
Browse files

myri10ge: small rx_done refactoring



Avoid theoretical race condition regarding accessing dev->features
NETIF_F_LRO flag, which is illustrated below.

CPU1					CPU2

myri10ge_clean_rx_done():		myri10ge_set_flags():
					or
					myri10ge_set_rx_csum():

if (dev->features & NETIF_F_LRO)
        setup lro
					dev->features |= NETIF_F_LRO
					or
					dev->features &= ~NETIF_F_LRO;
if (dev->features & NETIF_F_LRO)
        flush lro

On the way reduce myri10ge_rx_done() number of arguments and calls by
moving mgp->small_bytes check into that function. That reduce code size

from:
   text	   data	    bss	    dec	    hex	filename
  36644	    248	    100	  36992	   9080	drivers/net/myri10ge/myri10ge.o

to:
   text	   data	    bss	    dec	    hex	filename
  36037	    247	    100	  36384	   8e20	drivers/net/myri10ge/myri10ge.o

on my i686 system, what should also make myri10ge_clean_rx_done()
being faster.

Signed-off-by: default avatarStanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent edf947f1
Loading
Loading
Loading
Loading
+23 −14
Original line number Original line Diff line number Diff line
@@ -1312,17 +1312,26 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev,
				 * page into an skb */
				 * page into an skb */


static inline int
static inline int
myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
		 int bytes, int len, __wsum csum)
		 int lro_enabled)
{
{
	struct myri10ge_priv *mgp = ss->mgp;
	struct myri10ge_priv *mgp = ss->mgp;
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
	struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME];
	int i, idx, hlen, remainder;
	struct myri10ge_rx_buf *rx;
	int i, idx, hlen, remainder, bytes;
	struct pci_dev *pdev = mgp->pdev;
	struct pci_dev *pdev = mgp->pdev;
	struct net_device *dev = mgp->dev;
	struct net_device *dev = mgp->dev;
	u8 *va;
	u8 *va;


	if (len <= mgp->small_bytes) {
		rx = &ss->rx_small;
		bytes = mgp->small_bytes;
	} else {
		rx = &ss->rx_big;
		bytes = mgp->big_bytes;
	}

	len += MXGEFW_PAD;
	len += MXGEFW_PAD;
	idx = rx->cnt & rx->mask;
	idx = rx->cnt & rx->mask;
	va = page_address(rx->info[idx].page) + rx->info[idx].page_offset;
	va = page_address(rx->info[idx].page) + rx->info[idx].page_offset;
@@ -1341,7 +1350,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
		remainder -= MYRI10GE_ALLOC_SIZE;
		remainder -= MYRI10GE_ALLOC_SIZE;
	}
	}


	if (dev->features & NETIF_F_LRO) {
	if (lro_enabled) {
		rx_frags[0].page_offset += MXGEFW_PAD;
		rx_frags[0].page_offset += MXGEFW_PAD;
		rx_frags[0].size -= MXGEFW_PAD;
		rx_frags[0].size -= MXGEFW_PAD;
		len -= MXGEFW_PAD;
		len -= MXGEFW_PAD;
@@ -1463,7 +1472,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
{
{
	struct myri10ge_rx_done *rx_done = &ss->rx_done;
	struct myri10ge_rx_done *rx_done = &ss->rx_done;
	struct myri10ge_priv *mgp = ss->mgp;
	struct myri10ge_priv *mgp = ss->mgp;
	struct net_device *netdev = mgp->dev;

	unsigned long rx_bytes = 0;
	unsigned long rx_bytes = 0;
	unsigned long rx_packets = 0;
	unsigned long rx_packets = 0;
	unsigned long rx_ok;
	unsigned long rx_ok;
@@ -1474,18 +1483,18 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
	u16 length;
	u16 length;
	__wsum checksum;
	__wsum checksum;


	/*
	 * Prevent compiler from generating more than one ->features memory
	 * access to avoid theoretical race condition with functions that
	 * change NETIF_F_LRO flag at runtime.
	 */
	bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO;

	while (rx_done->entry[idx].length != 0 && work_done < budget) {
	while (rx_done->entry[idx].length != 0 && work_done < budget) {
		length = ntohs(rx_done->entry[idx].length);
		length = ntohs(rx_done->entry[idx].length);
		rx_done->entry[idx].length = 0;
		rx_done->entry[idx].length = 0;
		checksum = csum_unfold(rx_done->entry[idx].checksum);
		checksum = csum_unfold(rx_done->entry[idx].checksum);
		if (length <= mgp->small_bytes)
		rx_ok = myri10ge_rx_done(ss, length, checksum, lro_enabled);
			rx_ok = myri10ge_rx_done(ss, &ss->rx_small,
						 mgp->small_bytes,
						 length, checksum);
		else
			rx_ok = myri10ge_rx_done(ss, &ss->rx_big,
						 mgp->big_bytes,
						 length, checksum);
		rx_packets += rx_ok;
		rx_packets += rx_ok;
		rx_bytes += rx_ok * (unsigned long)length;
		rx_bytes += rx_ok * (unsigned long)length;
		cnt++;
		cnt++;
@@ -1497,7 +1506,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
	ss->stats.rx_packets += rx_packets;
	ss->stats.rx_packets += rx_packets;
	ss->stats.rx_bytes += rx_bytes;
	ss->stats.rx_bytes += rx_bytes;


	if (netdev->features & NETIF_F_LRO)
	if (lro_enabled)
		lro_flush_all(&rx_done->lro_mgr);
		lro_flush_all(&rx_done->lro_mgr);


	/* restock receive rings if needed */
	/* restock receive rings if needed */