From a410c821c0cf50bc0b73a91435852cd04b2c7acd Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Mon, 12 Dec 2016 15:44:07 -0800 Subject: [PATCH 01/13] i40e: fix disable overflow promiscuous mode There exists a bug in which the driver is unable to exit overflow promiscuous mode after having added "too many" mac filters. It is expected that after triggering overflow promiscuous, removing the failed/extra filters should then disable overflow promiscuous mode. The bug exists because we were intentionally skipping the sync_vsi_filter path in cases where we were removing failed filters since they shouldn't have been added to the firmware in the first place, however we still need to go through the sync_vsi_filter code path to determine whether or not it is ok to exit overflow promiscuous mode. This patch fixes the bug by making sure we go through the sync_vsi_filter path in cases of failed filters. Change-ID: I634d249ca3e5fa50729553137c295e73e7722143 Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e83a8ca5dd65..fb8a52dd94cd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1447,18 +1447,20 @@ void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f) if (!f) return; + /* If the filter was never added to firmware then we can just delete it + * directly and we don't want to set the status to remove or else an + * admin queue command will unnecessarily fire. + */ if ((f->state == I40E_FILTER_FAILED) || (f->state == I40E_FILTER_NEW)) { - /* this one never got added by the FW. Just remove it, - * no need to sync anything. - */ hash_del(&f->hlist); kfree(f); } else { f->state = I40E_FILTER_REMOVE; - vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; - vsi->back->flags |= I40E_FLAG_FILTER_SYNC; } + + vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; + vsi->back->flags |= I40E_FLAG_FILTER_SYNC; } /** From 1d68005db4e72082f3e537d6c0cf831a71a7e2ee Mon Sep 17 00:00:00 2001 From: Joshua Hay Date: Mon, 12 Dec 2016 15:44:08 -0800 Subject: [PATCH 02/13] i40e: enable mc magic pkt wakeup during power down This patch adds a call to the mac_address_write admin q function during power down to update the PRTPM_SAH/SAL registers with the MC_MAG_EN bit thus enabling multicast magic packet wakeup. A FW workaround is needed to write the multicast magic wake up enable bit in the PRTPM_SAH register. The FW expects the mac address write admin q cmd to be called first with one of the WRITE_TYPE_LAA flags and then with the multicast relevant flags. *Note: This solution only works for X722 devices currently. A PFR will clear the previously mentioned bit by default, but X722 has support for a WOL_PRESERVE_ON_PFR flag which prevents the bit from being cleared. Once other devices support this flag, this solution should work as well. Change-ID: I51bd5b8535bd9051c2676e27c999c1657f786827 Signed-off-by: Joshua Hay Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + .../net/ethernet/intel/i40e/i40e_adminq_cmd.h | 2 + drivers/net/ethernet/intel/i40e/i40e_main.c | 74 ++++++++++++++++--- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 7a23d3e47c6f..f4c4ee3edde1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -348,6 +348,7 @@ struct i40e_pf { #define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(51) #define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52) #define I40E_FLAG_PTP_L4_CAPABLE BIT_ULL(53) +#define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(54) /* tracks features that get auto disabled by errors */ u64 auto_disable_flags; diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index b2101a51534c..451f48b7540a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -538,6 +538,8 @@ I40E_CHECK_STRUCT_LEN(24, i40e_aqc_mac_address_read_data); /* Manage MAC Address Write Command (0x0108) */ struct i40e_aqc_mac_address_write { __le16 command_flags; +#define I40E_AQC_MC_MAG_EN 0x0100 +#define I40E_AQC_WOL_PRESERVE_ON_PFR 0x0200 #define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 #define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 #define I40E_AQC_WRITE_TYPE_PORT 0x8000 diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fb8a52dd94cd..e9335af4cc28 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8815,16 +8815,17 @@ static int i40e_sw_init(struct i40e_pf *pf) } #endif /* CONFIG_PCI_IOV */ if (pf->hw.mac.type == I40E_MAC_X722) { - pf->flags |= I40E_FLAG_RSS_AQ_CAPABLE | - I40E_FLAG_128_QP_RSS_CAPABLE | - I40E_FLAG_HW_ATR_EVICT_CAPABLE | - I40E_FLAG_OUTER_UDP_CSUM_CAPABLE | - I40E_FLAG_WB_ON_ITR_CAPABLE | - I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE | - I40E_FLAG_NO_PCI_LINK_CHECK | - I40E_FLAG_USE_SET_LLDP_MIB | - I40E_FLAG_GENEVE_OFFLOAD_CAPABLE | - I40E_FLAG_PTP_L4_CAPABLE; + pf->flags |= I40E_FLAG_RSS_AQ_CAPABLE + | I40E_FLAG_128_QP_RSS_CAPABLE + | I40E_FLAG_HW_ATR_EVICT_CAPABLE + | I40E_FLAG_OUTER_UDP_CSUM_CAPABLE + | I40E_FLAG_WB_ON_ITR_CAPABLE + | I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE + | I40E_FLAG_NO_PCI_LINK_CHECK + | I40E_FLAG_USE_SET_LLDP_MIB + | I40E_FLAG_GENEVE_OFFLOAD_CAPABLE + | I40E_FLAG_PTP_L4_CAPABLE + | I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE; } else if ((pf->hw.aq.api_maj_ver > 1) || ((pf->hw.aq.api_maj_ver == 1) && (pf->hw.aq.api_min_ver > 4))) { @@ -11740,6 +11741,53 @@ static void i40e_pci_error_resume(struct pci_dev *pdev) rtnl_unlock(); } +/** + * i40e_enable_mc_magic_wake - enable multicast magic packet wake up + * using the mac_address_write admin q function + * @pf: pointer to i40e_pf struct + **/ +static void i40e_enable_mc_magic_wake(struct i40e_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + i40e_status ret; + u8 mac_addr[6]; + u16 flags = 0; + + /* Get current MAC address in case it's an LAA */ + if (pf->vsi[pf->lan_vsi] && pf->vsi[pf->lan_vsi]->netdev) { + ether_addr_copy(mac_addr, + pf->vsi[pf->lan_vsi]->netdev->dev_addr); + } else { + dev_err(&pf->pdev->dev, + "Failed to retrieve MAC address; using default\n"); + ether_addr_copy(mac_addr, hw->mac.addr); + } + + /* The FW expects the mac address write cmd to first be called with + * one of these flags before calling it again with the multicast + * enable flags. + */ + flags = I40E_AQC_WRITE_TYPE_LAA_WOL; + + if (hw->func_caps.flex10_enable && hw->partition_id != 1) + flags = I40E_AQC_WRITE_TYPE_LAA_ONLY; + + ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); + if (ret) { + dev_err(&pf->pdev->dev, + "Failed to update MAC address registers; cannot enable Multicast Magic packet wake up"); + return; + } + + flags = I40E_AQC_MC_MAG_EN + | I40E_AQC_WOL_PRESERVE_ON_PFR + | I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG; + ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); + if (ret) + dev_err(&pf->pdev->dev, + "Failed to enable Multicast Magic Packet wake up\n"); +} + /** * i40e_shutdown - PCI callback for shutting down * @pdev: PCI device information struct @@ -11762,6 +11810,9 @@ static void i40e_shutdown(struct pci_dev *pdev) cancel_work_sync(&pf->service_task); i40e_fdir_teardown(pf); + if (pf->wol_en && (pf->flags & I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE)) + i40e_enable_mc_magic_wake(pf); + rtnl_lock(); i40e_prep_for_reset(pf); rtnl_unlock(); @@ -11793,6 +11844,9 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) set_bit(__I40E_SUSPENDED, &pf->state); set_bit(__I40E_DOWN, &pf->state); + if (pf->wol_en && (pf->flags & I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE)) + i40e_enable_mc_magic_wake(pf); + rtnl_lock(); i40e_prep_for_reset(pf); rtnl_unlock(); From 03aa268b146127361c206fe3942add2adf6ce1d7 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 12 Dec 2016 15:44:09 -0800 Subject: [PATCH 03/13] i40e: remove unnecessary call to i40e_update_link_info This call is made just prior to running i40e_link_event. In i40e_link_event, we set hw->phy.get_link_info to true just prior to calling i40e_get_link_status, which conveniently runs i40e_update_link_info for us. Thus, we are running i40e_update_link_info twice, which seems like something we don't need to do... Change-ID: I36467a570f44b7546d218c99e134ff97c2709315 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index e9335af4cc28..a6dca5822cff 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10761,7 +10761,6 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) i40e_pf_config_rss(pf); /* fill in link information and enable LSE reporting */ - i40e_update_link_info(&pf->hw); i40e_link_event(pf); /* Initialize user-specific link properties */ From 8a68badd12a8b708a02d54cd5aac4d07851a6d5a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 12 Dec 2016 15:44:10 -0800 Subject: [PATCH 04/13] i40evf: free rings in remove function When the i40evf_remove() calls netdev close, the device doesn't actually close - it schedules the work for the watchdog to perform. Since we're stopping the watchdog, this work doesn't get done. However, we're resetting the part, so we can free resources after the reset request has gone through. This plugs a memory leak. Change-ID: Id5335dcaf76ce00d2a4c3d26e9faf711d7f051cf Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 920c1cb06a92..5673dbd2cf7d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2871,7 +2871,8 @@ static void i40evf_remove(struct pci_dev *pdev) i40evf_request_reset(adapter); msleep(50); } - + i40evf_free_all_tx_resources(adapter); + i40evf_free_all_rx_resources(adapter); i40evf_misc_irq_disable(adapter); i40evf_free_misc_irq(adapter); i40evf_reset_interrupt_capability(adapter); From 51f38262669b88b6f5ec52cb93dc72c58d85dc1f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 12 Dec 2016 15:44:11 -0800 Subject: [PATCH 05/13] i40evf: add comment Add a comment to reduce confusion. Change-ID: I3d5819c0f3f5174680442ae54398a073d4a61f4f Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 5673dbd2cf7d..f35dcaac5bb7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2153,6 +2153,11 @@ static int i40evf_close(struct net_device *netdev) adapter->state = __I40EVF_DOWN_PENDING; i40evf_free_traffic_irqs(adapter); + /* We explicitly don't free resources here because the hardware is + * still active and can DMA into memory. Resources are cleared in + * i40evf_virtchnl_completion() after we get confirmation from the PF + * driver that the rings have been stopped. + */ return 0; } From 3c234c4709529298498b597bcff35f56ac866a99 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Mon, 12 Dec 2016 15:44:12 -0800 Subject: [PATCH 06/13] i40e: Fix Adaptive ITR enabling This patch fixes a bug introduced with the addition of the per queue ITR feature support in ethtool. With that addition, there were functions added which converted the ITR settings to binary values. The IS_ENABLED macros that run on those values check whether a bit is set or not and with the value being binary, the bit check always returned ITR disabled which prevents any updating of the ITR rate. This patch fixes the problem by changing the functions to return the current ITR value instead and renaming it to better reflect its function. These functions now provide a value which will be accurately asessed and update the ITR as intended. Change-ID: I14f1d088d052e27f652aaa3113e186415ddea1fc Signed-off-by: Carolyn Wyborny Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 12 ++++++------ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 09f09ea7a5e5..4dc993bb16bf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1864,14 +1864,14 @@ static u32 i40e_buildreg_itr(const int type, const u16 itr) /* a small macro to shorten up some long lines */ #define INTREG I40E_PFINT_DYN_CTLN -static inline int get_rx_itr_enabled(struct i40e_vsi *vsi, int idx) +static inline int get_rx_itr(struct i40e_vsi *vsi, int idx) { - return !!(vsi->rx_rings[idx]->rx_itr_setting); + return vsi->rx_rings[idx]->rx_itr_setting; } -static inline int get_tx_itr_enabled(struct i40e_vsi *vsi, int idx) +static inline int get_tx_itr(struct i40e_vsi *vsi, int idx) { - return !!(vsi->tx_rings[idx]->tx_itr_setting); + return vsi->tx_rings[idx]->tx_itr_setting; } /** @@ -1897,8 +1897,8 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, */ rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0); - rx_itr_setting = get_rx_itr_enabled(vsi, idx); - tx_itr_setting = get_tx_itr_enabled(vsi, idx); + rx_itr_setting = get_rx_itr(vsi, idx); + tx_itr_setting = get_tx_itr(vsi, idx); if (q_vector->itr_countdown > 0 || (!ITR_IS_DYNAMIC(rx_itr_setting) && diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index b758846d4dc5..7cd28ef6e714 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1324,18 +1324,18 @@ static u32 i40e_buildreg_itr(const int type, const u16 itr) /* a small macro to shorten up some long lines */ #define INTREG I40E_VFINT_DYN_CTLN1 -static inline int get_rx_itr_enabled(struct i40e_vsi *vsi, int idx) +static inline int get_rx_itr(struct i40e_vsi *vsi, int idx) { struct i40evf_adapter *adapter = vsi->back; - return !!(adapter->rx_rings[idx].rx_itr_setting); + return adapter->rx_rings[idx].rx_itr_setting; } -static inline int get_tx_itr_enabled(struct i40e_vsi *vsi, int idx) +static inline int get_tx_itr(struct i40e_vsi *vsi, int idx) { struct i40evf_adapter *adapter = vsi->back; - return !!(adapter->tx_rings[idx].tx_itr_setting); + return adapter->tx_rings[idx].tx_itr_setting; } /** @@ -1361,8 +1361,8 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, */ rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0); - rx_itr_setting = get_rx_itr_enabled(vsi, idx); - tx_itr_setting = get_tx_itr_enabled(vsi, idx); + rx_itr_setting = get_rx_itr(vsi, idx); + tx_itr_setting = get_tx_itr(vsi, idx); if (q_vector->itr_countdown > 0 || (!ITR_IS_DYNAMIC(rx_itr_setting) && From 773d4023badee2e196f4125a94fe9d5a739720a0 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Mon, 12 Dec 2016 15:44:13 -0800 Subject: [PATCH 07/13] i40e: refactor AQ CMD buffer debug printing This patch refactors the '%*ph' printk format specifier to instead use the print_hex_dump function, as recommended by the '%*ph' documentation. This produces better/more standardized output. Change-ID: Id56700b4e8abc40ff8c04bc8379e7df04cb4d6fd Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 19 ++++++++++++------- .../net/ethernet/intel/i40evf/i40e_common.c | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index fc73e4ef27ac..ece57d6a6e23 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -300,7 +300,6 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; u16 len; u8 *buf = (u8 *)buffer; - u16 i = 0; if ((!(mask & hw->debug_mask)) || (desc == NULL)) return; @@ -328,12 +327,18 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, if (buf_len < len) len = buf_len; /* write the full 16-byte chunks */ - for (i = 0; i < (len - 16); i += 16) - i40e_debug(hw, mask, "\t0x%04X %16ph\n", i, buf + i); - /* write whatever's left over without overrunning the buffer */ - if (i < len) - i40e_debug(hw, mask, "\t0x%04X %*ph\n", - i, len - i, buf + i); + if (hw->debug_mask & mask) { + char prefix[20]; + + snprintf(prefix, 20, + "i40e %02x:%02x.%x: \t0x", + hw->bus.bus_id, + hw->bus.device, + hw->bus.func); + + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); + } } } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index b5a59dd72a0c..89dfdbca13db 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -304,7 +304,6 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, { struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc; u8 *buf = (u8 *)buffer; - u16 i = 0; if ((!(mask & hw->debug_mask)) || (desc == NULL)) return; @@ -332,12 +331,18 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc, if (buf_len < len) len = buf_len; /* write the full 16-byte chunks */ - for (i = 0; i < (len - 16); i += 16) - i40e_debug(hw, mask, "\t0x%04X %16ph\n", i, buf + i); - /* write whatever's left over without overrunning the buffer */ - if (i < len) - i40e_debug(hw, mask, "\t0x%04X %*ph\n", - i, len - i, buf + i); + if (hw->debug_mask & mask) { + char prefix[20]; + + snprintf(prefix, 20, + "i40evf %02x:%02x.%x: \t0x", + hw->bus.bus_id, + hw->bus.device, + hw->bus.func); + + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, + 16, 1, buf, len, false); + } } } From 2ae0bf501425cbddc8b992a2b65fc04d911cae8c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 12 Dec 2016 15:44:14 -0800 Subject: [PATCH 08/13] i40e: convert to cpu from le16 to generate switch_id correctly On Big Endian platforms we would incorrectly calculate the wrong switch id since we did not properly convert the le16 value into CPU format. Caught by sparse. Change-ID: I69a2f9fa064a0a91691f7d0e6fcc206adceb8e36 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index f1f41f12902f..267ad2588255 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -974,7 +974,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, struct i40e_dcbx_config *r_cfg = &pf->hw.remote_dcbx_config; int i, ret; - u32 switch_id; + u16 switch_id; bw_data = kzalloc(sizeof( struct i40e_aqc_query_port_ets_config_resp), @@ -986,7 +986,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp, vsi = pf->vsi[pf->lan_vsi]; switch_id = - vsi->info.switch_id & I40E_AQ_VSI_SW_ID_MASK; + le16_to_cpu(vsi->info.switch_id) & + I40E_AQ_VSI_SW_ID_MASK; ret = i40e_aq_query_port_ets_config(&pf->hw, switch_id, From 5cb259016b4258d7ac53588a01d17da1ceda84b7 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 12 Dec 2016 15:44:15 -0800 Subject: [PATCH 09/13] i40e: properly convert le16 value to CPU format This ensures that the pvid which is stored in __le16 format is converted to the CPU format. This will fix comparison issues on Big Endian platforms. Change-ID: I92c80d1315dc2a0f9f095d5a0c48d461beb052ed Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a6dca5822cff..df78271bdce5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1254,6 +1254,7 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi, struct hlist_head *tmp_del_list, int vlan_filters) { + s16 pvid = le16_to_cpu(vsi->info.pvid); struct i40e_mac_filter *f, *add_head; struct i40e_new_mac_filter *new; struct hlist_node *h; @@ -1275,8 +1276,8 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi, /* Update the filters about to be added in place */ hlist_for_each_entry(new, tmp_add_list, hlist) { - if (vsi->info.pvid && new->f->vlan != vsi->info.pvid) - new->f->vlan = vsi->info.pvid; + if (pvid && new->f->vlan != pvid) + new->f->vlan = pvid; else if (vlan_filters && new->f->vlan == I40E_VLAN_ANY) new->f->vlan = 0; else if (!vlan_filters && new->f->vlan == 0) @@ -1290,12 +1291,12 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi, * order to avoid duplicating code for adding the new filter * then deleting the old filter. */ - if ((vsi->info.pvid && f->vlan != vsi->info.pvid) || + if ((pvid && f->vlan != pvid) || (vlan_filters && f->vlan == I40E_VLAN_ANY) || (!vlan_filters && f->vlan == 0)) { /* Determine the new vlan we will be adding */ - if (vsi->info.pvid) - new_vlan = vsi->info.pvid; + if (pvid) + new_vlan = pvid; else if (vlan_filters) new_vlan = 0; else From ae13670824d5adadc95a881ebfaa6fa8735218f0 Mon Sep 17 00:00:00 2001 From: Harshitha Ramamurthy Date: Mon, 12 Dec 2016 15:44:16 -0800 Subject: [PATCH 10/13] i40e: Error handling for link event There exists an intermittent bug which causes the 'Link Detected' field reported by the 'ethtool ' command to be 'Yes' when in fact, there is no link. This patch fixes the problem by enabling temporary link polling when i40e_get_link_status returns an error. This causes the driver to remember that an admin queue command failed and polls, until the function returns with a success. Change-Id: I64c69b008db4017b8729f3fc27b8f65c8fe2eaa0 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_main.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index f4c4ee3edde1..82d8040fa418 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -349,6 +349,7 @@ struct i40e_pf { #define I40E_FLAG_HAVE_CRT_RETIMER BIT_ULL(52) #define I40E_FLAG_PTP_L4_CAPABLE BIT_ULL(53) #define I40E_FLAG_WOL_MC_MAGIC_PKT_WAKE BIT_ULL(54) +#define I40E_FLAG_TEMP_LINK_POLLING BIT_ULL(55) /* tracks features that get auto disabled by errors */ u64 auto_disable_flags; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index df78271bdce5..199ef34e00f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6353,7 +6353,16 @@ static void i40e_link_event(struct i40e_pf *pf) old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP); status = i40e_get_link_status(&pf->hw, &new_link); - if (status) { + + /* On success, disable temp link polling */ + if (status == I40E_SUCCESS) { + if (pf->flags & I40E_FLAG_TEMP_LINK_POLLING) + pf->flags &= ~I40E_FLAG_TEMP_LINK_POLLING; + } else { + /* Enable link polling temporarily until i40e_get_link_status + * returns I40E_SUCCESS + */ + pf->flags |= I40E_FLAG_TEMP_LINK_POLLING; dev_dbg(&pf->pdev->dev, "couldn't get link state, status: %d\n", status); return; @@ -6405,7 +6414,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) return; pf->service_timer_previous = jiffies; - if (pf->flags & I40E_FLAG_LINK_POLLING_ENABLED) + if ((pf->flags & I40E_FLAG_LINK_POLLING_ENABLED) || + (pf->flags & I40E_FLAG_TEMP_LINK_POLLING)) i40e_link_event(pf); /* Update the stats for active netdevs so the network stack From b9c015d421946fe3675fcb9cbacd0a37f1d3263c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 12 Dec 2016 15:44:17 -0800 Subject: [PATCH 11/13] i40e: mark the value passed to csum_replace_by_diff as __wsum Fix, or rather, avoid a sparse warning caused by the fact that csum_replace_by_diff expects to receive a __wsum value. Since the calculation appears to work, simply typecast the passed paylen value to __wsum to avoid the warning. This seems pretty fishy since __wsum was obviously annotated as a separate type on purpose, so this throws the entire calculation into question. Since it currently appears to behave as expected, the typecast is probably safe. Change-ID: I4fdc5cddd589abc16098176e8a61127e761488f4 Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 5 +++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 4dc993bb16bf..97d46058d71d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2335,7 +2335,8 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, /* remove payload length from outer checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.udp->check, htonl(paylen)); + csum_replace_by_diff(&l4.udp->check, + (__force __wsum)htonl(paylen)); } /* reset pointers to inner headers */ @@ -2356,7 +2357,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, /* remove payload length from inner checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.tcp->check, htonl(paylen)); + csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); /* compute length of segmentation header */ *hdr_len = (l4.tcp->doff * 4) + l4_offset; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 7cd28ef6e714..c91fcf43ccbc 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1629,7 +1629,8 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, /* remove payload length from outer checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.udp->check, htonl(paylen)); + csum_replace_by_diff(&l4.udp->check, + (__force __wsum)htonl(paylen)); } /* reset pointers to inner headers */ @@ -1650,7 +1651,7 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, /* remove payload length from inner checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.tcp->check, htonl(paylen)); + csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); /* compute length of segmentation header */ *hdr_len = (l4.tcp->doff * 4) + l4_offset; From ee847d935156b041679ad82c269796dae1afaa6b Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 21 Dec 2016 18:04:47 -0500 Subject: [PATCH 12/13] i40e: remove duplicate device id from PCI table Signed-off-by: Carolyn Wyborny Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 199ef34e00f8..b0215c1159fe 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -77,7 +77,6 @@ static const struct pci_device_id i40e_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0}, - {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_X722), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0}, From 83a0c6e589017ce737720b9e05e2fa3fe4f7b860 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Thu, 12 Jan 2017 17:04:14 -0800 Subject: [PATCH 13/13] i40e: Invoke softirqs after napi_reschedule The following message is logged from time to time when using i40e: NOHZ: local_softirq_pending 08 i40e may schedule napi from a workqueue. Afterwards, softirqs are not run in a deterministic time frame. The problem is the same as what was described in commit ec13ee80145c ("virtio_net: invoke softirqs after __napi_schedule") and this patch applies the same fix to i40e. Signed-off-by: Benjamin Poirier Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b0215c1159fe..e8a8351c8ea9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4685,8 +4685,10 @@ static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi) */ if ((!tx_pending_hw) && i40e_get_tx_pending(tx_ring, true) && (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))) { + local_bh_disable(); if (napi_reschedule(&tx_ring->q_vector->napi)) tx_ring->tx_stats.tx_lost_interrupt++; + local_bh_enable(); } }