ixgbe: Pass staterr instead of re-reading status and error bits from descriptor
Alexander Duyck [Sat, 11 Jun 2011 01:45:13 +0000 (01:45 +0000)]
This change is meant to address possible race conditions from the status
and error bits on the RX descriptors being re-read by multiple functions in
the RX cleanup path.  To resolve this I have added code that will pass the
staterr value to those functions.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>

drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_main.c

index fbae735..0d610c7 100644 (file)
@@ -600,8 +600,9 @@ extern int ixgbe_fso(struct ixgbe_ring *tx_ring, struct sk_buff *skb,
                      u32 tx_flags, u8 *hdr_len);
 extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter);
 extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
-                          union ixgbe_adv_rx_desc *rx_desc,
-                          struct sk_buff *skb);
+                         union ixgbe_adv_rx_desc *rx_desc,
+                         struct sk_buff *skb,
+                         u32 staterr);
 extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
                               struct scatterlist *sgl, unsigned int sgc);
 extern int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid,
index f0c1018..824edae 100644 (file)
 #include <scsi/libfcoe.h>
 
 /**
- * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type
- * @rx_desc: advanced rx descriptor
- *
- * Returns : true if it is FCoE pkt
- */
-static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc)
-{
-       u16 p;
-
-       p = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info);
-       if (p & IXGBE_RXDADV_PKTTYPE_ETQF) {
-               p &= IXGBE_RXDADV_PKTTYPE_ETQF_MASK;
-               p >>= IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT;
-               return p == IXGBE_ETQF_FILTER_FCOE;
-       }
-       return false;
-}
-
-/**
  * ixgbe_fcoe_clear_ddp - clear the given ddp context
  * @ddp - ptr to the ixgbe_fcoe_ddp
  *
@@ -136,7 +117,6 @@ out_ddp_put:
        return len;
 }
 
-
 /**
  * ixgbe_fcoe_ddp_setup - called to set up ddp context
  * @netdev: the corresponding net_device
@@ -380,23 +360,20 @@ int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid,
  */
 int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
                   union ixgbe_adv_rx_desc *rx_desc,
-                  struct sk_buff *skb)
+                  struct sk_buff *skb,
+                  u32 staterr)
 {
        u16 xid;
        u32 fctl;
-       u32 sterr, fceofe, fcerr, fcstat;
+       u32 fceofe, fcerr, fcstat;
        int rc = -EINVAL;
        struct ixgbe_fcoe *fcoe;
        struct ixgbe_fcoe_ddp *ddp;
        struct fc_frame_header *fh;
        struct fcoe_crc_eof *crc;
 
-       if (!ixgbe_rx_is_fcoe(rx_desc))
-               goto ddp_out;
-
-       sterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-       fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR);
-       fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE);
+       fcerr = (staterr & IXGBE_RXDADV_ERR_FCERR);
+       fceofe = (staterr & IXGBE_RXDADV_ERR_FCEOFE);
        if (fcerr == IXGBE_FCERR_BADCRC)
                skb_checksum_none_assert(skb);
        else
@@ -425,7 +402,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
        if (fcerr | fceofe)
                goto ddp_out;
 
-       fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT);
+       fcstat = (staterr & IXGBE_RXDADV_STAT_FCSTAT);
        if (fcstat) {
                /* update length of DDPed data */
                ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
index 298c95b..a222af3 100644 (file)
@@ -1039,6 +1039,24 @@ static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc,
 }
 
 /**
+ * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type
+ * @adapter: address of board private structure
+ * @rx_desc: advanced rx descriptor
+ *
+ * Returns : true if it is FCoE pkt
+ */
+static inline bool ixgbe_rx_is_fcoe(struct ixgbe_adapter *adapter,
+                                   union ixgbe_adv_rx_desc *rx_desc)
+{
+       __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+
+       return (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) &&
+              ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_ETQF_MASK)) ==
+               (cpu_to_le16(IXGBE_ETQF_FILTER_FCOE <<
+                            IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT)));
+}
+
+/**
  * ixgbe_receive_skb - Send a completed packet up the stack
  * @adapter: board private structure
  * @skb: packet to send up
@@ -1070,14 +1088,14 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
  * @adapter: address of board private structure
  * @status_err: hardware indication of status of receive
  * @skb: skb currently being received and modified
+ * @status_err: status error value of last descriptor in packet
  **/
 static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
                                     union ixgbe_adv_rx_desc *rx_desc,
-                                    struct sk_buff *skb)
+                                    struct sk_buff *skb,
+                                    u32 status_err)
 {
-       u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error);
-
-       skb_checksum_none_assert(skb);
+       skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum disabled */
        if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
@@ -1421,14 +1439,12 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                }
 
                /* ERR_MASK will only have valid bits if EOP set */
-               if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) {
-                       /* trim packet back to size 0 and recycle it */
-                       __pskb_trim(skb, 0);
-                       rx_buffer_info->skb = skb;
+               if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) {
+                       dev_kfree_skb_any(skb);
                        goto next_desc;
                }
 
-               ixgbe_rx_checksum(adapter, rx_desc, skb);
+               ixgbe_rx_checksum(adapter, rx_desc, skb, staterr);
                if (adapter->netdev->features & NETIF_F_RXHASH)
                        ixgbe_rx_hash(rx_desc, skb);
 
@@ -1439,8 +1455,9 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                skb->protocol = eth_type_trans(skb, rx_ring->netdev);
 #ifdef IXGBE_FCOE
                /* if ddp, not passing to ULD unless for FCP_RSP or error */
-               if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
-                       ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb);
+               if (ixgbe_rx_is_fcoe(adapter, rx_desc)) {
+                       ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb,
+                                                  staterr);
                        if (!ddp_bytes)
                                goto next_desc;
                }