|
@@ -43,6 +43,7 @@
|
|
#include <linux/ethtool.h>
|
|
#include <linux/ethtool.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/prefetch.h>
|
|
#include <linux/prefetch.h>
|
|
|
|
+#include <linux/sctp.h>
|
|
|
|
|
|
#include "igbvf.h"
|
|
#include "igbvf.h"
|
|
|
|
|
|
@@ -1908,6 +1909,31 @@ static void igbvf_watchdog_task(struct work_struct *work)
|
|
#define IGBVF_TX_FLAGS_VLAN_MASK 0xffff0000
|
|
#define IGBVF_TX_FLAGS_VLAN_MASK 0xffff0000
|
|
#define IGBVF_TX_FLAGS_VLAN_SHIFT 16
|
|
#define IGBVF_TX_FLAGS_VLAN_SHIFT 16
|
|
|
|
|
|
|
|
+static void igbvf_tx_ctxtdesc(struct igbvf_ring *tx_ring, u32 vlan_macip_lens,
|
|
|
|
+ u32 type_tucmd, u32 mss_l4len_idx)
|
|
|
|
+{
|
|
|
|
+ struct e1000_adv_tx_context_desc *context_desc;
|
|
|
|
+ struct igbvf_buffer *buffer_info;
|
|
|
|
+ u16 i = tx_ring->next_to_use;
|
|
|
|
+
|
|
|
|
+ context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
|
|
|
|
+ buffer_info = &tx_ring->buffer_info[i];
|
|
|
|
+
|
|
|
|
+ i++;
|
|
|
|
+ tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
|
|
|
|
+
|
|
|
|
+ /* set bits to identify this as an advanced context descriptor */
|
|
|
|
+ type_tucmd |= E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
|
|
|
|
+
|
|
|
|
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
|
|
|
|
+ context_desc->seqnum_seed = 0;
|
|
|
|
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd);
|
|
|
|
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
|
|
|
|
+
|
|
|
|
+ buffer_info->time_stamp = jiffies;
|
|
|
|
+ buffer_info->dma = 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int igbvf_tso(struct igbvf_adapter *adapter,
|
|
static int igbvf_tso(struct igbvf_adapter *adapter,
|
|
struct igbvf_ring *tx_ring,
|
|
struct igbvf_ring *tx_ring,
|
|
struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
|
|
struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
|
|
@@ -1987,65 +2013,56 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
-static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
|
|
|
|
- struct igbvf_ring *tx_ring,
|
|
|
|
- struct sk_buff *skb, u32 tx_flags,
|
|
|
|
- __be16 protocol)
|
|
|
|
|
|
+static inline bool igbvf_ipv6_csum_is_sctp(struct sk_buff *skb)
|
|
{
|
|
{
|
|
- struct e1000_adv_tx_context_desc *context_desc;
|
|
|
|
- unsigned int i;
|
|
|
|
- struct igbvf_buffer *buffer_info;
|
|
|
|
- u32 info = 0, tu_cmd = 0;
|
|
|
|
-
|
|
|
|
- if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
|
|
|
|
- (tx_flags & IGBVF_TX_FLAGS_VLAN)) {
|
|
|
|
- i = tx_ring->next_to_use;
|
|
|
|
- buffer_info = &tx_ring->buffer_info[i];
|
|
|
|
- context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
|
|
|
|
|
|
+ unsigned int offset = 0;
|
|
|
|
|
|
- if (tx_flags & IGBVF_TX_FLAGS_VLAN)
|
|
|
|
- info |= (tx_flags & IGBVF_TX_FLAGS_VLAN_MASK);
|
|
|
|
|
|
+ ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
|
|
|
|
|
|
- info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
|
|
|
|
- if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
|
|
- info |= (skb_transport_header(skb) -
|
|
|
|
- skb_network_header(skb));
|
|
|
|
|
|
+ return offset == skb_checksum_start_offset(skb);
|
|
|
|
+}
|
|
|
|
|
|
- context_desc->vlan_macip_lens = cpu_to_le32(info);
|
|
|
|
|
|
+static bool igbvf_tx_csum(struct igbvf_ring *tx_ring, struct sk_buff *skb,
|
|
|
|
+ u32 tx_flags, __be16 protocol)
|
|
|
|
+{
|
|
|
|
+ u32 vlan_macip_lens = 0;
|
|
|
|
+ u32 type_tucmd = 0;
|
|
|
|
|
|
- tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
|
|
|
|
|
|
+ if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
|
|
|
+csum_failed:
|
|
|
|
+ if (!(tx_flags & IGBVF_TX_FLAGS_VLAN))
|
|
|
|
+ return false;
|
|
|
|
+ goto no_csum;
|
|
|
|
+ }
|
|
|
|
|
|
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
|
|
- switch (protocol) {
|
|
|
|
- case htons(ETH_P_IP):
|
|
|
|
- tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
|
|
|
|
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
|
|
|
|
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
|
|
|
|
- break;
|
|
|
|
- case htons(ETH_P_IPV6):
|
|
|
|
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
|
|
|
|
- tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ switch (skb->csum_offset) {
|
|
|
|
+ case offsetof(struct tcphdr, check):
|
|
|
|
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
|
|
|
|
+ /* fall through */
|
|
|
|
+ case offsetof(struct udphdr, check):
|
|
|
|
+ break;
|
|
|
|
+ case offsetof(struct sctphdr, checksum):
|
|
|
|
+ /* validate that this is actually an SCTP request */
|
|
|
|
+ if (((protocol == htons(ETH_P_IP)) &&
|
|
|
|
+ (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
|
|
|
|
+ ((protocol == htons(ETH_P_IPV6)) &&
|
|
|
|
+ igbvf_ipv6_csum_is_sctp(skb))) {
|
|
|
|
+ type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
|
|
|
|
- context_desc->seqnum_seed = 0;
|
|
|
|
- context_desc->mss_l4len_idx = 0;
|
|
|
|
-
|
|
|
|
- buffer_info->time_stamp = jiffies;
|
|
|
|
- buffer_info->dma = 0;
|
|
|
|
- i++;
|
|
|
|
- if (i == tx_ring->count)
|
|
|
|
- i = 0;
|
|
|
|
- tx_ring->next_to_use = i;
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
|
|
+ default:
|
|
|
|
+ skb_checksum_help(skb);
|
|
|
|
+ goto csum_failed;
|
|
}
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
|
|
|
+ vlan_macip_lens = skb_checksum_start_offset(skb) -
|
|
|
|
+ skb_network_offset(skb);
|
|
|
|
+no_csum:
|
|
|
|
+ vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
|
|
|
|
+ vlan_macip_lens |= tx_flags & IGBVF_TX_FLAGS_VLAN_MASK;
|
|
|
|
+
|
|
|
|
+ igbvf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
|
|
static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
|
|
@@ -2264,7 +2281,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
|
|
|
|
|
|
if (tso)
|
|
if (tso)
|
|
tx_flags |= IGBVF_TX_FLAGS_TSO;
|
|
tx_flags |= IGBVF_TX_FLAGS_TSO;
|
|
- else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) &&
|
|
|
|
|
|
+ else if (igbvf_tx_csum(tx_ring, skb, tx_flags, protocol) &&
|
|
(skb->ip_summed == CHECKSUM_PARTIAL))
|
|
(skb->ip_summed == CHECKSUM_PARTIAL))
|
|
tx_flags |= IGBVF_TX_FLAGS_CSUM;
|
|
tx_flags |= IGBVF_TX_FLAGS_CSUM;
|
|
|
|
|
|
@@ -2717,11 +2734,11 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
adapter->bd_number = cards_found++;
|
|
adapter->bd_number = cards_found++;
|
|
|
|
|
|
netdev->hw_features = NETIF_F_SG |
|
|
netdev->hw_features = NETIF_F_SG |
|
|
- NETIF_F_IP_CSUM |
|
|
|
|
- NETIF_F_IPV6_CSUM |
|
|
|
|
- NETIF_F_TSO |
|
|
|
|
- NETIF_F_TSO6 |
|
|
|
|
- NETIF_F_RXCSUM;
|
|
|
|
|
|
+ NETIF_F_TSO |
|
|
|
|
+ NETIF_F_TSO6 |
|
|
|
|
+ NETIF_F_RXCSUM |
|
|
|
|
+ NETIF_F_HW_CSUM |
|
|
|
|
+ NETIF_F_SCTP_CRC;
|
|
|
|
|
|
netdev->features = netdev->hw_features |
|
|
netdev->features = netdev->hw_features |
|
|
NETIF_F_HW_VLAN_CTAG_TX |
|
|
NETIF_F_HW_VLAN_CTAG_TX |
|
|
@@ -2731,11 +2748,14 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
if (pci_using_dac)
|
|
if (pci_using_dac)
|
|
netdev->features |= NETIF_F_HIGHDMA;
|
|
netdev->features |= NETIF_F_HIGHDMA;
|
|
|
|
|
|
- netdev->vlan_features |= NETIF_F_TSO;
|
|
|
|
- netdev->vlan_features |= NETIF_F_TSO6;
|
|
|
|
- netdev->vlan_features |= NETIF_F_IP_CSUM;
|
|
|
|
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
|
|
|
|
- netdev->vlan_features |= NETIF_F_SG;
|
|
|
|
|
|
+ netdev->vlan_features |= NETIF_F_SG |
|
|
|
|
+ NETIF_F_TSO |
|
|
|
|
+ NETIF_F_TSO6 |
|
|
|
|
+ NETIF_F_HW_CSUM |
|
|
|
|
+ NETIF_F_SCTP_CRC;
|
|
|
|
+
|
|
|
|
+ netdev->mpls_features |= NETIF_F_HW_CSUM;
|
|
|
|
+ netdev->hw_enc_features |= NETIF_F_HW_CSUM;
|
|
|
|
|
|
/*reset the controller to put the device in a known good state */
|
|
/*reset the controller to put the device in a known good state */
|
|
err = hw->mac.ops.reset_hw(hw);
|
|
err = hw->mac.ops.reset_hw(hw);
|