diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40evf/i40evf_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40evf_main.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index a53e81bb0960..ab15f4d07e41 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -527,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); @@ -1297,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; @@ -1328,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"); @@ -1395,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)); @@ -1495,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); @@ -1509,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); @@ -1527,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; @@ -1946,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); } @@ -2106,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; @@ -2289,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); @@ -2400,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); @@ -2415,6 +2448,7 @@ 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); } if (adapter->watchdog_timer.function) @@ -2430,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); |