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:
parent
bd19805803
commit
ff886dfce2
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue