Commit 27fa589d authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-06-09

This series contains more updates to i40e and i40evf.

Shannon adds checks for error status bits on the admin event queue and
provides notification if seen.  Cleans up unused variable and memory
allocation which was used earlier in driver development and is no longer
needed.  Also fixes the driver to not complain about removing
non-existent MAC addresses.  Bumps the driver versions for both i40e
and i40evf.

Catherine fixes a function header comment to make sure the comment correctly
reflects the function name.

Mitch adds code to allow for additional VSIs since the number of VSIs that
the firmware reports to us is a guaranteed minimum, not an absolute
maximum.  The hardware actually supports for more than the reported value,
which we often need.  Implements anti-spoofing for VFs for both MAC
addresses and VLANs, as well as enable this feature by default for all VFs.

Anjali changes the interrupt distribution policy to change the way
resources for special features are handled.  Fixes the driver to not fall
back to one queue if the only feature enabled is ATR, since FD_SB
and FD_ATR need to be checked independently in order to decide if we
will support multiple queue or not.  Allows the RSS table entry range
and GPS to be any number, not necessarily a power of 2 because hardware
does not restrict us to use a power of 2 GPS in the case of RSS as long as
we are not sharing the RSS table with another VSI (VMDq).

Frank modifies the driver to keep SR-IOV enabled in the case that RSS,
VMFq, FD_SB and DCB are disabled so that SR-IOV does not get turned off
unnecessarily.

Jesse fixes a bug in receive checksum where the driver was not marking
packets with bad checksums correctly, especially IPv6 packets with a bad
checksum.  To do this correctly, we need a define that may be set by
hardware in rare cases.

Greg fixes the driver to delete all the old and stale MAC filters for the
VF VSI when the host administrator changes the VF MAC address from under
its feet.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b78370c0 e8607ef5
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#define I40E_MIN_NUM_DESCRIPTORS 64 #define I40E_MIN_NUM_DESCRIPTORS 64
#define I40E_MIN_MSIX 2 #define I40E_MIN_MSIX 2
#define I40E_DEFAULT_NUM_VMDQ_VSI 8 /* max 256 VSIs */ #define I40E_DEFAULT_NUM_VMDQ_VSI 8 /* max 256 VSIs */
#define I40E_MIN_VSI_ALLOC 51 /* LAN, ATR, FCOE, 32 VF, 16 VMDQ */
#define I40E_DEFAULT_QUEUES_PER_VMDQ 2 /* max 16 qps */ #define I40E_DEFAULT_QUEUES_PER_VMDQ 2 /* max 16 qps */
#define I40E_DEFAULT_QUEUES_PER_VF 4 #define I40E_DEFAULT_QUEUES_PER_VF 4
#define I40E_DEFAULT_QUEUES_PER_TC 1 /* should be a power of 2 */ #define I40E_DEFAULT_QUEUES_PER_TC 1 /* should be a power of 2 */
...@@ -215,6 +216,7 @@ struct i40e_pf { ...@@ -215,6 +216,7 @@ struct i40e_pf {
u16 rss_size; /* num queues in the RSS array */ u16 rss_size; /* num queues in the RSS array */
u16 rss_size_max; /* HW defined max RSS queues */ u16 rss_size_max; /* HW defined max RSS queues */
u16 fdir_pf_filter_count; /* num of guaranteed filters for this PF */ u16 fdir_pf_filter_count; /* num of guaranteed filters for this PF */
u16 num_alloc_vsi; /* num VSIs this driver supports */
u8 atr_sample_rate; u8 atr_sample_rate;
bool wol_en; bool wol_en;
...@@ -295,7 +297,6 @@ struct i40e_pf { ...@@ -295,7 +297,6 @@ struct i40e_pf {
u16 pf_seid; u16 pf_seid;
u16 main_vsi_seid; u16 main_vsi_seid;
u16 mac_seid; u16 mac_seid;
struct i40e_aqc_get_switch_config_data *sw_config;
struct kobject *switch_kobj; struct kobject *switch_kobj;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *i40e_dbg_pf; struct dentry *i40e_dbg_pf;
......
...@@ -232,7 +232,7 @@ static void i40e_dcbnl_del_app(struct i40e_pf *pf, ...@@ -232,7 +232,7 @@ static void i40e_dcbnl_del_app(struct i40e_pf *pf,
struct i40e_ieee_app_priority_table *app) struct i40e_ieee_app_priority_table *app)
{ {
int v, err; int v, err;
for (v = 0; v < pf->hw.func_caps.num_vsis; v++) { for (v = 0; v < pf->num_alloc_vsi; v++) {
if (pf->vsi[v] && pf->vsi[v]->netdev) { if (pf->vsi[v] && pf->vsi[v]->netdev) {
err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app); err = i40e_dcbnl_vsi_del_app(pf->vsi[v], app);
if (err) if (err)
......
...@@ -45,7 +45,7 @@ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid) ...@@ -45,7 +45,7 @@ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid)
if (seid < 0) if (seid < 0)
dev_info(&pf->pdev->dev, "%d: bad seid\n", seid); dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
else else
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i] && (pf->vsi[i]->seid == seid)) if (pf->vsi[i] && (pf->vsi[i]->seid == seid))
return pf->vsi[i]; return pf->vsi[i];
...@@ -843,7 +843,7 @@ static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf) ...@@ -843,7 +843,7 @@ static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf)
{ {
int i; int i;
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i]) if (pf->vsi[i])
dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n", dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n",
i, pf->vsi[i]->seid); i, pf->vsi[i]->seid);
...@@ -1526,7 +1526,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, ...@@ -1526,7 +1526,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
cnt = sscanf(&cmd_buf[15], "%i", &vsi_seid); cnt = sscanf(&cmd_buf[15], "%i", &vsi_seid);
if (cnt == 0) { if (cnt == 0) {
int i; int i;
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) for (i = 0; i < pf->num_alloc_vsi; i++)
i40e_vsi_reset_stats(pf->vsi[i]); i40e_vsi_reset_stats(pf->vsi[i]);
dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n"); dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n");
} else if (cnt == 1) { } else if (cnt == 1) {
......
...@@ -119,6 +119,7 @@ static struct i40e_stats i40e_gstrings_stats[] = { ...@@ -119,6 +119,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
I40E_PF_STAT("tx_timeout", tx_timeout_count), I40E_PF_STAT("tx_timeout", tx_timeout_count),
I40E_PF_STAT("rx_csum_bad", hw_csum_rx_error),
I40E_PF_STAT("rx_length_errors", stats.rx_length_errors), I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
I40E_PF_STAT("link_xon_rx", stats.link_xon_rx), I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx), I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
......
This diff is collapsed.
...@@ -62,7 +62,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, ...@@ -62,7 +62,7 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
/* find existing FDIR VSI */ /* find existing FDIR VSI */
vsi = NULL; vsi = NULL;
for (i = 0; i < pf->hw.func_caps.num_vsis; i++) for (i = 0; i < pf->num_alloc_vsi; i++)
if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR)
vsi = pf->vsi[i]; vsi = pf->vsi[i];
if (!vsi) if (!vsi)
...@@ -1193,10 +1193,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -1193,10 +1193,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
u32 rx_error, u32 rx_error,
u16 rx_ptype) u16 rx_ptype)
{ {
struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
bool ipv4 = false, ipv6 = false;
bool ipv4_tunnel, ipv6_tunnel; bool ipv4_tunnel, ipv6_tunnel;
__wsum rx_udp_csum; __wsum rx_udp_csum;
__sum16 csum;
struct iphdr *iph; struct iphdr *iph;
__sum16 csum;
ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
(rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
...@@ -1207,29 +1209,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -1207,29 +1209,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
/* Rx csum enabled and ip headers found? */ /* Rx csum enabled and ip headers found? */
if (!(vsi->netdev->features & NETIF_F_RXCSUM && if (!(vsi->netdev->features & NETIF_F_RXCSUM))
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return;
/* did the hardware decode the packet and checksum? */
if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return;
/* both known and outer_ip must be set for the below code to work */
if (!(decoded.known && decoded.outer_ip))
return; return;
if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
ipv4 = true;
else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
ipv6 = true;
if (ipv4 &&
(rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
(1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))))
goto checksum_fail;
/* likely incorrect csum if alternate IP extension headers found */ /* likely incorrect csum if alternate IP extension headers found */
if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) if (ipv6 &&
decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP &&
rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) &&
rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
/* don't increment checksum err here, non-fatal err */
return; return;
/* IP or L4 or outmost IP checksum error */ /* there was some L4 error, count error and punt packet to the stack */
if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))
(1 << I40E_RX_DESC_ERROR_L4E_SHIFT) | goto checksum_fail;
(1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) {
vsi->back->hw_csum_rx_error++; /* handle packets that were not able to be checksummed due
* to arrival speed, in this case the stack can compute
* the csum.
*/
if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT))
return; return;
}
/* If VXLAN traffic has an outer UDPv4 checksum we need to check
* it in the driver, hardware does not do it for us.
* Since L3L4P bit was set we assume a valid IHL value (>=5)
* so the total length of IPv4 header is IHL*4 bytes
* The UDP_0 bit *may* bet set if the *inner* header is UDP
*/
if (ipv4_tunnel && if (ipv4_tunnel &&
(decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) &&
!(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) {
/* If VXLAN traffic has an outer UDPv4 checksum we need to check
* it in the driver, hardware does not do it for us.
* Since L3L4P bit was set we assume a valid IHL value (>=5)
* so the total length of IPv4 header is IHL*4 bytes
*/
skb->transport_header = skb->mac_header + skb->transport_header = skb->mac_header +
sizeof(struct ethhdr) + sizeof(struct ethhdr) +
(ip_hdr(skb)->ihl * 4); (ip_hdr(skb)->ihl * 4);
...@@ -1246,13 +1276,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -1246,13 +1276,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
(skb->len - skb_transport_offset(skb)), (skb->len - skb_transport_offset(skb)),
IPPROTO_UDP, rx_udp_csum); IPPROTO_UDP, rx_udp_csum);
if (udp_hdr(skb)->check != csum) { if (udp_hdr(skb)->check != csum)
vsi->back->hw_csum_rx_error++; goto checksum_fail;
return;
}
} }
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
return;
checksum_fail:
vsi->back->hw_csum_rx_error++;
} }
/** /**
...@@ -1429,6 +1462,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -1429,6 +1462,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
/* ERR_MASK will only have valid bits if EOP set */ /* ERR_MASK will only have valid bits if EOP set */
if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
/* TODO: shouldn't we increment a counter indicating the
* drop?
*/
goto next_desc; goto next_desc;
} }
......
...@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits { ...@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits {
I40E_RX_DESC_ERROR_IPE_SHIFT = 3, I40E_RX_DESC_ERROR_IPE_SHIFT = 3,
I40E_RX_DESC_ERROR_L4E_SHIFT = 4, I40E_RX_DESC_ERROR_L4E_SHIFT = 4,
I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, I40E_RX_DESC_ERROR_EIPE_SHIFT = 5,
I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6 I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6,
I40E_RX_DESC_ERROR_PPRS_SHIFT = 7
}; };
enum i40e_rx_desc_error_l3l4e_fcoe_masks { enum i40e_rx_desc_error_l3l4e_fcoe_masks {
......
...@@ -899,6 +899,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) ...@@ -899,6 +899,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
ret = -ENOMEM; ret = -ENOMEM;
goto err_alloc; goto err_alloc;
} }
pf->vf = vfs;
/* apply default profile */ /* apply default profile */
for (i = 0; i < num_alloc_vfs; i++) { for (i = 0; i < num_alloc_vfs; i++) {
...@@ -908,13 +909,13 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) ...@@ -908,13 +909,13 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
/* assign default capabilities */ /* assign default capabilities */
set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps); set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
vfs[i].spoofchk = true;
/* vf resources get allocated during reset */ /* vf resources get allocated during reset */
i40e_reset_vf(&vfs[i], false); i40e_reset_vf(&vfs[i], false);
/* enable vf vplan_qtable mappings */ /* enable vf vplan_qtable mappings */
i40e_enable_vf_mappings(&vfs[i]); i40e_enable_vf_mappings(&vfs[i]);
} }
pf->vf = vfs;
pf->num_alloc_vfs = num_alloc_vfs; pf->num_alloc_vfs = num_alloc_vfs;
i40e_enable_pf_switch_lb(pf); i40e_enable_pf_switch_lb(pf);
...@@ -2062,14 +2063,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) ...@@ -2062,14 +2063,11 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id, i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id,
true, false); true, false);
/* add the new mac address */ /* Delete all the filters for this VSI - we're going to kill it
f = i40e_add_filter(vsi, mac, vf->port_vlan_id, true, false); * anyway.
if (!f) { */
dev_err(&pf->pdev->dev, list_for_each_entry(f, &vsi->mac_filter_list, list)
"Unable to add VF ucast filter\n"); i40e_del_filter(vsi, f->macaddr, f->vlan, true, false);
ret = -ENOMEM;
goto error_param;
}
dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id); dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
/* program mac filter */ /* program mac filter */
...@@ -2328,7 +2326,7 @@ int i40e_ndo_get_vf_config(struct net_device *netdev, ...@@ -2328,7 +2326,7 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
else else
ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
ivi->spoofchk = vf->spoofchk;
ret = 0; ret = 0;
error_param: error_param:
...@@ -2395,3 +2393,50 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link) ...@@ -2395,3 +2393,50 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
error_out: error_out:
return ret; return ret;
} }
/**
* i40e_ndo_set_vf_spoofchk
* @netdev: network interface device structure
* @vf_id: vf identifier
* @enable: flag to enable or disable feature
*
* Enable or disable VF spoof checking
**/
int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
struct i40e_vsi_context ctxt;
struct i40e_hw *hw = &pf->hw;
struct i40e_vf *vf;
int ret = 0;
/* validate the request */
if (vf_id >= pf->num_alloc_vfs) {
dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
ret = -EINVAL;
goto out;
}
vf = &(pf->vf[vf_id]);
if (enable == vf->spoofchk)
goto out;
vf->spoofchk = enable;
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->vsi[vf->lan_vsi_index]->seid;
ctxt.pf_num = pf->hw.pf_id;
ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
if (enable)
ctxt.info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
if (ret) {
dev_err(&pf->pdev->dev, "Error %d updating VSI parameters\n",
ret);
ret = -EIO;
}
out:
return ret;
}
...@@ -101,6 +101,7 @@ struct i40e_vf { ...@@ -101,6 +101,7 @@ struct i40e_vf {
unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ unsigned int tx_rate; /* Tx bandwidth limit in Mbps */
bool link_forced; bool link_forced;
bool link_up; /* only valid if vf link is forced */ bool link_up; /* only valid if vf link is forced */
bool spoofchk;
}; };
void i40e_free_vfs(struct i40e_pf *pf); void i40e_free_vfs(struct i40e_pf *pf);
...@@ -121,6 +122,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate, ...@@ -121,6 +122,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
int i40e_ndo_get_vf_config(struct net_device *netdev, int i40e_ndo_get_vf_config(struct net_device *netdev,
int vf_id, struct ifla_vf_info *ivi); int vf_id, struct ifla_vf_info *ivi);
int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link); int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable);
void i40e_vc_notify_link_state(struct i40e_pf *pf); void i40e_vc_notify_link_state(struct i40e_pf *pf);
void i40e_vc_notify_reset(struct i40e_pf *pf); void i40e_vc_notify_reset(struct i40e_pf *pf);
......
...@@ -728,10 +728,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -728,10 +728,12 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
u32 rx_error, u32 rx_error,
u16 rx_ptype) u16 rx_ptype)
{ {
struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
bool ipv4 = false, ipv6 = false;
bool ipv4_tunnel, ipv6_tunnel; bool ipv4_tunnel, ipv6_tunnel;
__wsum rx_udp_csum; __wsum rx_udp_csum;
__sum16 csum;
struct iphdr *iph; struct iphdr *iph;
__sum16 csum;
ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) && ipv4_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
(rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4); (rx_ptype < I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
...@@ -742,29 +744,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -742,29 +744,57 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
/* Rx csum enabled and ip headers found? */ /* Rx csum enabled and ip headers found? */
if (!(vsi->netdev->features & NETIF_F_RXCSUM && if (!(vsi->netdev->features & NETIF_F_RXCSUM))
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return;
/* did the hardware decode the packet and checksum? */
if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return;
/* both known and outer_ip must be set for the below code to work */
if (!(decoded.known && decoded.outer_ip))
return; return;
if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
ipv4 = true;
else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
ipv6 = true;
if (ipv4 &&
(rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
(1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))))
goto checksum_fail;
/* likely incorrect csum if alternate IP extension headers found */ /* likely incorrect csum if alternate IP extension headers found */
if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) if (ipv6 &&
decoded.inner_prot == I40E_RX_PTYPE_INNER_PROT_TCP &&
rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) &&
rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
/* don't increment checksum err here, non-fatal err */
return; return;
/* IP or L4 or outmost IP checksum error */ /* there was some L4 error, count error and punt packet to the stack */
if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))
(1 << I40E_RX_DESC_ERROR_L4E_SHIFT) | goto checksum_fail;
(1 << I40E_RX_DESC_ERROR_EIPE_SHIFT))) {
vsi->back->hw_csum_rx_error++; /* handle packets that were not able to be checksummed due
* to arrival speed, in this case the stack can compute
* the csum.
*/
if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT))
return; return;
}
/* If VXLAN traffic has an outer UDPv4 checksum we need to check
* it in the driver, hardware does not do it for us.
* Since L3L4P bit was set we assume a valid IHL value (>=5)
* so the total length of IPv4 header is IHL*4 bytes
* The UDP_0 bit *may* bet set if the *inner* header is UDP
*/
if (ipv4_tunnel && if (ipv4_tunnel &&
(decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) &&
!(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) { !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) {
/* If VXLAN traffic has an outer UDPv4 checksum we need to check
* it in the driver, hardware does not do it for us.
* Since L3L4P bit was set we assume a valid IHL value (>=5)
* so the total length of IPv4 header is IHL*4 bytes
*/
skb->transport_header = skb->mac_header + skb->transport_header = skb->mac_header +
sizeof(struct ethhdr) + sizeof(struct ethhdr) +
(ip_hdr(skb)->ihl * 4); (ip_hdr(skb)->ihl * 4);
...@@ -781,13 +811,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -781,13 +811,16 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
(skb->len - skb_transport_offset(skb)), (skb->len - skb_transport_offset(skb)),
IPPROTO_UDP, rx_udp_csum); IPPROTO_UDP, rx_udp_csum);
if (udp_hdr(skb)->check != csum) { if (udp_hdr(skb)->check != csum)
vsi->back->hw_csum_rx_error++; goto checksum_fail;
return;
}
} }
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
return;
checksum_fail:
vsi->back->hw_csum_rx_error++;
} }
/** /**
...@@ -956,6 +989,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -956,6 +989,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
/* ERR_MASK will only have valid bits if EOP set */ /* ERR_MASK will only have valid bits if EOP set */
if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
/* TODO: shouldn't we increment a counter indicating the
* drop?
*/
goto next_desc; goto next_desc;
} }
......
...@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits { ...@@ -541,7 +541,8 @@ enum i40e_rx_desc_error_bits {
I40E_RX_DESC_ERROR_IPE_SHIFT = 3, I40E_RX_DESC_ERROR_IPE_SHIFT = 3,
I40E_RX_DESC_ERROR_L4E_SHIFT = 4, I40E_RX_DESC_ERROR_L4E_SHIFT = 4,
I40E_RX_DESC_ERROR_EIPE_SHIFT = 5, I40E_RX_DESC_ERROR_EIPE_SHIFT = 5,
I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6 I40E_RX_DESC_ERROR_OVERSIZE_SHIFT = 6,
I40E_RX_DESC_ERROR_PPRS_SHIFT = 7
}; };
enum i40e_rx_desc_error_l3l4e_fcoe_masks { enum i40e_rx_desc_error_l3l4e_fcoe_masks {
......
...@@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf"; ...@@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf";
static const char i40evf_driver_string[] = static const char i40evf_driver_string[] =
"Intel(R) XL710 X710 Virtual Function Network Driver"; "Intel(R) XL710 X710 Virtual Function Network Driver";
#define DRV_VERSION "0.9.29" #define DRV_VERSION "0.9.31"
const char i40evf_driver_version[] = DRV_VERSION; const char i40evf_driver_version[] = DRV_VERSION;
static const char i40evf_copyright[] = static const char i40evf_copyright[] =
"Copyright (c) 2013 - 2014 Intel Corporation."; "Copyright (c) 2013 - 2014 Intel Corporation.";
...@@ -1395,7 +1395,7 @@ static void i40evf_watchdog_task(struct work_struct *work) ...@@ -1395,7 +1395,7 @@ static void i40evf_watchdog_task(struct work_struct *work)
} }
/** /**
* i40evf_configure_rss - increment to next available tx queue * next_queue - increment to next available tx queue
* @adapter: board private structure * @adapter: board private structure
* @j: queue counter * @j: queue counter
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment