Commit 0e42aa4f authored by David S. Miller's avatar David S. Miller

Merge branch 'i40e'

Aaron Brown says:

====================
Intel Wired LAN Driver Updates

This series contains updates to i40e and i40evf, primarily reset
handling / refactoring along with a fair amount of minor cleanup.

Jesse fixes some spelling, bumps the version and other trivial fixes.
Akeem sets a bit that is needed before shutdown in the case of
tx_timeout recovery failure.  Mitch refactors reset handling along
with a whole bunch of clean up.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8815cbd9 ef8693eb
...@@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) ...@@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
desc_cb = *desc; desc_cb = *desc;
cb_func(hw, &desc_cb); cb_func(hw, &desc_cb);
} }
memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); memset(desc, 0, sizeof(*desc));
memset((void *)details, 0, memset(details, 0, sizeof(*details));
sizeof(struct i40e_asq_cmd_details));
ntc++; ntc++;
if (ntc == asq->count) if (ntc == asq->count)
ntc = 0; ntc = 0;
......
...@@ -38,7 +38,7 @@ static const char i40e_driver_string[] = ...@@ -38,7 +38,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MAJOR 0
#define DRV_VERSION_MINOR 3 #define DRV_VERSION_MINOR 3
#define DRV_VERSION_BUILD 30 #define DRV_VERSION_BUILD 31
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN __stringify(DRV_VERSION_BUILD) DRV_KERN
...@@ -305,6 +305,7 @@ static void i40e_tx_timeout(struct net_device *netdev) ...@@ -305,6 +305,7 @@ static void i40e_tx_timeout(struct net_device *netdev)
break; break;
default: default:
netdev_err(netdev, "tx_timeout recovery unsuccessful\n"); netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
set_bit(__I40E_DOWN, &vsi->state);
i40e_down(vsi); i40e_down(vsi);
break; break;
} }
...@@ -5331,6 +5332,11 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) ...@@ -5331,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 */ /* restart the VSIs that were rebuilt and running before the reset */
i40e_pf_unquiesce_all_vsi(pf); 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 */ /* tell the firmware that we're starting */
dv.major_version = DRV_VERSION_MAJOR; dv.major_version = DRV_VERSION_MAJOR;
dv.minor_version = DRV_VERSION_MINOR; dv.minor_version = DRV_VERSION_MINOR;
...@@ -8070,6 +8076,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -8070,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; val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val); wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
i40e_flush(hw); 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++; pfs_found++;
...@@ -8165,16 +8181,16 @@ static void i40e_remove(struct pci_dev *pdev) ...@@ -8165,16 +8181,16 @@ static void i40e_remove(struct pci_dev *pdev)
i40e_ptp_stop(pf); 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 */ /* no more scheduling of any task */
set_bit(__I40E_DOWN, &pf->state); set_bit(__I40E_DOWN, &pf->state);
del_timer_sync(&pf->service_timer); del_timer_sync(&pf->service_timer);
cancel_work_sync(&pf->service_task); 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); i40e_fdir_teardown(pf);
/* If there is a switch structure or any orphans, remove them. /* If there is a switch structure or any orphans, remove them.
......
...@@ -892,7 +892,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -892,7 +892,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return; 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)) if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
return; return;
......
...@@ -408,18 +408,10 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) ...@@ -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"); "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 */ /* program mac filter */
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi);
if (ret) { if (ret)
dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
goto error_alloc_vsi_res;
}
error_alloc_vsi_res: error_alloc_vsi_res:
return ret; return ret;
...@@ -682,6 +674,7 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) ...@@ -682,6 +674,7 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
mdelay(10); mdelay(10);
i40e_alloc_vf_res(vf); i40e_alloc_vf_res(vf);
i40e_enable_vf_mappings(vf); i40e_enable_vf_mappings(vf);
set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
/* tell the VF the reset is done */ /* tell the VF the reset is done */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
...@@ -847,7 +840,7 @@ void i40e_free_vfs(struct i40e_pf *pf) ...@@ -847,7 +840,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
* *
* allocate vf resources * 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; struct i40e_vf *vfs;
int i, ret = 0; int i, ret = 0;
...@@ -855,14 +848,16 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) ...@@ -855,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. */ /* Disable interrupt 0 so we don't try to handle the VFLR. */
i40e_irq_dynamic_disable_icr0(pf); i40e_irq_dynamic_disable_icr0(pf);
ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); /* Check to see if we're just allocating resources for extant VFs */
if (ret) { if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
dev_err(&pf->pdev->dev, ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
"pci_enable_sriov failed with error %d!\n", ret); if (ret) {
pf->num_alloc_vfs = 0; dev_err(&pf->pdev->dev,
goto err_iov; "Failed to enable SR-IOV, error %d.\n", ret);
pf->num_alloc_vfs = 0;
goto err_iov;
}
} }
/* allocate memory */ /* allocate memory */
vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL); vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL);
if (!vfs) { if (!vfs) {
...@@ -1873,7 +1868,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) ...@@ -1873,7 +1868,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
/* clear the bit in GLGEN_VFLRSTAT */ /* clear the bit in GLGEN_VFLRSTAT */
wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); 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);
} }
} }
......
...@@ -102,6 +102,7 @@ struct i40e_vf { ...@@ -102,6 +102,7 @@ struct i40e_vf {
void i40e_free_vfs(struct i40e_pf *pf); void i40e_free_vfs(struct i40e_pf *pf);
int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs); 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, int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
u32 v_retval, u8 *msg, u16 msglen); u32 v_retval, u8 *msg, u16 msglen);
int i40e_vc_process_vflr_event(struct i40e_pf *pf); int i40e_vc_process_vflr_event(struct i40e_pf *pf);
......
/******************************************************************************* /*******************************************************************************
* *
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -722,7 +722,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ...@@ -722,7 +722,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
return; 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)) if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
return; return;
...@@ -807,8 +807,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) ...@@ -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); rx_desc = I40E_RX_DESC(rx_ring, i);
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
>> I40E_RXD_QW1_STATUS_SHIFT; I40E_RXD_QW1_STATUS_SHIFT;
while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) { while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
union i40e_rx_desc *next_rxd; union i40e_rx_desc *next_rxd;
......
/******************************************************************************* /*******************************************************************************
* *
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -64,8 +64,6 @@ ...@@ -64,8 +64,6 @@
struct i40e_hw; struct i40e_hw;
typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
#define ETH_ALEN 6
/* Data type manipulation macros. */ /* Data type manipulation macros. */
#define I40E_DESC_UNUSED(R) \ #define I40E_DESC_UNUSED(R) \
......
/******************************************************************************* /*******************************************************************************
* *
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -164,15 +164,14 @@ struct i40evf_vlan_filter { ...@@ -164,15 +164,14 @@ struct i40evf_vlan_filter {
/* Driver state. The order of these is important! */ /* Driver state. The order of these is important! */
enum i40evf_state_t { enum i40evf_state_t {
__I40EVF_STARTUP, /* driver loaded, probe complete */ __I40EVF_STARTUP, /* driver loaded, probe complete */
__I40EVF_FAILED, /* PF communication failed. Fatal. */
__I40EVF_REMOVE, /* driver is being unloaded */ __I40EVF_REMOVE, /* driver is being unloaded */
__I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */ __I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */
__I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */ __I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */
__I40EVF_INIT_SW, /* got resources, setting up structs */ __I40EVF_INIT_SW, /* got resources, setting up structs */
__I40EVF_RESETTING, /* in reset */
/* Below here, watchdog is running */ /* Below here, watchdog is running */
__I40EVF_DOWN, /* ready, can be opened */ __I40EVF_DOWN, /* ready, can be opened */
__I40EVF_TESTING, /* in ethtool self-test */ __I40EVF_TESTING, /* in ethtool self-test */
__I40EVF_RESETTING, /* in reset */
__I40EVF_RUNNING, /* opened, working */ __I40EVF_RUNNING, /* opened, working */
}; };
...@@ -185,47 +184,27 @@ enum i40evf_critical_section_t { ...@@ -185,47 +184,27 @@ enum i40evf_critical_section_t {
/* board specific private data structure */ /* board specific private data structure */
struct i40evf_adapter { struct i40evf_adapter {
struct timer_list watchdog_timer; struct timer_list watchdog_timer;
struct vlan_group *vlgrp;
struct work_struct reset_task; struct work_struct reset_task;
struct work_struct adminq_task; struct work_struct adminq_task;
struct delayed_work init_task; struct delayed_work init_task;
struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
struct list_head vlan_filter_list; struct list_head vlan_filter_list;
char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; char misc_vector_name[IFNAMSIZ + 9];
/* Interrupt Throttle Rate */
u32 itr_setting;
u16 eitr_low;
u16 eitr_high;
/* TX */ /* TX */
struct i40e_ring *tx_rings[I40E_MAX_VSI_QP]; 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; u32 tx_timeout_count;
struct list_head mac_filter_list; struct list_head mac_filter_list;
#ifdef DEBUG
bool detect_tx_hung;
#endif /* DEBUG */
/* RX */ /* RX */
struct i40e_ring *rx_rings[I40E_MAX_VSI_QP]; struct i40e_ring *rx_rings[I40E_MAX_VSI_QP];
int txd_count; int txd_count;
int rxd_count; int rxd_count;
u64 hw_csum_rx_error; u64 hw_csum_rx_error;
u64 hw_rx_no_dma_resources;
u64 hw_csum_rx_good;
u64 non_eop_descs;
int num_msix_vectors; int num_msix_vectors;
struct msix_entry *msix_entries; struct msix_entry *msix_entries;
u64 rx_hdr_split; u32 flags;
u32 init_state;
volatile unsigned long flags;
#define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) #define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1)
#define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) #define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1)
#define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2) #define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2)
...@@ -234,6 +213,8 @@ struct i40evf_adapter { ...@@ -234,6 +213,8 @@ struct i40evf_adapter {
#define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5) #define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5)
#define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6) #define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6)
#define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) #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 */ /* duplcates for common code */
#define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_FDIR_ATR_ENABLED 0
#define I40E_FLAG_DCB_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0
...@@ -251,21 +232,19 @@ struct i40evf_adapter { ...@@ -251,21 +232,19 @@ struct i40evf_adapter {
#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6)
#define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) #define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7)
#define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) #define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8)
/* OS defined structs */ /* OS defined structs */
struct net_device *netdev; struct net_device *netdev;
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device_stats net_stats; struct net_device_stats net_stats;
/* structs defined in i40e_vf.h */ struct i40e_hw hw; /* defined in i40e_type.h */
struct i40e_hw hw;
enum i40evf_state_t state; enum i40evf_state_t state;
volatile unsigned long crit_section; volatile unsigned long crit_section;
u64 tx_busy;
struct work_struct watchdog_task; struct work_struct watchdog_task;
bool netdev_registered; bool netdev_registered;
bool dev_closed;
bool link_up; bool link_up;
enum i40e_virtchnl_ops current_op; enum i40e_virtchnl_ops current_op;
struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */
...@@ -276,11 +255,6 @@ struct i40evf_adapter { ...@@ -276,11 +255,6 @@ struct i40evf_adapter {
u32 aq_wait_count; u32 aq_wait_count;
}; };
struct i40evf_info {
enum i40e_mac_type mac;
unsigned int flags;
};
/* needed by i40evf_ethtool.c */ /* needed by i40evf_ethtool.c */
extern char i40evf_driver_name[]; extern char i40evf_driver_name[];
......
/******************************************************************************* /*******************************************************************************
* *
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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) ...@@ -511,9 +511,10 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
int err; int err;
sprintf(adapter->name[0], "i40evf:mbx"); sprintf(adapter->misc_vector_name, "i40evf:mbx");
err = request_irq(adapter->msix_entries[0].vector, 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) { if (err) {
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
"request_irq for msix_aq failed: %d\n", err); "request_irq for msix_aq failed: %d\n", err);
...@@ -963,16 +964,18 @@ void i40evf_down(struct i40evf_adapter *adapter) ...@@ -963,16 +964,18 @@ void i40evf_down(struct i40evf_adapter *adapter)
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
struct i40evf_mac_filter *f; 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) { list_for_each_entry(f, &adapter->mac_filter_list, list) {
f->remove = true; f->remove = true;
} }
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
/* disable receives */ adapter->state != __I40EVF_RESETTING) {
adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); /* disable receives */
msleep(20); adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
msleep(20);
}
netif_tx_disable(netdev); netif_tx_disable(netdev);
netif_tx_stop_all_queues(netdev); netif_tx_stop_all_queues(netdev);
...@@ -1291,19 +1294,47 @@ static void i40evf_watchdog_task(struct work_struct *work) ...@@ -1291,19 +1294,47 @@ static void i40evf_watchdog_task(struct work_struct *work)
watchdog_task); watchdog_task);
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
if (adapter->state < __I40EVF_DOWN) 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; goto watchdog_done;
}
if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) if ((adapter->state < __I40EVF_DOWN) ||
(adapter->flags & I40EVF_FLAG_RESET_PENDING))
goto watchdog_done; goto watchdog_done;
/* check for unannounced reset */ /* check for reset */
if ((adapter->state != __I40EVF_RESETTING) && if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) &&
(rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) { (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) {
adapter->state = __I40EVF_RESETTING; 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); schedule_work(&adapter->reset_task);
dev_info(&adapter->pdev->dev, "%s: hardware reset detected\n", adapter->aq_pending = 0;
__func__); adapter->aq_required = 0;
adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
goto watchdog_done; goto watchdog_done;
} }
...@@ -1358,13 +1389,15 @@ static void i40evf_watchdog_task(struct work_struct *work) ...@@ -1358,13 +1389,15 @@ static void i40evf_watchdog_task(struct work_struct *work)
i40evf_irq_enable(adapter, true); i40evf_irq_enable(adapter, true);
i40evf_fire_sw_int(adapter, 0xFF); i40evf_fire_sw_int(adapter, 0xFF);
watchdog_done: watchdog_done:
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
restart_watchdog:
if (adapter->aq_required) if (adapter->aq_required)
mod_timer(&adapter->watchdog_timer, mod_timer(&adapter->watchdog_timer,
jiffies + msecs_to_jiffies(20)); jiffies + msecs_to_jiffies(20));
else else
mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2)); mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2));
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
schedule_work(&adapter->adminq_task); schedule_work(&adapter->adminq_task);
} }
...@@ -1411,6 +1444,8 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) ...@@ -1411,6 +1444,8 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
i40e_flush(hw); 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 * i40evf_reset_task - Call-back task to handle hardware reset
* @work: pointer to work_struct * @work: pointer to work_struct
...@@ -1421,8 +1456,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) ...@@ -1421,8 +1456,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
**/ **/
static void i40evf_reset_task(struct work_struct *work) static void i40evf_reset_task(struct work_struct *work)
{ {
struct i40evf_adapter *adapter = struct i40evf_adapter *adapter = container_of(work,
container_of(work, struct i40evf_adapter, reset_task); struct i40evf_adapter,
reset_task);
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
int i = 0, err; int i = 0, err;
uint32_t rstat_val; uint32_t rstat_val;
...@@ -1430,22 +1466,56 @@ static void i40evf_reset_task(struct work_struct *work) ...@@ -1430,22 +1466,56 @@ static void i40evf_reset_task(struct work_struct *work)
while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
&adapter->crit_section)) &adapter->crit_section))
udelay(500); udelay(500);
/* 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_VFACTIVE) {
dev_info(&adapter->pdev->dev, "Reset now occurring\n");
break;
} else {
msleep(I40EVF_RESET_WAIT_MS);
}
}
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 */ /* wait until the reset is complete and the PF is responding to us */
for (i = 0; i < 20; i++) { for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
I40E_VFGEN_RSTAT_VFR_STATE_MASK; I40E_VFGEN_RSTAT_VFR_STATE_MASK;
if (rstat_val == I40E_VFR_COMPLETED) if (rstat_val == I40E_VFR_VFACTIVE) {
dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n");
break; break;
else } else {
mdelay(100); msleep(I40EVF_RESET_WAIT_MS);
}
} }
if (i == 20) { if (i == I40EVF_RESET_WAIT_COUNT) {
/* reset never finished */ /* reset never finished */
dev_info(&adapter->pdev->dev, "%s: reset never finished: %x\n", dev_err(&adapter->pdev->dev, "Reset never finished (%x). PF driver is dead, and so am I.\n",
__func__, rstat_val); rstat_val);
/* carry on anyway */ 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); i40evf_down(adapter);
adapter->state = __I40EVF_RESETTING; adapter->state = __I40EVF_RESETTING;
...@@ -1505,6 +1575,9 @@ static void i40evf_adminq_task(struct work_struct *work) ...@@ -1505,6 +1575,9 @@ static void i40evf_adminq_task(struct work_struct *work)
i40e_status ret; i40e_status ret;
u16 pending; u16 pending;
if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
return;
event.msg_size = I40EVF_MAX_AQ_BUF_SIZE; event.msg_size = I40EVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL); event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL);
if (!event.msg_buf) { if (!event.msg_buf) {
...@@ -1636,6 +1709,10 @@ static int i40evf_open(struct net_device *netdev) ...@@ -1636,6 +1709,10 @@ static int i40evf_open(struct net_device *netdev)
struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_adapter *adapter = netdev_priv(netdev);
int err; 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) if (adapter->state != __I40EVF_DOWN)
return -EBUSY; return -EBUSY;
...@@ -1690,8 +1767,12 @@ static int i40evf_close(struct net_device *netdev) ...@@ -1690,8 +1767,12 @@ static int i40evf_close(struct net_device *netdev)
{ {
struct i40evf_adapter *adapter = netdev_priv(netdev); struct i40evf_adapter *adapter = netdev_priv(netdev);
if (adapter->state <= __I40EVF_DOWN)
return 0;
/* signal that we are down to the interrupt handler */ /* signal that we are down to the interrupt handler */
adapter->state = __I40EVF_DOWN; adapter->state = __I40EVF_DOWN;
set_bit(__I40E_DOWN, &adapter->vsi.state); set_bit(__I40E_DOWN, &adapter->vsi.state);
i40evf_down(adapter); i40evf_down(adapter);
...@@ -1842,6 +1923,8 @@ static void i40evf_init_task(struct work_struct *work) ...@@ -1842,6 +1923,8 @@ static void i40evf_init_task(struct work_struct *work)
switch (adapter->state) { switch (adapter->state) {
case __I40EVF_STARTUP: case __I40EVF_STARTUP:
/* driver loaded, probe complete */ /* driver loaded, probe complete */
adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
err = i40e_set_mac_type(hw); err = i40e_set_mac_type(hw);
if (err) { if (err) {
dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n", dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n",
...@@ -2005,9 +2088,11 @@ static void i40evf_init_task(struct work_struct *work) ...@@ -2005,9 +2088,11 @@ static void i40evf_init_task(struct work_struct *work)
adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC; adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC;
adapter->vsi.netdev = adapter->netdev; adapter->vsi.netdev = adapter->netdev;
err = register_netdev(netdev); if (!adapter->netdev_registered) {
if (err) err = register_netdev(netdev);
goto err_register; if (err)
goto err_register;
}
adapter->netdev_registered = true; adapter->netdev_registered = true;
...@@ -2031,17 +2116,16 @@ static void i40evf_init_task(struct work_struct *work) ...@@ -2031,17 +2116,16 @@ static void i40evf_init_task(struct work_struct *work)
i40evf_free_misc_irq(adapter); i40evf_free_misc_irq(adapter);
err_sw_init: err_sw_init:
i40evf_reset_interrupt_capability(adapter); i40evf_reset_interrupt_capability(adapter);
adapter->state = __I40EVF_FAILED;
err_alloc: err_alloc:
kfree(adapter->vf_res); kfree(adapter->vf_res);
adapter->vf_res = NULL; adapter->vf_res = NULL;
err: err:
if (hw->aq.asq.count)
i40evf_shutdown_adminq(hw); /* ignore error */
/* Things went into the weeds, so try again later */ /* Things went into the weeds, so try again later */
if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) { if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) {
dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n"); dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n");
if (hw->aq.asq.count) adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
i40evf_shutdown_adminq(hw); /* ignore error */
adapter->state = __I40EVF_FAILED;
return; /* do not reschedule */ return; /* do not reschedule */
} }
schedule_delayed_work(&adapter->init_task, HZ * 3); schedule_delayed_work(&adapter->init_task, HZ * 3);
...@@ -2271,6 +2355,7 @@ static void i40evf_remove(struct pci_dev *pdev) ...@@ -2271,6 +2355,7 @@ static void i40evf_remove(struct pci_dev *pdev)
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
cancel_delayed_work_sync(&adapter->init_task); cancel_delayed_work_sync(&adapter->init_task);
cancel_work_sync(&adapter->reset_task);
if (adapter->netdev_registered) { if (adapter->netdev_registered) {
unregister_netdev(netdev); unregister_netdev(netdev);
......
/******************************************************************************* /*******************************************************************************
* *
* Intel Ethernet Controller XL710 Family Linux Virtual Function Driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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, ...@@ -43,6 +43,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter,
struct i40e_hw *hw = &adapter->hw; struct i40e_hw *hw = &adapter->hw;
i40e_status err; 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); err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
if (err) if (err)
dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", 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, ...@@ -689,10 +692,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
} }
break; break;
case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
adapter->state = __I40EVF_RESETTING; dev_info(&adapter->pdev->dev, "PF reset warning received\n");
schedule_work(&adapter->reset_task); if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
dev_info(&adapter->pdev->dev, adapter->flags |= I40EVF_FLAG_RESET_PENDING;
"%s: hardware reset pending\n", __func__); dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
schedule_work(&adapter->reset_task);
}
break; break;
default: default:
dev_err(&adapter->pdev->dev, dev_err(&adapter->pdev->dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment