From ddf1d0d7715eff6cf8f04f68ca14efdbf18bf7e2 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 13 Feb 2014 03:48:39 -0800 Subject: [PATCH 01/15] i40e: spelling error Fix a spelling error, s/extention/extension/. Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index d4bb482b1a7f..19af4ce0a4fe 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -892,7 +892,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; - /* likely incorrect csum if alternate IP extention headers found */ + /* likely incorrect csum if alternate IP extension headers found */ if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) return; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index ffdb01d853db..3bb755893786 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -722,7 +722,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; - /* likely incorrect csum if alternate IP extention headers found */ + /* likely incorrect csum if alternate IP extension headers found */ if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) return; From 14ad37597b2038ad006674e5c7ab0248afe821d4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 13 Feb 2014 03:48:40 -0800 Subject: [PATCH 02/15] i40e: bump driver version Update the driver version to 0.3.31-k. Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- 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 b901371ca361..f596f74cae4a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -38,7 +38,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 30 +#define DRV_VERSION_BUILD 31 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN From af1a2a9c94d7b509ded794ef20b27f8fd36dee63 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 13 Feb 2014 03:48:41 -0800 Subject: [PATCH 03/15] i40evf: trivial fixes This change moves one operator up to the previous line and deletes the duplicate declaration of ETH_ALEN. Also update copyrights. Change-ID: I88de73093b584e0f3b29d481ccd83fc4b1a1afa5 Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 6 +++--- drivers/net/ethernet/intel/i40evf/i40e_type.h | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 3bb755893786..827bb5fa4af9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * Copyright(c) 2013 - 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -807,8 +807,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); - rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) - >> I40E_RXD_QW1_STATUS_SHIFT; + rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> + I40E_RXD_QW1_STATUS_SHIFT; while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) { union i40e_rx_desc *next_rxd; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 3bffac06592f..092aace2a76c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * Copyright(c) 2013 - 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -64,8 +64,6 @@ struct i40e_hw; typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); -#define ETH_ALEN 6 - /* Data type manipulation macros. */ #define I40E_DESC_UNUSED(R) \ From a63fa1cdb667609cd9f99435ecbbcda61861b38f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:42 -0800 Subject: [PATCH 04/15] i40evf: clean up memsets As politely pointed out by Dave Miller, calls to memset do not need a void pointer cast. Additionally, it is preferred to use sizeof(*the actual object) instead of sizeof(type). Change-ID: Id6a02429b7040111531f3865ea03fbe619167cb3 Signed-off-by: Mitch Williams Signed-off-by: Kevin Scott Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index a50e6b3479ae..ed3902bf249b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) desc_cb = *desc; cb_func(hw, &desc_cb); } - memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); - memset((void *)details, 0, - sizeof(struct i40e_asq_cmd_details)); + memset(desc, 0, sizeof(*desc)); + memset(details, 0, sizeof(*details)); ntc++; if (ntc == asq->count) ntc = 0; From e108b0e341ec835df19dd3433b883b0abc509ed8 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Thu, 13 Feb 2014 03:48:43 -0800 Subject: [PATCH 05/15] i40e: Setting i40e_down bit for tx_timeout If tx_timeout recovery failed, then it becomes necessary to set i40e_down bit before actually shutdown the connection. Change-ID: Iaac81df0e302116571827aa0cff450697fbb7fa3 Signed-off-by: Akeem G Abodunrin Signed-off-by: Jesse Brandeburg Tested-by: Kavindya Deegala Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index f596f74cae4a..8e444114bfc7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -305,6 +305,7 @@ static void i40e_tx_timeout(struct net_device *netdev) break; default: netdev_err(netdev, "tx_timeout recovery unsuccessful\n"); + set_bit(__I40E_DOWN, &vsi->state); i40e_down(vsi); break; } From fd1646ee3a311362d3315250b30ccc688b919aef Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:44 -0800 Subject: [PATCH 06/15] i40e: remove dead code This looks like a cut and paste error. The code makes no sense where it is, and accomplishes nothing. Since we've removed the goto, we can also get rid of the extraneous brackets. Change-ID: I9315e3eafeee0a5713c94b0dc57b58b60a849124 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index b9d1c1c8ca5a..299372b852ce 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -408,18 +408,10 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) "Could not allocate VF broadcast filter\n"); } - if (!f) { - dev_err(&pf->pdev->dev, "Unable to add ucast filter\n"); - ret = -ENOMEM; - goto error_alloc_vsi_res; - } - /* program mac filter */ ret = i40e_sync_vsi_filters(vsi); - if (ret) { + if (ret) dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); - goto error_alloc_vsi_res; - } error_alloc_vsi_res: return ret; From c17b362b6ffb720e570bb43fe28f2ac5e78a7ce8 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:45 -0800 Subject: [PATCH 07/15] i40e: set VF state to active when reset is complete Without this, the VF can never communicate with the PF after a VF reset. Change-ID: I8d10f1d0d0638d50d39f0aff263422e05d83ad83 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 299372b852ce..052be06b91aa 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 @@ complete_reset: mdelay(10); i40e_alloc_vf_res(vf); i40e_enable_vf_mappings(vf); + set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); From 69f64b2b77012e5e1d9ae25135e85aa7f469c397 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:46 -0800 Subject: [PATCH 08/15] i40e: reset VFs after PF reset Reset all of the VFs after a PF reset, so that they are in a known state, and the VF driver can detect the reset and reinit itself. Change-ID: I93c5b3a0f8b1371d0da078f92de948b9d3a6413f Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 8e444114bfc7..21d46f4bb214 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5332,6 +5332,11 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) /* restart the VSIs that were rebuilt and running before the reset */ i40e_pf_unquiesce_all_vsi(pf); + if (pf->num_alloc_vfs) { + for (v = 0; v < pf->num_alloc_vfs; v++) + i40e_reset_vf(&pf->vf[v], true); + } + /* tell the firmware that we're starting */ dv.major_version = DRV_VERSION_MAJOR; dv.minor_version = DRV_VERSION_MINOR; From 4aeec0106d503a0b88bf3852834c05228c073423 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:47 -0800 Subject: [PATCH 09/15] i40e: enable extant VFs If VFs are present when the driver loads, then set up some resources so they can function. Change-ID: I485916a811609a9990ce663d06dc645f625b07ff Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 ++++++++++ .../net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 18 ++++++++++-------- .../net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 21d46f4bb214..897452d72d71 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8076,6 +8076,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK; wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val); i40e_flush(hw); + + if (pci_num_vf(pdev)) { + dev_info(&pdev->dev, + "Active VFs found, allocating resources.\n"); + err = i40e_alloc_vfs(pf, pci_num_vf(pdev)); + if (err) + dev_info(&pdev->dev, + "Error %d allocating resources for existing VFs\n", + err); + } } pfs_found++; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 052be06b91aa..9074f63a2447 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -840,7 +840,7 @@ void i40e_free_vfs(struct i40e_pf *pf) * * allocate vf resources **/ -static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) +int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) { struct i40e_vf *vfs; int i, ret = 0; @@ -848,14 +848,16 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) /* Disable interrupt 0 so we don't try to handle the VFLR. */ i40e_irq_dynamic_disable_icr0(pf); - ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); - if (ret) { - dev_err(&pf->pdev->dev, - "pci_enable_sriov failed with error %d!\n", ret); - pf->num_alloc_vfs = 0; - goto err_iov; + /* Check to see if we're just allocating resources for extant VFs */ + if (pci_num_vf(pf->pdev) != num_alloc_vfs) { + ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); + if (ret) { + dev_err(&pf->pdev->dev, + "Failed to enable SR-IOV, error %d.\n", ret); + pf->num_alloc_vfs = 0; + goto err_iov; + } } - /* allocate memory */ vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL); if (!vfs) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index cc1feee36e12..bedf0ba21d74 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -102,6 +102,7 @@ struct i40e_vf { void i40e_free_vfs(struct i40e_pf *pf); int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs); +int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs); int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen); int i40e_vc_process_vflr_event(struct i40e_pf *pf); From eb2d80bcf6b3c101ffe728554ebb702db096917a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:48 -0800 Subject: [PATCH 10/15] i40e: don't handle VF reset on unload Set the DOWN flag before attempting to disable VFs when unloading the driver. Also, don't attempt to reset the VFs when the driver is unloading, because the switch configuration will fail. This fixes a panic on unload when VFs are enabled. Change-ID: I25a6567e89c9687145f510ff4f630932412c5c5d Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 +++++----- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 897452d72d71..628e917f5338 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8181,16 +8181,16 @@ static void i40e_remove(struct pci_dev *pdev) i40e_ptp_stop(pf); - if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { - i40e_free_vfs(pf); - pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; - } - /* no more scheduling of any task */ set_bit(__I40E_DOWN, &pf->state); del_timer_sync(&pf->service_timer); cancel_work_sync(&pf->service_task); + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + i40e_free_vfs(pf); + pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; + } + i40e_fdir_teardown(pf); /* If there is a switch structure or any orphans, remove them. diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 9074f63a2447..7d133faad4cf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1868,7 +1868,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) /* clear the bit in GLGEN_VFLRSTAT */ wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); - i40e_reset_vf(vf, true); + if (!test_bit(__I40E_DOWN, &pf->state)) + i40e_reset_vf(vf, true); } } From a377384a0429d1dcf8956b803329588edf477ade Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:49 -0800 Subject: [PATCH 11/15] i40evf: clean up adapter struct Remove a bunch of unused structure members that are just wasting space. Remove a completely unused info structure definition as well. Also update copyrights. Change-ID: I028ab92d9b7bd13a832cf3363bd1dc6610d8a535 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf.h | 29 +--------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index ff6529b288a1..05969b3a59e0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * Copyright(c) 2013 - 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -185,7 +185,6 @@ enum i40evf_critical_section_t { /* board specific private data structure */ struct i40evf_adapter { struct timer_list watchdog_timer; - struct vlan_group *vlgrp; struct work_struct reset_task; struct work_struct adminq_task; struct delayed_work init_task; @@ -193,38 +192,19 @@ struct i40evf_adapter { struct list_head vlan_filter_list; char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; - /* Interrupt Throttle Rate */ - u32 itr_setting; - u16 eitr_low; - u16 eitr_high; - /* TX */ struct i40e_ring *tx_rings[I40E_MAX_VSI_QP]; - u64 restart_queue; - u64 hw_csum_tx_good; - u64 lsc_int; - u64 hw_tso_ctxt; - u64 hw_tso6_ctxt; u32 tx_timeout_count; struct list_head mac_filter_list; -#ifdef DEBUG - bool detect_tx_hung; -#endif /* DEBUG */ /* RX */ struct i40e_ring *rx_rings[I40E_MAX_VSI_QP]; int txd_count; int rxd_count; u64 hw_csum_rx_error; - u64 hw_rx_no_dma_resources; - u64 hw_csum_rx_good; - u64 non_eop_descs; int num_msix_vectors; struct msix_entry *msix_entries; - u64 rx_hdr_split; - - u32 init_state; volatile unsigned long flags; #define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) #define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) @@ -261,11 +241,9 @@ struct i40evf_adapter { enum i40evf_state_t state; volatile unsigned long crit_section; - u64 tx_busy; struct work_struct watchdog_task; bool netdev_registered; - bool dev_closed; bool link_up; enum i40e_virtchnl_ops current_op; struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ @@ -276,11 +254,6 @@ struct i40evf_adapter { u32 aq_wait_count; }; -struct i40evf_info { - enum i40e_mac_type mac; - unsigned int flags; -}; - /* needed by i40evf_ethtool.c */ extern char i40evf_driver_name[]; From 708e8c247e43482f510a11c6720b0001a68b4404 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:50 -0800 Subject: [PATCH 12/15] i40evf: fix bogus comment Locate the structure in the correct header file. Change-ID: Ic7853131728812093a44a75d6b70953311a48dab Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 05969b3a59e0..37f5877df2a9 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -236,8 +236,7 @@ struct i40evf_adapter { struct pci_dev *pdev; struct net_device_stats net_stats; - /* structs defined in i40e_vf.h */ - struct i40e_hw hw; + struct i40e_hw hw; /* defined in i40e_type.h */ enum i40evf_state_t state; volatile unsigned long crit_section; From e1dfee8e64c2b30e123080e87c5528fae94f5440 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:51 -0800 Subject: [PATCH 13/15] i40evf: don't store unnecessary array of strings Since we store the traffic vector names in the queue vector struct, we don't need to maintain an array of strings for these names in the adapter structure. Replace this array with a single string and use it when allocating the misc irq vector. Also update copyrights. Change-ID: I664f096c3c008210d6a04a487163e8aa934fee5b Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 37f5877df2a9..696c9d125188 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -190,7 +190,7 @@ struct i40evf_adapter { struct delayed_work init_task; struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; struct list_head vlan_filter_list; - char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; + char misc_vector_name[IFNAMSIZ + 9]; /* TX */ struct i40e_ring *tx_rings[I40E_MAX_VSI_QP]; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f5caf4419243..d271d3a5ae28 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * Copyright(c) 2013 - 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -511,9 +511,10 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) struct net_device *netdev = adapter->netdev; int err; - sprintf(adapter->name[0], "i40evf:mbx"); + sprintf(adapter->misc_vector_name, "i40evf:mbx"); err = request_irq(adapter->msix_entries[0].vector, - &i40evf_msix_aq, 0, adapter->name[0], netdev); + &i40evf_msix_aq, 0, + adapter->misc_vector_name, netdev); if (err) { dev_err(&adapter->pdev->dev, "request_irq for msix_aq failed: %d\n", err); From e8106ebe2feb29b2790ba4ad4494b8f6a31126cc Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:52 -0800 Subject: [PATCH 14/15] i40evf: change type of flags variable As pointed out by Dan Carpenter (from Oracle), the flags variable is declared as a 64-bit long but all of the flags are defined as u32, which may lead to unintended consequences. Fix this by declaring flags as u32 (since we don't need any more than about a dozen flags right now), and remove the volatile qualifier, since it's unnecessary and just makes checkpatch cry. Change-ID: I137d3bb1842bf7e9456b5929ca54e3b0ed45dcab Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg CC: Dan Carpenter Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 696c9d125188..5e0a3440c064 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -205,7 +205,7 @@ struct i40evf_adapter { int num_msix_vectors; struct msix_entry *msix_entries; - volatile unsigned long flags; + u32 flags; #define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) #define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) #define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2) From ef8693eb90ae38704569ba0e114859799eee1fed Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 13 Feb 2014 03:48:53 -0800 Subject: [PATCH 15/15] i40evf: refactor reset handling Respond better to a VF reset event. When a reset is signaled by the PF, or detected by the watchdog task, prevent the watchdog from processing admin queue requests, and schedule the reset task. In the reset task, wait first for the reset to start, then for it to complete, then reinit the driver. If the reset never appears to complete after a long, long time (>10 seconds is possible depending on what's going on with the PF driver), then set a flag to indicate that PF communications have failed. If this flag is set, check for the reset to complete in the watchdog, and attempt to do a full reinitialization of the driver from scratch. With these changes the VF driver correctly handles a PF reset event while running on bare metal, or in a VM. Also update copyrights. Change-ID: I93513efd0b50523a8345e7f6a33a5e4f8a2a5996 Signed-off-by: Mitch Williams Signed-off-by: Jesse Brandeburg Tested-by: Sibai Li Signed-off-by: Aaron Brown Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/i40evf/i40evf.h | 6 +- .../net/ethernet/intel/i40evf/i40evf_main.c | 152 ++++++++++++++---- .../ethernet/intel/i40evf/i40evf_virtchnl.c | 15 +- 3 files changed, 132 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 5e0a3440c064..a30c4a9125a4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -164,15 +164,14 @@ struct i40evf_vlan_filter { /* Driver state. The order of these is important! */ enum i40evf_state_t { __I40EVF_STARTUP, /* driver loaded, probe complete */ - __I40EVF_FAILED, /* PF communication failed. Fatal. */ __I40EVF_REMOVE, /* driver is being unloaded */ __I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */ __I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */ __I40EVF_INIT_SW, /* got resources, setting up structs */ + __I40EVF_RESETTING, /* in reset */ /* Below here, watchdog is running */ __I40EVF_DOWN, /* ready, can be opened */ __I40EVF_TESTING, /* in ethtool self-test */ - __I40EVF_RESETTING, /* in reset */ __I40EVF_RUNNING, /* opened, working */ }; @@ -214,6 +213,8 @@ struct i40evf_adapter { #define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5) #define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6) #define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) +#define I40EVF_FLAG_PF_COMMS_FAILED (u32)(1 << 8) +#define I40EVF_FLAG_RESET_PENDING (u32)(1 << 9) /* duplcates for common code */ #define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0 @@ -231,6 +232,7 @@ struct i40evf_adapter { #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) #define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) #define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) + /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index d271d3a5ae28..fe2271e19423 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -964,16 +964,18 @@ void i40evf_down(struct i40evf_adapter *adapter) struct net_device *netdev = adapter->netdev; struct i40evf_mac_filter *f; - /* remove all MAC filters from the VSI */ + /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; } - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; - /* disable receives */ - adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; - mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); - msleep(20); - + if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && + adapter->state != __I40EVF_RESETTING) { + adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + /* disable receives */ + adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; + mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); + msleep(20); + } netif_tx_disable(netdev); netif_tx_stop_all_queues(netdev); @@ -1292,19 +1294,47 @@ static void i40evf_watchdog_task(struct work_struct *work) watchdog_task); struct i40e_hw *hw = &adapter->hw; - if (adapter->state < __I40EVF_DOWN) - goto watchdog_done; - if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) + goto restart_watchdog; + + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + dev_info(&adapter->pdev->dev, "Checking for redemption\n"); + if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) { + /* A chance for redemption! */ + dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); + adapter->state = __I40EVF_STARTUP; + adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; + schedule_delayed_work(&adapter->init_task, 10); + clear_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section); + /* Don't reschedule the watchdog, since we've restarted + * the init task. When init_task contacts the PF and + * gets everything set up again, it'll restart the + * watchdog for us. Down, boy. Sit. Stay. Woof. + */ + return; + } + adapter->aq_pending = 0; + adapter->aq_required = 0; + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; + goto watchdog_done; + } + + if ((adapter->state < __I40EVF_DOWN) || + (adapter->flags & I40EVF_FLAG_RESET_PENDING)) goto watchdog_done; - /* check for unannounced reset */ - if ((adapter->state != __I40EVF_RESETTING) && + /* check for reset */ + if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) { adapter->state = __I40EVF_RESETTING; + adapter->flags |= I40EVF_FLAG_RESET_PENDING; + dev_err(&adapter->pdev->dev, "Hardware reset detected.\n"); + dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); schedule_work(&adapter->reset_task); - dev_info(&adapter->pdev->dev, "%s: hardware reset detected\n", - __func__); + adapter->aq_pending = 0; + adapter->aq_required = 0; + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1359,13 +1389,15 @@ static void i40evf_watchdog_task(struct work_struct *work) i40evf_irq_enable(adapter, true); i40evf_fire_sw_int(adapter, 0xFF); + watchdog_done: + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); +restart_watchdog: if (adapter->aq_required) mod_timer(&adapter->watchdog_timer, jiffies + msecs_to_jiffies(20)); else mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2)); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); schedule_work(&adapter->adminq_task); } @@ -1412,6 +1444,8 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) i40e_flush(hw); } +#define I40EVF_RESET_WAIT_MS 100 +#define I40EVF_RESET_WAIT_COUNT 200 /** * i40evf_reset_task - Call-back task to handle hardware reset * @work: pointer to work_struct @@ -1422,8 +1456,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) **/ static void i40evf_reset_task(struct work_struct *work) { - struct i40evf_adapter *adapter = - container_of(work, struct i40evf_adapter, reset_task); + struct i40evf_adapter *adapter = container_of(work, + struct i40evf_adapter, + reset_task); struct i40e_hw *hw = &adapter->hw; int i = 0, err; uint32_t rstat_val; @@ -1431,22 +1466,56 @@ static void i40evf_reset_task(struct work_struct *work) while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) udelay(500); - - /* wait until the reset is complete */ - for (i = 0; i < 20; i++) { + /* poll until we see the reset actually happen */ + for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (rstat_val == I40E_VFR_COMPLETED) + if (rstat_val != I40E_VFR_VFACTIVE) { + dev_info(&adapter->pdev->dev, "Reset now occurring\n"); break; - else - mdelay(100); + } else { + msleep(I40EVF_RESET_WAIT_MS); + } } - if (i == 20) { + if (i == I40EVF_RESET_WAIT_COUNT) { + dev_err(&adapter->pdev->dev, "Reset was not detected\n"); + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + goto continue_reset; /* act like the reset happened */ + } + + /* wait until the reset is complete and the PF is responding to us */ + for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { + rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & + I40E_VFGEN_RSTAT_VFR_STATE_MASK; + if (rstat_val == I40E_VFR_VFACTIVE) { + dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n"); + break; + } else { + msleep(I40EVF_RESET_WAIT_MS); + } + } + if (i == I40EVF_RESET_WAIT_COUNT) { /* reset never finished */ - dev_info(&adapter->pdev->dev, "%s: reset never finished: %x\n", - __func__, rstat_val); - /* carry on anyway */ + dev_err(&adapter->pdev->dev, "Reset never finished (%x). PF driver is dead, and so am I.\n", + rstat_val); + adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; + + if (netif_running(adapter->netdev)) + i40evf_close(adapter->netdev); + + i40evf_free_misc_irq(adapter); + i40evf_reset_interrupt_capability(adapter); + i40evf_free_queues(adapter); + kfree(adapter->vf_res); + i40evf_shutdown_adminq(hw); + adapter->netdev->flags &= ~IFF_UP; + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + return; /* Do not attempt to reinit. It's dead, Jim. */ } + +continue_reset: + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + i40evf_down(adapter); adapter->state = __I40EVF_RESETTING; @@ -1506,6 +1575,9 @@ static void i40evf_adminq_task(struct work_struct *work) i40e_status ret; u16 pending; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + return; + event.msg_size = I40EVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL); if (!event.msg_buf) { @@ -1637,6 +1709,10 @@ static int i40evf_open(struct net_device *netdev) struct i40evf_adapter *adapter = netdev_priv(netdev); int err; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); + return -EIO; + } if (adapter->state != __I40EVF_DOWN) return -EBUSY; @@ -1691,8 +1767,12 @@ static int i40evf_close(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); + if (adapter->state <= __I40EVF_DOWN) + return 0; + /* signal that we are down to the interrupt handler */ adapter->state = __I40EVF_DOWN; + set_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_down(adapter); @@ -1843,6 +1923,8 @@ static void i40evf_init_task(struct work_struct *work) switch (adapter->state) { case __I40EVF_STARTUP: /* driver loaded, probe complete */ + adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; err = i40e_set_mac_type(hw); if (err) { dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n", @@ -2006,9 +2088,11 @@ static void i40evf_init_task(struct work_struct *work) adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC; adapter->vsi.netdev = adapter->netdev; - err = register_netdev(netdev); - if (err) - goto err_register; + if (!adapter->netdev_registered) { + err = register_netdev(netdev); + if (err) + goto err_register; + } adapter->netdev_registered = true; @@ -2032,17 +2116,16 @@ err_register: i40evf_free_misc_irq(adapter); err_sw_init: i40evf_reset_interrupt_capability(adapter); - adapter->state = __I40EVF_FAILED; err_alloc: kfree(adapter->vf_res); adapter->vf_res = NULL; err: + if (hw->aq.asq.count) + i40evf_shutdown_adminq(hw); /* ignore error */ /* Things went into the weeds, so try again later */ if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) { dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n"); - if (hw->aq.asq.count) - i40evf_shutdown_adminq(hw); /* ignore error */ - adapter->state = __I40EVF_FAILED; + adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; return; /* do not reschedule */ } schedule_delayed_work(&adapter->init_task, HZ * 3); @@ -2272,6 +2355,7 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40e_hw *hw = &adapter->hw; cancel_delayed_work_sync(&adapter->init_task); + cancel_work_sync(&adapter->reset_task); if (adapter->netdev_registered) { unregister_netdev(netdev); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index e6978d79e62b..93891a114d3f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * Copyright(c) 2013 - 2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -43,6 +43,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, struct i40e_hw *hw = &adapter->hw; i40e_status err; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + return 0; /* nothing to see here, move along */ + err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); if (err) dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", @@ -689,10 +692,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } break; case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: - adapter->state = __I40EVF_RESETTING; - schedule_work(&adapter->reset_task); - dev_info(&adapter->pdev->dev, - "%s: hardware reset pending\n", __func__); + dev_info(&adapter->pdev->dev, "PF reset warning received\n"); + if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { + adapter->flags |= I40EVF_FLAG_RESET_PENDING; + dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); + schedule_work(&adapter->reset_task); + } break; default: dev_err(&adapter->pdev->dev,