diff options
| author | Alexander Duyck <alexander.h.duyck@intel.com> | 2011-06-10 21:45:13 -0400 |
|---|---|---|
| committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-07-22 01:56:37 -0400 |
| commit | ff886dfce2bdacbe71583ec973cec117973d8859 (patch) | |
| tree | ea48f94008d8ef554f709962b7f0b7fcee860c3b | |
| parent | bd19805803a954415ec36a559fd3b8a0a3647d7c (diff) | |
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>
| -rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 5 | ||||
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.c | 35 | ||||
| -rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 39 |
3 files changed, 37 insertions, 42 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index fbae7352b036..0d610c73164d 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
| @@ -600,8 +600,9 @@ extern int ixgbe_fso(struct ixgbe_ring *tx_ring, struct sk_buff *skb, | |||
| 600 | u32 tx_flags, u8 *hdr_len); | 600 | u32 tx_flags, u8 *hdr_len); |
| 601 | extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter); | 601 | extern void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter); |
| 602 | extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, | 602 | extern int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, |
| 603 | union ixgbe_adv_rx_desc *rx_desc, | 603 | union ixgbe_adv_rx_desc *rx_desc, |
| 604 | struct sk_buff *skb); | 604 | struct sk_buff *skb, |
| 605 | u32 staterr); | ||
| 605 | extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, | 606 | extern int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, |
| 606 | struct scatterlist *sgl, unsigned int sgc); | 607 | struct scatterlist *sgl, unsigned int sgc); |
| 607 | extern int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, | 608 | extern int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, |
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index f0c1018bbf31..824edae77865 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c | |||
| @@ -37,25 +37,6 @@ | |||
| 37 | #include <scsi/libfcoe.h> | 37 | #include <scsi/libfcoe.h> |
| 38 | 38 | ||
| 39 | /** | 39 | /** |
| 40 | * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type | ||
| 41 | * @rx_desc: advanced rx descriptor | ||
| 42 | * | ||
| 43 | * Returns : true if it is FCoE pkt | ||
| 44 | */ | ||
| 45 | static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc) | ||
| 46 | { | ||
| 47 | u16 p; | ||
| 48 | |||
| 49 | p = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info); | ||
| 50 | if (p & IXGBE_RXDADV_PKTTYPE_ETQF) { | ||
| 51 | p &= IXGBE_RXDADV_PKTTYPE_ETQF_MASK; | ||
| 52 | p >>= IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT; | ||
| 53 | return p == IXGBE_ETQF_FILTER_FCOE; | ||
| 54 | } | ||
| 55 | return false; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * ixgbe_fcoe_clear_ddp - clear the given ddp context | 40 | * ixgbe_fcoe_clear_ddp - clear the given ddp context |
| 60 | * @ddp - ptr to the ixgbe_fcoe_ddp | 41 | * @ddp - ptr to the ixgbe_fcoe_ddp |
| 61 | * | 42 | * |
| @@ -136,7 +117,6 @@ out_ddp_put: | |||
| 136 | return len; | 117 | return len; |
| 137 | } | 118 | } |
| 138 | 119 | ||
| 139 | |||
| 140 | /** | 120 | /** |
| 141 | * ixgbe_fcoe_ddp_setup - called to set up ddp context | 121 | * ixgbe_fcoe_ddp_setup - called to set up ddp context |
| 142 | * @netdev: the corresponding net_device | 122 | * @netdev: the corresponding net_device |
| @@ -380,23 +360,20 @@ int ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, | |||
| 380 | */ | 360 | */ |
| 381 | int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, | 361 | int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, |
| 382 | union ixgbe_adv_rx_desc *rx_desc, | 362 | union ixgbe_adv_rx_desc *rx_desc, |
| 383 | struct sk_buff *skb) | 363 | struct sk_buff *skb, |
| 364 | u32 staterr) | ||
| 384 | { | 365 | { |
| 385 | u16 xid; | 366 | u16 xid; |
| 386 | u32 fctl; | 367 | u32 fctl; |
| 387 | u32 sterr, fceofe, fcerr, fcstat; | 368 | u32 fceofe, fcerr, fcstat; |
| 388 | int rc = -EINVAL; | 369 | int rc = -EINVAL; |
| 389 | struct ixgbe_fcoe *fcoe; | 370 | struct ixgbe_fcoe *fcoe; |
| 390 | struct ixgbe_fcoe_ddp *ddp; | 371 | struct ixgbe_fcoe_ddp *ddp; |
| 391 | struct fc_frame_header *fh; | 372 | struct fc_frame_header *fh; |
| 392 | struct fcoe_crc_eof *crc; | 373 | struct fcoe_crc_eof *crc; |
| 393 | 374 | ||
| 394 | if (!ixgbe_rx_is_fcoe(rx_desc)) | 375 | fcerr = (staterr & IXGBE_RXDADV_ERR_FCERR); |
| 395 | goto ddp_out; | 376 | fceofe = (staterr & IXGBE_RXDADV_ERR_FCEOFE); |
| 396 | |||
| 397 | sterr = le32_to_cpu(rx_desc->wb.upper.status_error); | ||
| 398 | fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR); | ||
| 399 | fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE); | ||
| 400 | if (fcerr == IXGBE_FCERR_BADCRC) | 377 | if (fcerr == IXGBE_FCERR_BADCRC) |
| 401 | skb_checksum_none_assert(skb); | 378 | skb_checksum_none_assert(skb); |
| 402 | else | 379 | else |
| @@ -425,7 +402,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, | |||
| 425 | if (fcerr | fceofe) | 402 | if (fcerr | fceofe) |
| 426 | goto ddp_out; | 403 | goto ddp_out; |
| 427 | 404 | ||
| 428 | fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); | 405 | fcstat = (staterr & IXGBE_RXDADV_STAT_FCSTAT); |
| 429 | if (fcstat) { | 406 | if (fcstat) { |
| 430 | /* update length of DDPed data */ | 407 | /* update length of DDPed data */ |
| 431 | ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); | 408 | ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 298c95b1480f..a222af378a32 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
| @@ -1039,6 +1039,24 @@ static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc, | |||
| 1039 | } | 1039 | } |
| 1040 | 1040 | ||
| 1041 | /** | 1041 | /** |
| 1042 | * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type | ||
| 1043 | * @adapter: address of board private structure | ||
| 1044 | * @rx_desc: advanced rx descriptor | ||
| 1045 | * | ||
| 1046 | * Returns : true if it is FCoE pkt | ||
| 1047 | */ | ||
| 1048 | static inline bool ixgbe_rx_is_fcoe(struct ixgbe_adapter *adapter, | ||
| 1049 | union ixgbe_adv_rx_desc *rx_desc) | ||
| 1050 | { | ||
| 1051 | __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; | ||
| 1052 | |||
| 1053 | return (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && | ||
| 1054 | ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_ETQF_MASK)) == | ||
| 1055 | (cpu_to_le16(IXGBE_ETQF_FILTER_FCOE << | ||
| 1056 | IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT))); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /** | ||
| 1042 | * ixgbe_receive_skb - Send a completed packet up the stack | 1060 | * ixgbe_receive_skb - Send a completed packet up the stack |
| 1043 | * @adapter: board private structure | 1061 | * @adapter: board private structure |
| 1044 | * @skb: packet to send up | 1062 | * @skb: packet to send up |
| @@ -1070,14 +1088,14 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, | |||
| 1070 | * @adapter: address of board private structure | 1088 | * @adapter: address of board private structure |
| 1071 | * @status_err: hardware indication of status of receive | 1089 | * @status_err: hardware indication of status of receive |
| 1072 | * @skb: skb currently being received and modified | 1090 | * @skb: skb currently being received and modified |
| 1091 | * @status_err: status error value of last descriptor in packet | ||
| 1073 | **/ | 1092 | **/ |
| 1074 | static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, | 1093 | static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, |
| 1075 | union ixgbe_adv_rx_desc *rx_desc, | 1094 | union ixgbe_adv_rx_desc *rx_desc, |
| 1076 | struct sk_buff *skb) | 1095 | struct sk_buff *skb, |
| 1096 | u32 status_err) | ||
| 1077 | { | 1097 | { |
| 1078 | u32 status_err = le32_to_cpu(rx_desc->wb.upper.status_error); | 1098 | skb->ip_summed = CHECKSUM_NONE; |
| 1079 | |||
| 1080 | skb_checksum_none_assert(skb); | ||
| 1081 | 1099 | ||
| 1082 | /* Rx csum disabled */ | 1100 | /* Rx csum disabled */ |
| 1083 | if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) | 1101 | if (!(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED)) |
| @@ -1421,14 +1439,12 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, | |||
| 1421 | } | 1439 | } |
| 1422 | 1440 | ||
| 1423 | /* ERR_MASK will only have valid bits if EOP set */ | 1441 | /* ERR_MASK will only have valid bits if EOP set */ |
| 1424 | if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) { | 1442 | if (unlikely(staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK)) { |
| 1425 | /* trim packet back to size 0 and recycle it */ | 1443 | dev_kfree_skb_any(skb); |
| 1426 | __pskb_trim(skb, 0); | ||
| 1427 | rx_buffer_info->skb = skb; | ||
| 1428 | goto next_desc; | 1444 | goto next_desc; |
| 1429 | } | 1445 | } |
| 1430 | 1446 | ||
| 1431 | ixgbe_rx_checksum(adapter, rx_desc, skb); | 1447 | ixgbe_rx_checksum(adapter, rx_desc, skb, staterr); |
| 1432 | if (adapter->netdev->features & NETIF_F_RXHASH) | 1448 | if (adapter->netdev->features & NETIF_F_RXHASH) |
| 1433 | ixgbe_rx_hash(rx_desc, skb); | 1449 | ixgbe_rx_hash(rx_desc, skb); |
| 1434 | 1450 | ||
| @@ -1439,8 +1455,9 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, | |||
| 1439 | skb->protocol = eth_type_trans(skb, rx_ring->netdev); | 1455 | skb->protocol = eth_type_trans(skb, rx_ring->netdev); |
| 1440 | #ifdef IXGBE_FCOE | 1456 | #ifdef IXGBE_FCOE |
| 1441 | /* if ddp, not passing to ULD unless for FCP_RSP or error */ | 1457 | /* if ddp, not passing to ULD unless for FCP_RSP or error */ |
| 1442 | if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) { | 1458 | if (ixgbe_rx_is_fcoe(adapter, rx_desc)) { |
| 1443 | ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb); | 1459 | ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb, |
| 1460 | staterr); | ||
| 1444 | if (!ddp_bytes) | 1461 | if (!ddp_bytes) |
| 1445 | goto next_desc; | 1462 | goto next_desc; |
| 1446 | } | 1463 | } |
