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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0e42aa4fb0
@ -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;
|
||||
|
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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 */
|
||||
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;
|
||||
@ -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;
|
||||
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++;
|
||||
@ -8165,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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
@ -682,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);
|
||||
@ -847,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;
|
||||
@ -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. */
|
||||
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) {
|
||||
@ -1873,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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,
|
||||
@ -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 */
|
||||
};
|
||||
|
||||
@ -185,47 +184,27 @@ 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;
|
||||
struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
|
||||
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;
|
||||
char misc_vector_name[IFNAMSIZ + 9];
|
||||
|
||||
/* 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;
|
||||
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)
|
||||
@ -234,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
|
||||
@ -251,21 +232,19 @@ 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;
|
||||
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;
|
||||
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 +255,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[];
|
||||
|
@ -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);
|
||||
@ -963,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);
|
||||
@ -1291,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;
|
||||
}
|
||||
|
||||
@ -1358,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);
|
||||
}
|
||||
|
||||
@ -1411,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
|
||||
@ -1421,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;
|
||||
@ -1430,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;
|
||||
|
||||
@ -1505,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) {
|
||||
@ -1636,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;
|
||||
|
||||
@ -1690,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);
|
||||
@ -1842,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",
|
||||
@ -2005,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;
|
||||
|
||||
@ -2031,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);
|
||||
@ -2271,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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user