summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/i40evf/i40evf_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c')
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c86
1 files changed, 69 insertions, 17 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index 7fc5f3b5d6bf..ab15f4d07e41 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -34,9 +34,9 @@ static int i40evf_close(struct net_device *netdev);
char i40evf_driver_name[] = "i40evf";
static const char i40evf_driver_string[] =
- "Intel(R) XL710 X710 Virtual Function Network Driver";
+ "Intel(R) XL710/X710 Virtual Function Network Driver";
-#define DRV_VERSION "0.9.34"
+#define DRV_VERSION "0.9.40"
const char i40evf_driver_version[] = DRV_VERSION;
static const char i40evf_copyright[] =
"Copyright (c) 2013 - 2014 Intel Corporation.";
@@ -260,6 +260,12 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter,
int i;
uint32_t dyn_ctl;
+ if (mask & 1) {
+ dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01);
+ dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK |
+ I40E_VFINT_DYN_CTLN_CLEARPBA_MASK;
+ wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl);
+ }
for (i = 1; i < adapter->num_msix_vectors; i++) {
if (mask & (1 << i)) {
dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1));
@@ -278,6 +284,7 @@ void i40evf_irq_enable(struct i40evf_adapter *adapter, bool flush)
{
struct i40e_hw *hw = &adapter->hw;
+ i40evf_misc_irq_enable(adapter);
i40evf_irq_enable_queues(adapter, ~0);
if (flush)
@@ -520,7 +527,8 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int err;
- sprintf(adapter->misc_vector_name, "i40evf:mbx");
+ snprintf(adapter->misc_vector_name,
+ sizeof(adapter->misc_vector_name) - 1, "i40evf:mbx");
err = request_irq(adapter->msix_entries[0].vector,
&i40evf_msix_aq, 0,
adapter->misc_vector_name, netdev);
@@ -761,7 +769,7 @@ i40evf_mac_filter *i40evf_add_filter(struct i40evf_adapter *adapter,
while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
&adapter->crit_section))
- mdelay(1);
+ udelay(1);
f = i40evf_find_filter(adapter, macaddr);
if (NULL == f) {
@@ -833,7 +841,7 @@ static void i40evf_set_rx_mode(struct net_device *netdev)
while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
&adapter->crit_section))
- mdelay(1);
+ udelay(1);
/* remove filter if not in netdev list */
list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
bool found = false;
@@ -1290,12 +1298,16 @@ static void i40evf_watchdog_task(struct work_struct *work)
struct i40evf_adapter,
watchdog_task);
struct i40e_hw *hw = &adapter->hw;
+ uint32_t rstat_val;
if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
goto restart_watchdog;
if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
- if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) {
+ rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
+ I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ if ((rstat_val == I40E_VFR_VFACTIVE) ||
+ (rstat_val == I40E_VFR_COMPLETED)) {
/* A chance for redemption! */
dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
adapter->state = __I40EVF_STARTUP;
@@ -1321,8 +1333,11 @@ static void i40evf_watchdog_task(struct work_struct *work)
goto watchdog_done;
/* check for reset */
+ rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
+ I40E_VFGEN_RSTAT_VFR_STATE_MASK;
if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) &&
- (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) {
+ (rstat_val != I40E_VFR_VFACTIVE) &&
+ (rstat_val != I40E_VFR_COMPLETED)) {
adapter->state = __I40EVF_RESETTING;
adapter->flags |= I40EVF_FLAG_RESET_PENDING;
dev_err(&adapter->pdev->dev, "Hardware reset detected\n");
@@ -1388,6 +1403,8 @@ static void i40evf_watchdog_task(struct work_struct *work)
watchdog_done:
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
restart_watchdog:
+ if (adapter->state == __I40EVF_REMOVE)
+ return;
if (adapter->aq_required)
mod_timer(&adapter->watchdog_timer,
jiffies + msecs_to_jiffies(20));
@@ -1488,7 +1505,8 @@ static void i40evf_reset_task(struct work_struct *work)
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)
+ if ((rstat_val != I40E_VFR_VFACTIVE) &&
+ (rstat_val != I40E_VFR_COMPLETED))
break;
else
msleep(I40EVF_RESET_WAIT_MS);
@@ -1502,12 +1520,16 @@ static void i40evf_reset_task(struct work_struct *work)
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)
+ if ((rstat_val == I40E_VFR_VFACTIVE) ||
+ (rstat_val == I40E_VFR_COMPLETED))
break;
else
msleep(I40EVF_RESET_WAIT_MS);
}
if (i == I40EVF_RESET_WAIT_COUNT) {
+ struct i40evf_mac_filter *f, *ftmp;
+ struct i40evf_vlan_filter *fv, *fvtmp;
+
/* reset never finished */
dev_err(&adapter->pdev->dev, "Reset never finished (%x)\n",
rstat_val);
@@ -1520,9 +1542,23 @@ static void i40evf_reset_task(struct work_struct *work)
i40evf_free_all_tx_resources(adapter);
i40evf_free_all_rx_resources(adapter);
}
+
+ /* Delete all of the filters, both MAC and VLAN. */
+ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list,
+ list) {
+ list_del(&f->list);
+ kfree(f);
+ }
+ list_for_each_entry_safe(fv, fvtmp, &adapter->vlan_filter_list,
+ list) {
+ list_del(&fv->list);
+ kfree(fv);
+ }
+
i40evf_free_misc_irq(adapter);
i40evf_reset_interrupt_capability(adapter);
i40evf_free_queues(adapter);
+ i40evf_free_q_vectors(adapter);
kfree(adapter->vf_res);
i40evf_shutdown_adminq(hw);
adapter->netdev->flags &= ~IFF_UP;
@@ -1939,8 +1975,10 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw)
int i;
for (i = 0; i < 100; i++) {
- rstat = rd32(hw, I40E_VFGEN_RSTAT);
- if (rstat == I40E_VFR_VFACTIVE)
+ rstat = rd32(hw, I40E_VFGEN_RSTAT) &
+ I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+ if ((rstat == I40E_VFR_VFACTIVE) ||
+ (rstat == I40E_VFR_COMPLETED))
return 0;
udelay(10);
}
@@ -2006,7 +2044,6 @@ static void i40evf_init_task(struct work_struct *work)
}
adapter->state = __I40EVF_INIT_VERSION_CHECK;
goto restart;
- break;
case __I40EVF_INIT_VERSION_CHECK:
if (!i40evf_asq_done(hw)) {
dev_err(&pdev->dev, "Admin queue command never completed\n");
@@ -2018,17 +2055,20 @@ static void i40evf_init_task(struct work_struct *work)
if (err) {
dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n",
err);
+ if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
+ dev_info(&pdev->dev, "Resending request\n");
+ err = i40evf_send_api_ver(adapter);
+ }
goto err;
}
err = i40evf_send_vf_config_msg(adapter);
if (err) {
- dev_err(&pdev->dev, "Unable send config request (%d)\n",
+ dev_err(&pdev->dev, "Unable to send config request (%d)\n",
err);
goto err;
}
adapter->state = __I40EVF_INIT_GET_RESOURCES;
goto restart;
- break;
case __I40EVF_INIT_GET_RESOURCES:
/* aq msg sent, awaiting reply */
if (!adapter->vf_res) {
@@ -2097,8 +2137,6 @@ static void i40evf_init_task(struct work_struct *work)
ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr);
ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
- INIT_LIST_HEAD(&adapter->mac_filter_list);
- INIT_LIST_HEAD(&adapter->vlan_filter_list);
f = kzalloc(sizeof(*f), GFP_ATOMIC);
if (NULL == f)
goto err_sw_init;
@@ -2280,6 +2318,9 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->bus.device = PCI_SLOT(pdev->devfn);
hw->bus.func = PCI_FUNC(pdev->devfn);
+ INIT_LIST_HEAD(&adapter->mac_filter_list);
+ INIT_LIST_HEAD(&adapter->vlan_filter_list);
+
INIT_WORK(&adapter->reset_task, i40evf_reset_task);
INIT_WORK(&adapter->adminq_task, i40evf_adminq_task);
INIT_WORK(&adapter->watchdog_task, i40evf_watchdog_task);
@@ -2391,6 +2432,7 @@ static void i40evf_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct i40evf_adapter *adapter = netdev_priv(netdev);
+ struct i40evf_mac_filter *f, *ftmp;
struct i40e_hw *hw = &adapter->hw;
cancel_delayed_work_sync(&adapter->init_task);
@@ -2406,9 +2448,12 @@ static void i40evf_remove(struct pci_dev *pdev)
i40evf_misc_irq_disable(adapter);
i40evf_free_misc_irq(adapter);
i40evf_reset_interrupt_capability(adapter);
+ i40evf_free_q_vectors(adapter);
}
- del_timer_sync(&adapter->watchdog_timer);
+ if (adapter->watchdog_timer.function)
+ del_timer_sync(&adapter->watchdog_timer);
+
flush_scheduled_work();
if (hw->aq.asq.count)
@@ -2419,6 +2464,13 @@ static void i40evf_remove(struct pci_dev *pdev)
i40evf_free_queues(adapter);
kfree(adapter->vf_res);
+ /* If we got removed before an up/down sequence, we've got a filter
+ * hanging out there that we need to get rid of.
+ */
+ list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
+ list_del(&f->list);
+ kfree(f);
+ }
free_netdev(netdev);