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)
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 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
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);
......
/*******************************************************************************
*
* 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;
......
/*******************************************************************************
*
* 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) \
......
/*******************************************************************************
*
* 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[];
......
/*******************************************************************************
*
* 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)
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 (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;
/* 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);
/* 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 */
for (i = 0; i < 20; i++) {
/* 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_COMPLETED)
if (rstat_val == I40E_VFR_VFACTIVE) {
dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n");
break;
else
mdelay(100);
} else {
msleep(I40EVF_RESET_WAIT_MS);
}
}
if (i == 20) {
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 @@ static void i40evf_init_task(struct work_struct *work)
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);
......
/*******************************************************************************
*
* 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,
......
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