ixgbe: Pass staterr instead of re-reading status and error bits from descriptor

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>
This commit is contained in:
Alexander Duyck 2011-06-11 01:45:13 +00:00 committed by Jeff Kirsher
parent bd19805803
commit ff886dfce2
3 changed files with 37 additions and 42 deletions

View File

@ -601,7 +601,8 @@ extern int ixgbe_fso(struct ixgbe_ring *tx_ring, struct sk_buff *skb,
extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter); extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter);
extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
union ixgbe_adv_rx_desc *rx_desc, union ixgbe_adv_rx_desc *rx_desc,
struct sk_buff *skb); struct sk_buff *skb,
u32 staterr);
extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
struct scatterlist *sgl, unsigned int sgc); struct scatterlist *sgl, unsigned int sgc);
extern int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, extern int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid,

View File

@ -36,25 +36,6 @@
#include <scsi/libfc.h> #include <scsi/libfc.h>
#include <scsi/libfcoe.h> #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 * ixgbe_fcoe_clear_ddp - clear the given ddp context
* @ddp - ptr to the ixgbe_fcoe_ddp * @ddp - ptr to the ixgbe_fcoe_ddp
@ -136,7 +117,6 @@ out_ddp_put:
return len; return len;
} }
/** /**
* ixgbe_fcoe_ddp_setup - called to set up ddp context * ixgbe_fcoe_ddp_setup - called to set up ddp context
* @netdev: the corresponding net_device * @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, int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
union ixgbe_adv_rx_desc *rx_desc, union ixgbe_adv_rx_desc *rx_desc,
struct sk_buff *skb) struct sk_buff *skb,
u32 staterr)
{ {
u16 xid; u16 xid;
u32 fctl; u32 fctl;
u32 sterr, fceofe, fcerr, fcstat; u32 fceofe, fcerr, fcstat;
int rc = -EINVAL; int rc = -EINVAL;
struct ixgbe_fcoe *fcoe; struct ixgbe_fcoe *fcoe;
struct ixgbe_fcoe_ddp *ddp; struct ixgbe_fcoe_ddp *ddp;
struct fc_frame_header *fh; struct fc_frame_header *fh;
struct fcoe_crc_eof *crc; struct fcoe_crc_eof *crc;
if (!ixgbe_rx_is_fcoe(rx_desc)) fcerr = (staterr & IXGBE_RXDADV_ERR_FCERR);
goto ddp_out; fceofe = (staterr & IXGBE_RXDADV_ERR_FCEOFE);
sterr = le32_to_cpu(rx_desc->wb.upper.status_error);
fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR);
fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE);
if (fcerr == IXGBE_FCERR_BADCRC) if (fcerr == IXGBE_FCERR_BADCRC)
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
else else
@ -425,7 +402,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
if (fcerr | fceofe) if (fcerr | fceofe)
goto ddp_out; goto ddp_out;
fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); fcstat = (staterr & IXGBE_RXDADV_STAT_FCSTAT);
if (fcstat) { if (fcstat) {
/* update length of DDPed data */ /* update length of DDPed data */
ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);

View File

@ -1038,6 +1038,24 @@ static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc,
skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
} }
/**
* 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 * ixgbe_receive_skb - Send a completed packet up the stack
* @adapter: board private structure * @adapter: board private structure
@ -1070,14 +1088,14 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
* @adapter: address of board private structure * @adapter: address of board private structure
* @status_err: hardware indication of status of receive * @status_err: hardware indication of status of receive
* @skb: skb currently being received and modified * @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, static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
union ixgbe_adv_rx_desc *rx_desc, 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->ip_summed = CHECKSUM_NONE;
skb_checksum_none_assert(skb);
/* Rx csum disabled */ /* Rx csum disabled */
if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) 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 */ /* ERR_MASK will only have valid bits if EOP set */
if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) { if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) {
/* trim packet back to size 0 and recycle it */ dev_kfree_skb_any(skb);
__pskb_trim(skb, 0);
rx_buffer_info->skb = skb;
goto next_desc; 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) if (adapter->netdev->features & NETIF_F_RXHASH)
ixgbe_rx_hash(rx_desc, skb); 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); skb->protocol = eth_type_trans(skb, rx_ring->netdev);
#ifdef IXGBE_FCOE #ifdef IXGBE_FCOE
/* if ddp, not passing to ULD unless for FCP_RSP or error */ /* if ddp, not passing to ULD unless for FCP_RSP or error */
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { if (ixgbe_rx_is_fcoe(adapter, rx_desc)) {
ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb,
staterr);
if (!ddp_bytes) if (!ddp_bytes)
goto next_desc; goto next_desc;
} }