Merge branch 'rmobile-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / myri10ge / myri10ge.c
index 1f4e868..1446de5 100644 (file)
@@ -1312,17 +1312,26 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev,
                                 * page into an skb */
 
 static inline int
-myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
-                int bytes, int len, __wsum csum)
+myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
+                int lro_enabled)
 {
        struct myri10ge_priv *mgp = ss->mgp;
        struct sk_buff *skb;
        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 net_device *dev = mgp->dev;
        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;
        idx = rx->cnt & rx->mask;
        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;
        }
 
-       if (dev->features & NETIF_F_LRO) {
+       if (lro_enabled) {
                rx_frags[0].page_offset += MXGEFW_PAD;
                rx_frags[0].size -= 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_priv *mgp = ss->mgp;
-       struct net_device *netdev = mgp->dev;
+
        unsigned long rx_bytes = 0;
        unsigned long rx_packets = 0;
        unsigned long rx_ok;
@@ -1474,18 +1483,18 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
        u16 length;
        __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) {
                length = ntohs(rx_done->entry[idx].length);
                rx_done->entry[idx].length = 0;
                checksum = csum_unfold(rx_done->entry[idx].checksum);
-               if (length <= mgp->small_bytes)
-                       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_ok = myri10ge_rx_done(ss, length, checksum, lro_enabled);
                rx_packets += rx_ok;
                rx_bytes += rx_ok * (unsigned long)length;
                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_bytes += rx_bytes;
 
-       if (netdev->features & NETIF_F_LRO)
+       if (lro_enabled)
                lro_flush_all(&rx_done->lro_mgr);
 
        /* restock receive rings if needed */
@@ -3693,7 +3702,7 @@ abort:
 
 /*
  * This function determines the number of slices supported.
- * The number slices is the minumum of the number of CPUS,
+ * The number slices is the minimum of the number of CPUS,
  * the number of MSI-X irqs supported, the number of slices
  * supported by the firmware
  */