From f114dca2533ca770aebebffb5ed56e5e7d1fb3fb Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Oct 2016 16:08:46 -0700 Subject: [PATCH 01/18] i40e: Be much more verbose about what we can and cannot offload This change makes it so that we are much more robust about defining what we can and cannot offload. Previously we were just checking for the L4 tunnel header length, however there are other fields we should be verifying as there are multiple scenarios in which we cannot perform hardware offloads. In addition the device only supports GSO as long as the MSS is 64 or greater. We were not checking this so an MSS less than that was resulting in Tx hangs. Change-ID: I5e2fd5f3075c73601b4b36327b771c64fcb6c31b Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers --- drivers/net/ethernet/intel/i40e/i40e_main.c | 52 +++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5c6a5ceb8a91..2d91274f9f62 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9070,10 +9070,6 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, 0, 0, nlflags, filter_mask, NULL); } -/* Hardware supports L4 tunnel length of 128B (=2^7) which includes - * inner mac plus all inner ethertypes. - */ -#define I40E_MAX_TUNNEL_HDR_LEN 128 /** * i40e_features_check - Validate encapsulated packet conforms to limits * @skb: skb buff @@ -9084,12 +9080,52 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features) { - if (skb->encapsulation && - ((skb_inner_network_header(skb) - skb_transport_header(skb)) > - I40E_MAX_TUNNEL_HDR_LEN)) - return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); + size_t len; + + /* No point in doing any of this if neither checksum nor GSO are + * being requested for this frame. We can rule out both by just + * checking for CHECKSUM_PARTIAL + */ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return features; + + /* We cannot support GSO if the MSS is going to be less than + * 64 bytes. If it is then we need to drop support for GSO. + */ + if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64)) + features &= ~NETIF_F_GSO_MASK; + + /* MACLEN can support at most 63 words */ + len = skb_network_header(skb) - skb->data; + if (len & ~(63 * 2)) + goto out_err; + + /* IPLEN and EIPLEN can support at most 127 dwords */ + len = skb_transport_header(skb) - skb_network_header(skb); + if (len & ~(127 * 4)) + goto out_err; + + if (skb->encapsulation) { + /* L4TUNLEN can support 127 words */ + len = skb_inner_network_header(skb) - skb_transport_header(skb); + if (len & ~(127 * 2)) + goto out_err; + + /* IPLEN can support at most 127 dwords */ + len = skb_inner_transport_header(skb) - + skb_inner_network_header(skb); + if (len & ~(127 * 4)) + goto out_err; + } + + /* No need to validate L4LEN as TCP is the only protocol with a + * a flexible value and we support all possible values supported + * by TCP, which is at most 15 dwords + */ return features; +out_err: + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); } static const struct net_device_ops i40e_netdev_ops = { From 06fc016c43eac5d88a53677ed0db7e28a7a1b4bd Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Oct 2016 16:08:47 -0700 Subject: [PATCH 02/18] i40evf: Be much more verbose about what we can and cannot offload This change makes it so that we are much more robust about defining what we can and cannot offload. Previously we were performing no checks. This should bring us up to parity with the i40e PF driver. In addition the device only supports GSO as long as the MSS is 64 or greater. We were not checking this so an MSS less than that was resulting in Tx hangs. Change-ID: If533553ec92fc6ba694eab6ac81fdaf3004f3592 Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_main.c | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index db36744c6691..7bbb55f303b1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2172,6 +2172,64 @@ static int i40evf_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +/** + * i40evf_features_check - Validate encapsulated packet conforms to limits + * @skb: skb buff + * @netdev: This physical port's netdev + * @features: Offload features that the stack believes apply + **/ +static netdev_features_t i40evf_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + size_t len; + + /* No point in doing any of this if neither checksum nor GSO are + * being requested for this frame. We can rule out both by just + * checking for CHECKSUM_PARTIAL + */ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return features; + + /* We cannot support GSO if the MSS is going to be less than + * 64 bytes. If it is then we need to drop support for GSO. + */ + if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64)) + features &= ~NETIF_F_GSO_MASK; + + /* MACLEN can support at most 63 words */ + len = skb_network_header(skb) - skb->data; + if (len & ~(63 * 2)) + goto out_err; + + /* IPLEN and EIPLEN can support at most 127 dwords */ + len = skb_transport_header(skb) - skb_network_header(skb); + if (len & ~(127 * 4)) + goto out_err; + + if (skb->encapsulation) { + /* L4TUNLEN can support 127 words */ + len = skb_inner_network_header(skb) - skb_transport_header(skb); + if (len & ~(127 * 2)) + goto out_err; + + /* IPLEN can support at most 127 dwords */ + len = skb_inner_transport_header(skb) - + skb_inner_network_header(skb); + if (len & ~(127 * 4)) + goto out_err; + } + + /* No need to validate L4LEN as TCP is the only protocol with a + * a flexible value and we support all possible values supported + * by TCP, which is at most 15 dwords + */ + + return features; +out_err: + return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); +} + #define I40EVF_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_TX |\ NETIF_F_HW_VLAN_CTAG_RX |\ NETIF_F_HW_VLAN_CTAG_FILTER) @@ -2206,6 +2264,7 @@ static const struct net_device_ops i40evf_netdev_ops = { .ndo_tx_timeout = i40evf_tx_timeout, .ndo_vlan_rx_add_vid = i40evf_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = i40evf_vlan_rx_kill_vid, + .ndo_features_check = i40evf_features_check, .ndo_fix_features = i40evf_fix_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = i40evf_netpoll, From 7429c0bd0155c73e0c6ec8f16e440735209d24a5 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 25 Oct 2016 16:08:48 -0700 Subject: [PATCH 03/18] i40e: remove error_param_int label from i40e_vc_config_promiscuous_mode_msg This label is unnecessary, as are jumping to a block that checks aq_ret and then immediately skipping it and returning. So just jump straight to the error_param and remove this unnecessary label. Also use goto error_param even in the last check for style consistency. Change-ID: If487c7d10c4048e37c594e5eca167693aaed45f6 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 53b46553dd8d..46908c0f834a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1536,7 +1536,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, vf->vf_id, i40e_stat_str(&pf->hw, aq_ret), i40e_aq_str(&pf->hw, aq_err)); - goto error_param_int; + goto error_param; } } @@ -1581,15 +1581,16 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, allmulti, NULL, true); aq_err = pf->hw.aq.asq_last_status; - if (aq_ret) + if (aq_ret) { dev_err(&pf->pdev->dev, "VF %d failed to set unicast promiscuous mode %8.8x err %s aq_err %s\n", vf->vf_id, info->flags, i40e_stat_str(&pf->hw, aq_ret), i40e_aq_str(&pf->hw, aq_err)); + goto error_param; + } } -error_param_int: if (!aq_ret) { dev_info(&pf->pdev->dev, "VF %d successfully set unicast promiscuous mode\n", From 6a112785fd18a954033fd030ce156501f15c8fa7 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 25 Oct 2016 16:08:49 -0700 Subject: [PATCH 04/18] i40e: remove second check of VLAN_N_VID in i40e_vlan_rx_add_vid Replace a check of magic number 4095 with VLAN_N_VID. This makes it obvious that a later check against VLAN_N_VID is always true and can be removed. Change-ID: I28998f127a61a529480ce63d8a07e266f6c63b7b Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2d91274f9f62..fe5939a3536f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2549,7 +2549,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, struct i40e_vsi *vsi = np->vsi; int ret = 0; - if (vid > 4095) + if (vid >= VLAN_N_VID) return -EINVAL; /* If the network stack called us with vid = 0 then @@ -2561,7 +2561,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, if (vid) ret = i40e_vsi_add_vlan(vsi, vid); - if (!ret && (vid < VLAN_N_VID)) + if (!ret) set_bit(vid, vsi->active_vlans); return ret; From d182a5ca1f72ab4ef5ad118c64fb80aac659b122 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 25 Oct 2016 16:08:50 -0700 Subject: [PATCH 05/18] i40e: avoid duplicate private flags definitions Separate the global private flags and the regular private flags per interface into two arrays. Future additions of private flags will not need to be duplicated which may lead to buggy code. Also rename "i40e_priv_flags_strings_gl" to "i40e_gl_priv_flags_strings" for clarity, as it reads more naturally. Change-ID: I68caef3c9954eb7da342d7f9d20f2873186f2758 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b9e1162d927f..f99c135718dd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -228,19 +228,8 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = { #define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN) -static const char i40e_priv_flags_strings_gl[][ETH_GSTRING_LEN] = { - "MFP", - "LinkPolling", - "flow-director-atr", - "veb-stats", - "hw-atr-eviction", - "vf-true-promisc-support", -}; - -#define I40E_PRIV_FLAGS_GL_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings_gl) - static const char i40e_priv_flags_strings[][ETH_GSTRING_LEN] = { - "NPAR", + "MFP", "LinkPolling", "flow-director-atr", "veb-stats", @@ -249,6 +238,13 @@ static const char i40e_priv_flags_strings[][ETH_GSTRING_LEN] = { #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings) +/* Private flags with a global effect, restricted to PF 0 */ +static const char i40e_gl_priv_flags_strings[][ETH_GSTRING_LEN] = { + "vf-true-promisc-support", +}; + +#define I40E_GL_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gl_priv_flags_strings) + /** * i40e_partition_setting_complaint - generic complaint for MFP restriction * @pf: the PF struct @@ -1194,10 +1190,9 @@ static void i40e_get_drvinfo(struct net_device *netdev, sizeof(drvinfo->fw_version)); strlcpy(drvinfo->bus_info, pci_name(pf->pdev), sizeof(drvinfo->bus_info)); + drvinfo->n_priv_flags = I40E_PRIV_FLAGS_STR_LEN; if (pf->hw.pf_id == 0) - drvinfo->n_priv_flags = I40E_PRIV_FLAGS_GL_STR_LEN; - else - drvinfo->n_priv_flags = I40E_PRIV_FLAGS_STR_LEN; + drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN; } static void i40e_get_ringparam(struct net_device *netdev, @@ -1425,10 +1420,8 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset) return I40E_VSI_STATS_LEN(netdev); } case ETH_SS_PRIV_FLAGS: - if (pf->hw.pf_id == 0) - return I40E_PRIV_FLAGS_GL_STR_LEN; - else - return I40E_PRIV_FLAGS_STR_LEN; + return I40E_PRIV_FLAGS_STR_LEN + + (pf->hw.pf_id == 0 ? I40E_GL_PRIV_FLAGS_STR_LEN : 0); default: return -EOPNOTSUPP; } @@ -1626,15 +1619,14 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, /* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */ break; case ETH_SS_PRIV_FLAGS: + for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) { + memcpy(data, i40e_priv_flags_strings[i], + ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } if (pf->hw.pf_id == 0) { - for (i = 0; i < I40E_PRIV_FLAGS_GL_STR_LEN; i++) { - memcpy(data, i40e_priv_flags_strings_gl[i], - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } - } else { - for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) { - memcpy(data, i40e_priv_flags_strings[i], + for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++) { + memcpy(data, i40e_gl_priv_flags_strings[i], ETH_GSTRING_LEN); data += ETH_GSTRING_LEN; } From 91dc1e5d3dbe05046a1d5b7539e5ab08e96b2dd2 Mon Sep 17 00:00:00 2001 From: Michal Kosiarz Date: Tue, 25 Oct 2016 16:08:51 -0700 Subject: [PATCH 06/18] i40e: Add Clause22 implementation Some external PHYs require Clause22 method for accessing registers. This patch also adds some defines to support blink led on devices using 10CBaseT PHY. Change-ID: I868a4326911900f6c89e7e522fda4968b0825f14 Signed-off-by: Michal Kosiarz Signed-off-by: Matt Jared Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 180 +++++++++++++----- .../net/ethernet/intel/i40e/i40e_prototype.h | 12 +- drivers/net/ethernet/intel/i40e/i40e_type.h | 19 +- 3 files changed, 159 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 98791ba57211..5cef393407f9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -4396,7 +4396,99 @@ i40e_status i40e_aq_configure_partition_bw(struct i40e_hw *hw, } /** - * i40e_read_phy_register + * i40e_read_phy_register_clause22 + * @hw: pointer to the HW structure + * @reg: register address in the page + * @phy_adr: PHY address on MDIO interface + * @value: PHY register value + * + * Reads specified PHY register value + **/ +i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw, + u16 reg, u8 phy_addr, u16 *value) +{ + i40e_status status = I40E_ERR_TIMEOUT; + u8 port_num = (u8)hw->func_caps.mdio_port_num; + u32 command = 0; + u16 retry = 1000; + + command = (reg << I40E_GLGEN_MSCA_DEVADD_SHIFT) | + (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | + (I40E_MDIO_CLAUSE22_OPCODE_READ_MASK) | + (I40E_MDIO_CLAUSE22_STCODE_MASK) | + (I40E_GLGEN_MSCA_MDICMD_MASK); + wr32(hw, I40E_GLGEN_MSCA(port_num), command); + do { + command = rd32(hw, I40E_GLGEN_MSCA(port_num)); + if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) { + status = 0; + break; + } + udelay(10); + retry--; + } while (retry); + + if (status) { + i40e_debug(hw, I40E_DEBUG_PHY, + "PHY: Can't write command to external PHY.\n"); + goto phy_read_end; + } + + if (!status) { + command = rd32(hw, I40E_GLGEN_MSRWD(port_num)); + *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >> + I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT; + } else { + i40e_debug(hw, I40E_DEBUG_PHY, + "PHY: Can't read register value from external PHY.\n"); + } + +phy_read_end: + return status; +} + +/** + * i40e_write_phy_register_clause22 + * @hw: pointer to the HW structure + * @reg: register address in the page + * @phy_adr: PHY address on MDIO interface + * @value: PHY register value + * + * Writes specified PHY register value + **/ +i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw, + u16 reg, u8 phy_addr, u16 value) +{ + i40e_status status = I40E_ERR_TIMEOUT; + u8 port_num = (u8)hw->func_caps.mdio_port_num; + u32 command = 0; + u16 retry = 1000; + + command = value << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT; + wr32(hw, I40E_GLGEN_MSRWD(port_num), command); + + command = (reg << I40E_GLGEN_MSCA_DEVADD_SHIFT) | + (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | + (I40E_MDIO_CLAUSE22_OPCODE_WRITE_MASK) | + (I40E_MDIO_CLAUSE22_STCODE_MASK) | + (I40E_GLGEN_MSCA_MDICMD_MASK); + + wr32(hw, I40E_GLGEN_MSCA(port_num), command); + do { + command = rd32(hw, I40E_GLGEN_MSCA(port_num)); + if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) { + status = 0; + break; + } + udelay(10); + retry--; + } while (retry); + + return status; +} + +/** + * i40e_read_phy_register_clause45 * @hw: pointer to the HW structure * @page: registers page number * @reg: register address in the page @@ -4405,9 +4497,8 @@ i40e_status i40e_aq_configure_partition_bw(struct i40e_hw *hw, * * Reads specified PHY register value **/ -i40e_status i40e_read_phy_register(struct i40e_hw *hw, - u8 page, u16 reg, u8 phy_addr, - u16 *value) +i40e_status i40e_read_phy_register_clause45(struct i40e_hw *hw, + u8 page, u16 reg, u8 phy_addr, u16 *value) { i40e_status status = I40E_ERR_TIMEOUT; u32 command = 0; @@ -4417,8 +4508,8 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw, command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) | (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) | (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | - (I40E_MDIO_OPCODE_ADDRESS) | - (I40E_MDIO_STCODE) | + (I40E_MDIO_CLAUSE45_OPCODE_ADDRESS_MASK) | + (I40E_MDIO_CLAUSE45_STCODE_MASK) | (I40E_GLGEN_MSCA_MDICMD_MASK) | (I40E_GLGEN_MSCA_MDIINPROGEN_MASK); wr32(hw, I40E_GLGEN_MSCA(port_num), command); @@ -4440,8 +4531,8 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw, command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) | (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | - (I40E_MDIO_OPCODE_READ) | - (I40E_MDIO_STCODE) | + (I40E_MDIO_CLAUSE45_OPCODE_READ_MASK) | + (I40E_MDIO_CLAUSE45_STCODE_MASK) | (I40E_GLGEN_MSCA_MDICMD_MASK) | (I40E_GLGEN_MSCA_MDIINPROGEN_MASK); status = I40E_ERR_TIMEOUT; @@ -4471,7 +4562,7 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw, } /** - * i40e_write_phy_register + * i40e_write_phy_register_clause45 * @hw: pointer to the HW structure * @page: registers page number * @reg: register address in the page @@ -4480,9 +4571,8 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw, * * Writes value to specified PHY register **/ -i40e_status i40e_write_phy_register(struct i40e_hw *hw, - u8 page, u16 reg, u8 phy_addr, - u16 value) +i40e_status i40e_write_phy_register_clause45(struct i40e_hw *hw, + u8 page, u16 reg, u8 phy_addr, u16 value) { i40e_status status = I40E_ERR_TIMEOUT; u32 command = 0; @@ -4492,8 +4582,8 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw, command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) | (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) | (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | - (I40E_MDIO_OPCODE_ADDRESS) | - (I40E_MDIO_STCODE) | + (I40E_MDIO_CLAUSE45_OPCODE_ADDRESS_MASK) | + (I40E_MDIO_CLAUSE45_STCODE_MASK) | (I40E_GLGEN_MSCA_MDICMD_MASK) | (I40E_GLGEN_MSCA_MDIINPROGEN_MASK); wr32(hw, I40E_GLGEN_MSCA(port_num), command); @@ -4517,8 +4607,8 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw, command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) | (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) | - (I40E_MDIO_OPCODE_WRITE) | - (I40E_MDIO_STCODE) | + (I40E_MDIO_CLAUSE45_OPCODE_WRITE_MASK) | + (I40E_MDIO_CLAUSE45_STCODE_MASK) | (I40E_GLGEN_MSCA_MDICMD_MASK) | (I40E_GLGEN_MSCA_MDIINPROGEN_MASK); status = I40E_ERR_TIMEOUT; @@ -4580,14 +4670,16 @@ i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw, for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++, led_addr++) { - status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, &led_reg); + status = i40e_read_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, + &led_reg); if (status) goto phy_blinking_end; led_ctl = led_reg; if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) { led_reg = 0; - status = i40e_write_phy_register(hw, + status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, led_addr, phy_addr, led_reg); @@ -4599,20 +4691,18 @@ i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw, if (time > 0 && interval > 0) { for (i = 0; i < time * 1000; i += interval) { - status = i40e_read_phy_register(hw, - I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, - &led_reg); + status = i40e_read_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, &led_reg); if (status) goto restore_config; if (led_reg & I40E_PHY_LED_MANUAL_ON) led_reg = 0; else led_reg = I40E_PHY_LED_MANUAL_ON; - status = i40e_write_phy_register(hw, - I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, - led_reg); + status = i40e_write_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, led_reg); if (status) goto restore_config; msleep(interval); @@ -4620,8 +4710,9 @@ i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw, } restore_config: - status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr, - phy_addr, led_ctl); + status = i40e_write_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, led_ctl); phy_blinking_end: return status; @@ -4652,8 +4743,10 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr, for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++, temp_addr++) { - status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, - temp_addr, phy_addr, ®_val); + status = i40e_read_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + temp_addr, phy_addr, + ®_val); if (status) return status; *val = reg_val; @@ -4686,41 +4779,42 @@ i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on, i = rd32(hw, I40E_PFGEN_PORTNUM); port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK); phy_addr = i40e_get_phy_address(hw, port_num); - - status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr, - phy_addr, &led_reg); + status = i40e_read_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, &led_reg); if (status) return status; led_ctl = led_reg; if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) { led_reg = 0; - status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, led_reg); + status = i40e_write_phy_register_clause45(hw, + I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, + led_reg); if (status) return status; } - status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, &led_reg); + status = i40e_read_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, &led_reg); if (status) goto restore_config; if (on) led_reg = I40E_PHY_LED_MANUAL_ON; else led_reg = 0; - status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, - led_addr, phy_addr, led_reg); + status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, led_reg); if (status) goto restore_config; if (mode & I40E_PHY_LED_MODE_ORIG) { led_ctl = (mode & I40E_PHY_LED_MODE_MASK); - status = i40e_write_phy_register(hw, + status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, led_addr, phy_addr, led_ctl); } return status; restore_config: - status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr, - phy_addr, led_ctl); + status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE, + led_addr, phy_addr, led_ctl); return status; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 4660c5abc855..82dedc978482 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -362,10 +362,14 @@ i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw, u32 reg_addr, u32 reg_val, struct i40e_asq_cmd_details *cmd_details); void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val); -i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page, - u16 reg, u8 phy_addr, u16 *value); -i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page, - u16 reg, u8 phy_addr, u16 value); +i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw, + u16 reg, u8 phy_addr, u16 *value); +i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw, + u16 reg, u8 phy_addr, u16 value); +i40e_status i40e_read_phy_register_clause45(struct i40e_hw *hw, + u8 page, u16 reg, u8 phy_addr, u16 *value); +i40e_status i40e_write_phy_register_clause45(struct i40e_hw *hw, + u8 page, u16 reg, u8 phy_addr, u16 value); u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num); i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw, u32 time, u32 interval); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index d9a266041bf1..671969ce332c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -90,14 +90,23 @@ enum i40e_debug_mask { I40E_DEBUG_ALL = 0xFFFFFFFF }; -#define I40E_MDIO_STCODE 0 -#define I40E_MDIO_OPCODE_ADDRESS 0 -#define I40E_MDIO_OPCODE_WRITE I40E_MASK(1, \ +#define I40E_MDIO_CLAUSE22_STCODE_MASK I40E_MASK(1, \ + I40E_GLGEN_MSCA_STCODE_SHIFT) +#define I40E_MDIO_CLAUSE22_OPCODE_WRITE_MASK I40E_MASK(1, \ I40E_GLGEN_MSCA_OPCODE_SHIFT) -#define I40E_MDIO_OPCODE_READ_INC_ADDR I40E_MASK(2, \ +#define I40E_MDIO_CLAUSE22_OPCODE_READ_MASK I40E_MASK(2, \ I40E_GLGEN_MSCA_OPCODE_SHIFT) -#define I40E_MDIO_OPCODE_READ I40E_MASK(3, \ + +#define I40E_MDIO_CLAUSE45_STCODE_MASK I40E_MASK(0, \ + I40E_GLGEN_MSCA_STCODE_SHIFT) +#define I40E_MDIO_CLAUSE45_OPCODE_ADDRESS_MASK I40E_MASK(0, \ I40E_GLGEN_MSCA_OPCODE_SHIFT) +#define I40E_MDIO_CLAUSE45_OPCODE_WRITE_MASK I40E_MASK(1, \ + I40E_GLGEN_MSCA_OPCODE_SHIFT) +#define I40E_MDIO_CLAUSE45_OPCODE_READ_INC_ADDR_MASK I40E_MASK(2, \ + I40E_GLGEN_MSCA_OPCODE_SHIFT) +#define I40E_MDIO_CLAUSE45_OPCODE_READ_MASK I40E_MASK(3, \ + I40E_GLGEN_MSCA_OPCODE_SHIFT) #define I40E_PHY_COM_REG_PAGE 0x1E #define I40E_PHY_LED_LINK_MODE_MASK 0xF0 From 0b7c8b5d5436317a5f4509e2a150c6cec017f348 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 25 Oct 2016 16:08:52 -0700 Subject: [PATCH 07/18] i40e: fix trivial typo in naming of i40e_sync_filters_subtask A comment incorrectly referred to i40e_vsi_sync_filters_subtask which does not actually exist. Reference the correct function instead. Change-ID: I6bd805c605741ffb6fe34377259bb0d597edfafd Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fe5939a3536f..6832ab126d41 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1211,12 +1211,12 @@ bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi) * i40e_add_filter. * * 2) the only place where filters are actually removed is in - * i40e_vsi_sync_filters_subtask. + * i40e_sync_filters_subtask. * * Thus, we can simply use a boolean value, has_vlan_filters which we * will set to true when we add a VLAN filter in i40e_add_filter. Then * we have to perform the full search after deleting filters in - * i40e_vsi_sync_filters_subtask, but we already have to search + * i40e_sync_filters_subtask, but we already have to search * filters here and can perform the check at the same time. This * results in avoiding embedding a loop for VLAN mode inside another * loop over all the filters, and should maintain correctness as noted From 64f5ead95ade8d43e7f3ee79261b5525fff1feac Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Tue, 25 Oct 2016 16:08:53 -0700 Subject: [PATCH 08/18] i40e: Add protocols over MCTP to i40e_aq_discover_capabilities Add logical_id to I40E_AQ_CAP_ID_MNG_MODE capability starting from major version 2. Change-ID: Idb29214b172ea5c70cbd45a99e6745c0215af7e4 Signed-off-by: Piotr Raczynski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 8 ++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 4 ++++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 5cef393407f9..e83e8e399547 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -3147,6 +3147,14 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, break; case I40E_AQ_CAP_ID_MNG_MODE: p->management_mode = number; + if (major_rev > 1) { + p->mng_protocols_over_mctp = logical_id; + i40e_debug(hw, I40E_DEBUG_INIT, + "HW Capability: Protocols over MCTP = %d\n", + p->mng_protocols_over_mctp); + } else { + p->mng_protocols_over_mctp = 0; + } break; case I40E_AQ_CAP_ID_NPAR_ACTIVE: p->npar_enable = number; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 671969ce332c..bd1ffae4054d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -263,6 +263,10 @@ struct i40e_hw_capabilities { #define I40E_NVM_IMAGE_TYPE_UDP_CLOUD 0x3 u32 management_mode; + u32 mng_protocols_over_mctp; +#define I40E_MNG_PROTOCOL_PLDM 0x2 +#define I40E_MNG_PROTOCOL_OEM_COMMANDS 0x4 +#define I40E_MNG_PROTOCOL_NCSI 0x8 u32 npar_enable; u32 os2bmc; u32 valid_functions; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index ca7afe59c55f..515484c2b82a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -237,6 +237,10 @@ struct i40e_hw_capabilities { #define I40E_NVM_IMAGE_TYPE_UDP_CLOUD 0x3 u32 management_mode; + u32 mng_protocols_over_mctp; +#define I40E_MNG_PROTOCOL_PLDM 0x2 +#define I40E_MNG_PROTOCOL_OEM_COMMANDS 0x4 +#define I40E_MNG_PROTOCOL_NCSI 0x8 u32 npar_enable; u32 os2bmc; u32 valid_functions; From 2f7679ee2ec1bfc5042ff334bade395ef208d4fe Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Wed, 26 Oct 2016 10:49:27 -0700 Subject: [PATCH 09/18] i40e: fix panic on SPARC while changing num of desc On SPARC, writel() should not be used to write directly to memory address but only to memory mapped I/O address otherwise it causes data access exception. Commit 147e81ec75689 ("i40e: Test memory before ethtool alloc succeeds") introduced a code that uses memory address to fake the HW tail address and attempt to write to that address using writel() causes kernel panic on SPARC. The issue is reproduced while changing number of descriptors using ethtool. This change resolves the panic by using HW read-only memory mapped I/O register to fake HW tail address instead memory address. e.g. > ethtool -G eth2 tx 2048 rx 2048 i40e 0000:03:00.2 eth2: Changing Tx descriptor count from 512 to 2048. i40e 0000:03:00.2 eth2: Changing Rx descriptor count from 512 to 2048 sun4v_data_access_exception: ADDR[fff8001f9734a000] CTX[0000] TYPE[0004], going. \|/ ____ \|/ "@'/ .. \`@" /_| \__/ |_\ \__U_/ ethtool(3273): Dax [#1] CPU: 9 PID: 3273 Comm: ethtool Tainted: G E 4.8.0-linux-net_temp+ #7 task: fff8001f96d7a660 task.stack: fff8001f97348000 TSTATE: 0000009911001601 TPC: 00000000103189e4 TNPC: 00000000103189e8 Y: 00000000 Tainted: G E TPC: g0: fff8001f4eb64000 g1: 00000000000007ff g2: fff8001f9734b92c g3: 00203e0000000000 g4: fff8001f96d7a660 g5: fff8001fa6704000 g6: fff8001f97348000 g7: 0000000000000001 o0: 0006000046706928 o1: 00000000db3e2000 o2: fff8001f00000000 o3: 0000000000002000 o4: 0000000000002000 o5: 0000000000000001 sp: fff8001f9734afc1 ret_pc: 0000000010318a64 RPC: l0: fff8001f4e8bffe0 l1: fff8001f4e8cffe0 l2: 00000000000007ff l3: 00000000ff000000 l4: 0000000000ff0000 l5: 000000000000ff00 l6: 0000000000cda6a8 l7: 0000000000e822f0 i0: fff8001f96380000 i1: 0000000000000000 i2: 00203edb00000000 i3: 0006000046706928 i4: 0000000002086320 i5: 0000000000e82370 i6: fff8001f9734b071 i7: 00000000103062d4 I7: Call Trace: [00000000103062d4] i40e_set_ringparam+0x3b4/0x540 [i40e] [000000000094e2f8] dev_ethtool+0x898/0xbe0 [0000000000965570] dev_ioctl+0x250/0x300 [0000000000923800] sock_do_ioctl+0x40/0x60 [000000000092427c] sock_ioctl+0x7c/0x280 [00000000005ef040] vfs_ioctl+0x20/0x60 [00000000005ef5d4] do_vfs_ioctl+0x194/0x4c0 [00000000005ef974] SyS_ioctl+0x74/0xa0 [0000000000406214] linux_sparc_syscall+0x34/0x44 Disabling lock debugging due to kernel taint Caller[00000000103062d4]: i40e_set_ringparam+0x3b4/0x540 [i40e] Caller[000000000094e2f8]: dev_ethtool+0x898/0xbe0 Caller[0000000000965570]: dev_ioctl+0x250/0x300 Caller[0000000000923800]: sock_do_ioctl+0x40/0x60 Caller[000000000092427c]: sock_ioctl+0x7c/0x280 Caller[00000000005ef040]: vfs_ioctl+0x20/0x60 Caller[00000000005ef5d4]: do_vfs_ioctl+0x194/0x4c0 Caller[00000000005ef974]: SyS_ioctl+0x74/0xa0 Caller[0000000000406214]: linux_sparc_syscall+0x34/0x44 Caller[0000000000107154]: 0x107154 Instruction DUMP: e43620c8 e436204a c45e2038 82102000 81cfe008 90086001 82102000 81cfe008 Kernel panic - not syncing: Fatal exception Signed-off-by: Tushar Dave Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f99c135718dd..92a2f03a06c8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1217,6 +1217,7 @@ static int i40e_set_ringparam(struct net_device *netdev, { struct i40e_ring *tx_rings = NULL, *rx_rings = NULL; struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_hw *hw = &np->vsi->back->hw; struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; u32 new_rx_count, new_tx_count; @@ -1309,10 +1310,6 @@ static int i40e_set_ringparam(struct net_device *netdev, } for (i = 0; i < vsi->num_queue_pairs; i++) { - /* this is to allow wr32 to have something to write to - * during early allocation of Rx buffers - */ - u32 __iomem faketail = 0; struct i40e_ring *ring; u16 unused; @@ -1324,7 +1321,10 @@ static int i40e_set_ringparam(struct net_device *netdev, */ rx_rings[i].desc = NULL; rx_rings[i].rx_bi = NULL; - rx_rings[i].tail = (u8 __iomem *)&faketail; + /* this is to allow wr32 to have something to write to + * during early allocation of Rx buffers + */ + rx_rings[i].tail = hw->hw_addr + I40E_PRTGEN_STATUS; err = i40e_setup_rx_descriptors(&rx_rings[i]); if (err) goto rx_unwind; From dedecb6d429bd3311bb24ea1379b47c8471c88b9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 1 Nov 2016 15:35:14 -0700 Subject: [PATCH 10/18] i40evf: Move some i40evf_reset_task code to separate function The i40evf_reset_task function is a couple hundred lines and it has a separable block that disables VF. Move that block to a new i40evf_disable_vf function to shorten i40evf_reset_task a bit. Signed-off-by: Joe Perches Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_main.c | 86 ++++++++++--------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 7bbb55f303b1..f04ac36f25cf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1693,6 +1693,49 @@ static void i40evf_watchdog_task(struct work_struct *work) schedule_work(&adapter->adminq_task); } +static void i40evf_disable_vf(struct i40evf_adapter *adapter) +{ + struct i40evf_mac_filter *f, *ftmp; + struct i40evf_vlan_filter *fv, *fvtmp; + + adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; + + if (netif_running(adapter->netdev)) { + set_bit(__I40E_DOWN, &adapter->vsi.state); + netif_carrier_off(adapter->netdev); + netif_tx_disable(adapter->netdev); + adapter->link_up = false; + i40evf_napi_disable_all(adapter); + i40evf_irq_disable(adapter); + i40evf_free_traffic_irqs(adapter); + i40evf_free_all_tx_resources(adapter); + i40evf_free_all_rx_resources(adapter); + } + + /* Delete all of the filters, both MAC and VLAN. */ + list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { + list_del(&f->list); + kfree(f); + } + + list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, list) { + list_del(&fv->list); + kfree(fv); + } + + i40evf_free_misc_irq(adapter); + i40evf_reset_interrupt_capability(adapter); + i40evf_free_queues(adapter); + i40evf_free_q_vectors(adapter); + kfree(adapter->vf_res); + i40evf_shutdown_adminq(&adapter->hw); + adapter->netdev->flags &= ~IFF_UP; + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + adapter->state = __I40EVF_DOWN; + dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); +} + #define I40EVF_RESET_WAIT_MS 10 #define I40EVF_RESET_WAIT_COUNT 500 /** @@ -1758,50 +1801,9 @@ static void i40evf_reset_task(struct work_struct *work) pci_set_master(adapter->pdev); if (i == I40EVF_RESET_WAIT_COUNT) { - struct i40evf_mac_filter *ftmp; - struct i40evf_vlan_filter *fv, *fvtmp; - - /* reset never finished */ dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n", reg_val); - adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; - - if (netif_running(adapter->netdev)) { - set_bit(__I40E_DOWN, &adapter->vsi.state); - netif_carrier_off(netdev); - netif_tx_disable(netdev); - adapter->link_up = false; - i40evf_napi_disable_all(adapter); - i40evf_irq_disable(adapter); - i40evf_free_traffic_irqs(adapter); - i40evf_free_all_tx_resources(adapter); - i40evf_free_all_rx_resources(adapter); - } - - /* Delete all of the filters, both MAC and VLAN. */ - list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, - list) { - list_del(&f->list); - kfree(f); - } - - list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list, - list) { - list_del(&fv->list); - kfree(fv); - } - - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); - i40evf_free_queues(adapter); - i40evf_free_q_vectors(adapter); - kfree(adapter->vf_res); - i40evf_shutdown_adminq(hw); - adapter->netdev->flags &= ~IFF_UP; - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); - adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; - adapter->state = __I40EVF_DOWN; - dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); + i40evf_disable_vf(adapter); return; /* Do not attempt to reinit. It's dead, Jim. */ } From 47d2a5d8279dcdcaec2c67b3d2c72cfa62979c58 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Tue, 8 Nov 2016 13:05:05 -0800 Subject: [PATCH 11/18] i40evf: check for msix_entries null dereference It is possible for msix_entries to be freed by a previous suspend/remove before a VF is closed. This patch fixes the issue by checking for NULL before dereferencing msix_entries and returning early in the case where it is NULL within the i40evf_close code path. Without this patch it is possible to trigger a kernel panic through NULL dereference. Change-ID: I92a2746e82533a889e25f91578eac9abd0388ae2 Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f04ac36f25cf..420e5453effe 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -631,6 +631,9 @@ static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter) { int vector, irq_num, q_vectors; + if (!adapter->msix_entries) + return; + q_vectors = adapter->num_msix_vectors - NONQ_VECS; for (vector = 0; vector < q_vectors; vector++) { @@ -1443,6 +1446,9 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) **/ void i40evf_reset_interrupt_capability(struct i40evf_adapter *adapter) { + if (!adapter->msix_entries) + return; + pci_disable_msix(adapter->pdev); kfree(adapter->msix_entries); adapter->msix_entries = NULL; From 27e5f25b917b4d388ffba8dbfae4952834d48e49 Mon Sep 17 00:00:00 2001 From: Henry Tieman Date: Tue, 8 Nov 2016 13:05:06 -0800 Subject: [PATCH 12/18] i40e: Remove unreachable code The code at the end of i40e_read_phy_register_clause22() contained unreachable code and redundant control statements. This change removes the unreachable code. And deletes the redundant goto statement and if statement. Change-ID: I713032b1585396f40f903cbcfdea987abd874400 Signed-off-by: Henry Tieman Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index e83e8e399547..fc7ce0238dea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -4439,19 +4439,12 @@ i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw, if (status) { i40e_debug(hw, I40E_DEBUG_PHY, "PHY: Can't write command to external PHY.\n"); - goto phy_read_end; - } - - if (!status) { + } else { command = rd32(hw, I40E_GLGEN_MSRWD(port_num)); *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >> I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT; - } else { - i40e_debug(hw, I40E_DEBUG_PHY, - "PHY: Can't read register value from external PHY.\n"); } -phy_read_end: return status; } From e586bb66b57c2a50d464d0f87cf8c7c9c3b36835 Mon Sep 17 00:00:00 2001 From: Henry Tieman Date: Tue, 8 Nov 2016 13:05:07 -0800 Subject: [PATCH 13/18] i40e: Pass unknown PHY type for unknown PHYs The PHY type value for unrecognized PHYs and cables was changed based on firmware version number. Newer hardware use lower firmware version numbers and this was causing some PHYs to be identified as type 0x16 instead of 0xe (unknown). Without this patch, newer card will incorrectly identify unknown PHYs and cables. This change adds hardware type to the check for firmware version so the PHY type is reported correctly. Change-ID: I0723cbfd263c76fc73ff1a5275d1639051376c9a Signed-off-by: Henry Tieman Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index fc7ce0238dea..f6fee7950726 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1854,7 +1854,8 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, else hw_link_info->lse_enable = false; - if ((hw->aq.fw_maj_ver < 4 || (hw->aq.fw_maj_ver == 4 && + if ((hw->mac.type == I40E_MAC_XL710) && + (hw->aq.fw_maj_ver < 4 || (hw->aq.fw_maj_ver == 4 && hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE) hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU; From ef4603e82f64605e73495c26050f3f236609d991 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 8 Nov 2016 13:05:08 -0800 Subject: [PATCH 14/18] i40evf: protect against NULL msix_entries and q_vectors pointers Update the functions which free msix_entries and q_vectors so that they are safe against NULL values. This allows calling code to not care whether these have already been freed when disabling and freeing them. Change-ID: I31bfd1c0da18023d971b618edc6fb049721f3298 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40evf_main.c | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 420e5453effe..ca850212521e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -207,6 +207,9 @@ static void i40evf_misc_irq_disable(struct i40evf_adapter *adapter) { struct i40e_hw *hw = &adapter->hw; + if (!adapter->msix_entries) + return; + wr32(hw, I40E_VFINT_DYN_CTL01, 0); /* read flush */ @@ -654,6 +657,9 @@ static void i40evf_free_misc_irq(struct i40evf_adapter *adapter) { struct net_device *netdev = adapter->netdev; + if (!adapter->msix_entries) + return; + free_irq(adapter->msix_entries[0].vector, netdev); } @@ -1428,6 +1434,9 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) int q_idx, num_q_vectors; int napi_vectors; + if (!adapter->q_vectors) + return; + num_q_vectors = adapter->num_msix_vectors - NONQ_VECS; napi_vectors = adapter->num_active_queues; @@ -1437,6 +1446,7 @@ static void i40evf_free_q_vectors(struct i40evf_adapter *adapter) netif_napi_del(&q_vector->napi); } kfree(adapter->q_vectors); + adapter->q_vectors = NULL; } /** @@ -2862,12 +2872,10 @@ static void i40evf_remove(struct pci_dev *pdev) msleep(50); } - if (adapter->msix_entries) { - i40evf_misc_irq_disable(adapter); - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); - i40evf_free_q_vectors(adapter); - } + i40evf_misc_irq_disable(adapter); + i40evf_free_misc_irq(adapter); + i40evf_reset_interrupt_capability(adapter); + i40evf_free_q_vectors(adapter); if (adapter->watchdog_timer.function) del_timer_sync(&adapter->watchdog_timer); From 4ad9f4f9e2873ca999135b151dbb7d80f57ea0a9 Mon Sep 17 00:00:00 2001 From: Harshitha Ramamurthy Date: Tue, 8 Nov 2016 13:05:09 -0800 Subject: [PATCH 15/18] i40e: Fix for ethtool Supported link modes This patch fixes the problem where the ethtool Supported link modes list backplane interfaces on X722 devices for 10GbE with SFP+ and Cortina retimer. This patch fixes the problem by setting and using a flag for this particular device since the backplane interface is only between the internal PHY and the retimer and it should not be seen by the user as they cannot use it. Without this patch, the user wrongly thinks that backplane interfaces are supported on their device when they actually are not. Change-ID: I3882bc2928431d48a2db03a51a713a1f681a79e9 Signed-off-by: Harshitha Ramamurthy Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 16 ++++++++++------ drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 29c23183a0e0..4cb8fb3dcb34 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -359,6 +359,7 @@ struct i40e_pf { #define I40E_FLAG_HAVE_10GBASET_PHY BIT_ULL(48) #define I40E_FLAG_PF_MAC BIT_ULL(50) #define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(51) +#define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52) /* tracks features that get auto disabled by errors */ u64 auto_disable_flags; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 92a2f03a06c8..9500e7bba76d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -345,11 +345,13 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, u32 *supported, *advertising |= ADVERTISED_20000baseKR2_Full; } if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_KR) { - *supported |= SUPPORTED_10000baseKR_Full | - SUPPORTED_Autoneg; + if (!(pf->flags & I40E_FLAG_HAVE_CRT_RETIMER)) + *supported |= SUPPORTED_10000baseKR_Full | + SUPPORTED_Autoneg; *advertising |= ADVERTISED_Autoneg; if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB) - *advertising |= ADVERTISED_10000baseKR_Full; + if (!(pf->flags & I40E_FLAG_HAVE_CRT_RETIMER)) + *advertising |= ADVERTISED_10000baseKR_Full; } if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_KX4) { *supported |= SUPPORTED_10000baseKX4_Full | @@ -359,11 +361,13 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf, u32 *supported, *advertising |= ADVERTISED_10000baseKX4_Full; } if (phy_types & I40E_CAP_PHY_TYPE_1000BASE_KX) { - *supported |= SUPPORTED_1000baseKX_Full | - SUPPORTED_Autoneg; + if (!(pf->flags & I40E_FLAG_HAVE_CRT_RETIMER)) + *supported |= SUPPORTED_1000baseKX_Full | + SUPPORTED_Autoneg; *advertising |= ADVERTISED_Autoneg; if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB) - *advertising |= ADVERTISED_1000baseKX_Full; + if (!(pf->flags & I40E_FLAG_HAVE_CRT_RETIMER)) + *advertising |= ADVERTISED_1000baseKX_Full; } } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6832ab126d41..17dde8518403 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11302,7 +11302,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) || (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) pf->flags |= I40E_FLAG_HAVE_10GBASET_PHY; - + if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722) + pf->flags |= I40E_FLAG_HAVE_CRT_RETIMER; /* print a string summarizing features */ i40e_print_features(pf); From 435c084aad9615c7c77464e7c04600da920fc208 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 8 Nov 2016 13:05:10 -0800 Subject: [PATCH 16/18] i40e: set broadcast promiscuous mode for each active VLAN A previous workaround added to ensure receipt of all broadcast frames incorrectly set the broadcast promiscuous mode unconditionally regardless of active VLAN status. Replace this partial workaround with a complete solution that sets the broadcast promiscuous filters in i40e_sync_vsi_filters. This new method sets the promiscuous mode based on when broadcast filters are added or removed. I40E_VLAN_ANY will request a broadcast filter for all VLANs, (as we're in untagged mode) while a broadcast filter on a specific VLAN will only request broadcast for that VLAN. Thus, we restore addition of broadcast filter to the array, but we add special handling for these such that they enable the broadcast promiscuous mode instead of being sent as regular filters. The end result is that we will correctly receive all broadcast packets (even those with a *source* address equal to the broadcast address) but will not receive packets for which we don't have an active VLAN filter. Change-ID: I7d0585c5cec1a5bf55bf533b42e5e817d5db6a2d Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 34 ++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 106 ++++++++++++++---- .../net/ethernet/intel/i40e/i40e_prototype.h | 3 + .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 7 ++ 4 files changed, 129 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index f6fee7950726..eb392d63cd03 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2169,6 +2169,40 @@ enum i40e_status_code i40e_aq_set_vsi_uc_promisc_on_vlan(struct i40e_hw *hw, return status; } +/** + * i40e_aq_set_vsi_bc_promisc_on_vlan + * @hw: pointer to the hw struct + * @seid: vsi number + * @enable: set broadcast promiscuous enable/disable for a given VLAN + * @vid: The VLAN tag filter - capture any broadcast packet with this VLAN tag + * @cmd_details: pointer to command details structure or NULL + **/ +i40e_status i40e_aq_set_vsi_bc_promisc_on_vlan(struct i40e_hw *hw, + u16 seid, bool enable, u16 vid, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_set_vsi_promiscuous_modes *cmd = + (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw; + i40e_status status; + u16 flags = 0; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_vsi_promiscuous_modes); + + if (enable) + flags |= I40E_AQC_SET_VSI_PROMISC_BROADCAST; + + cmd->promiscuous_flags = cpu_to_le16(flags); + cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_BROADCAST); + cmd->seid = cpu_to_le16(seid); + cmd->vlan_tag = cpu_to_le16(vid | I40E_AQC_SET_VSI_VLAN_VALID); + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + /** * i40e_aq_set_vsi_broadcast * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 17dde8518403..594856d605ec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1245,13 +1245,6 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, if (!vsi || !macaddr) return NULL; - /* Do not allow broadcast filter to be added since broadcast filter - * is added as part of add VSI for any newly created VSI except - * FDIR VSI - */ - if (is_broadcast_ether_addr(macaddr)) - return NULL; - f = i40e_find_filter(vsi, macaddr, vlan); if (!f) { f = kzalloc(sizeof(*f), GFP_ATOMIC); @@ -1856,6 +1849,47 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name, } } +/** + * i40e_aqc_broadcast_filter - Set promiscuous broadcast flags + * @vsi: pointer to the VSI + * @f: filter data + * + * This function sets or clears the promiscuous broadcast flags for VLAN + * filters in order to properly receive broadcast frames. Assumes that only + * broadcast filters are passed. + **/ +static +void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name, + struct i40e_mac_filter *f) +{ + bool enable = f->state == I40E_FILTER_NEW; + struct i40e_hw *hw = &vsi->back->hw; + i40e_status aq_ret; + + if (f->vlan == I40E_VLAN_ANY) { + aq_ret = i40e_aq_set_vsi_broadcast(hw, + vsi->seid, + enable, + NULL); + } else { + aq_ret = i40e_aq_set_vsi_bc_promisc_on_vlan(hw, + vsi->seid, + enable, + f->vlan, + NULL); + } + + if (aq_ret) { + dev_warn(&vsi->back->pdev->dev, + "Error %s setting broadcast promiscuous mode on %s\n", + i40e_aq_str(hw, hw->aq.asq_last_status), + vsi_name); + f->state = I40E_FILTER_FAILED; + } else if (enable) { + f->state = I40E_FILTER_ACTIVE; + } +} + /** * i40e_sync_vsi_filters - Update the VSI filter list to the HW * @vsi: ptr to the VSI @@ -2004,6 +2038,17 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) hlist_for_each_entry_safe(f, h, &tmp_del_list, hlist) { cmd_flags = 0; + /* handle broadcast filters by updating the broadcast + * promiscuous flag instead of deleting a MAC filter. + */ + if (is_broadcast_ether_addr(f->macaddr)) { + i40e_aqc_broadcast_filter(vsi, vsi_name, f); + + hlist_del(&f->hlist); + kfree(f); + continue; + } + /* add to delete list */ ether_addr_copy(del_list[num_del].mac_addr, f->macaddr); if (f->vlan == I40E_VLAN_ANY) { @@ -2060,12 +2105,25 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) goto err_no_memory; num_add = 0; - hlist_for_each_entry(f, &tmp_add_list, hlist) { + hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) { if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)) { f->state = I40E_FILTER_FAILED; continue; } + + /* handle broadcast filters by updating the broadcast + * promiscuous flag instead of adding a MAC filter. + */ + if (is_broadcast_ether_addr(f->macaddr)) { + u64 key = i40e_addr_to_hkey(f->macaddr); + i40e_aqc_broadcast_filter(vsi, vsi_name, f); + + hlist_del(&f->hlist); + hash_add(vsi->mac_filter_hash, &f->hlist, key); + continue; + } + /* add to add array */ if (num_add == 0) add_head = f; @@ -9178,6 +9236,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) struct i40e_hw *hw = &pf->hw; struct i40e_netdev_priv *np; struct net_device *netdev; + u8 broadcast[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; int etherdev_size; @@ -9246,6 +9305,24 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) spin_unlock_bh(&vsi->mac_filter_hash_lock); } + /* Add the broadcast filter so that we initially will receive + * broadcast packets. Note that when a new VLAN is first added the + * driver will convert all filters marked I40E_VLAN_ANY into VLAN + * specific filters as part of transitioning into "vlan" operation. + * When more VLANs are added, the driver will copy each existing MAC + * filter and add it for the new VLAN. + * + * Broadcast filters are handled specially by + * i40e_sync_filters_subtask, as the driver must to set the broadcast + * promiscuous bit instead of adding this directly as a MAC/VLAN + * filter. The subtask will update the correct broadcast promiscuous + * bits as VLANs become active or inactive. + */ + eth_broadcast_addr(broadcast); + spin_lock_bh(&vsi->mac_filter_hash_lock); + i40e_add_filter(vsi, broadcast, I40E_VLAN_ANY); + spin_unlock_bh(&vsi->mac_filter_hash_lock); + ether_addr_copy(netdev->dev_addr, mac_addr); ether_addr_copy(netdev->perm_addr, mac_addr); @@ -9328,7 +9405,6 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi) static int i40e_add_vsi(struct i40e_vsi *vsi) { int ret = -ENODEV; - i40e_status aq_ret = 0; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; struct i40e_vsi_context ctxt; @@ -9518,18 +9594,6 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) vsi->seid = ctxt.seid; vsi->id = ctxt.vsi_number; } - /* Except FDIR VSI, for all othet VSI set the broadcast filter */ - if (vsi->type != I40E_VSI_FDIR) { - aq_ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL); - if (aq_ret) { - ret = i40e_aq_rc_to_posix(aq_ret, - hw->aq.asq_last_status); - dev_info(&pf->pdev->dev, - "set brdcast promisc failed, err %s, aq_err %s\n", - i40e_stat_str(hw, aq_ret), - i40e_aq_str(hw, hw->aq.asq_last_status)); - } - } vsi->active_filters = 0; clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 82dedc978482..37d67e792ad0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -144,6 +144,9 @@ enum i40e_status_code i40e_aq_set_vsi_uc_promisc_on_vlan(struct i40e_hw *hw, u16 seid, bool enable, u16 vid, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_set_vsi_bc_promisc_on_vlan(struct i40e_hw *hw, + u16 seid, bool enable, u16 vid, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw, u16 seid, bool enable, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 46908c0f834a..05ed49b4b7c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -674,6 +674,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) } if (type == I40E_VSI_SRIOV) { u64 hena = i40e_pf_get_default_rss_hena(pf); + u8 broadcast[ETH_ALEN]; vf->lan_vsi_idx = vsi->idx; vf->lan_vsi_id = vsi->id; @@ -696,6 +697,12 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) "Could not add MAC filter %pM for VF %d\n", vf->default_lan_addr.addr, vf->vf_id); } + eth_broadcast_addr(broadcast); + f = i40e_add_filter(vsi, broadcast, + vf->port_vlan_id ? vf->port_vlan_id : -1); + if (!f) + dev_info(&pf->pdev->dev, + "Could not allocate VF broadcast filter\n"); spin_unlock_bh(&vsi->mac_filter_hash_lock); i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena); From e5d32205555da77ec8d0d129ffa27c20f3d60230 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 8 Nov 2016 13:05:11 -0800 Subject: [PATCH 17/18] i40e/i40evf: replace for memcpy with single memcpy call in ethtool memcpy replaced with single memcpy call in ethtool. Change-ID: I3f5bef6bcc593412c56592c6459784db41575a0a Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9500e7bba76d..76753e1ff6c2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1536,10 +1536,8 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, switch (stringset) { case ETH_SS_TEST: - for (i = 0; i < I40E_TEST_LEN; i++) { - memcpy(data, i40e_gstrings_test[i], ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + memcpy(data, i40e_gstrings_test, + I40E_TEST_LEN * ETH_GSTRING_LEN); break; case ETH_SS_STATS: for (i = 0; i < I40E_NETDEV_STATS_LEN; i++) { @@ -1623,18 +1621,12 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, /* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */ break; case ETH_SS_PRIV_FLAGS: - for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) { - memcpy(data, i40e_priv_flags_strings[i], - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } - if (pf->hw.pf_id == 0) { - for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++) { - memcpy(data, i40e_gl_priv_flags_strings[i], - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } - } + memcpy(data, i40e_priv_flags_strings, + I40E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); + data += I40E_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN; + if (pf->hw.pf_id == 0) + memcpy(data, i40e_gl_priv_flags_strings, + I40E_GL_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); break; default: break; From 23bb6dc3644a6705c989e326362c7ccf05807477 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Tue, 8 Nov 2016 13:05:12 -0800 Subject: [PATCH 18/18] i40e: change message to only appear when extra debug info is wanted This patch changes an X722 informational message so that it only appears when extra messages are desired. Without this patch, on X722 devices, this message appears at load, potentially causing unnecessary alarm. Change-ID: I94f7aae15dc5b2723cc9728c630c72538a3e670e Signed-off-by: Carolyn Wyborny Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 594856d605ec..5777e49ee9e4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3579,7 +3579,7 @@ static irqreturn_t i40e_intr(int irq, void *data) (ena_mask & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) { ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; icr0 &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; - dev_info(&pf->pdev->dev, "cleared PE_CRITERR\n"); + dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n"); } /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */