|
@@ -278,10 +278,41 @@ static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter,
|
|
|
static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
|
|
|
+ !test_bit(__IXGBE_REMOVING, &adapter->state) &&
|
|
|
!test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
|
|
|
schedule_work(&adapter->service_task);
|
|
|
}
|
|
|
|
|
|
+static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
|
|
|
+{
|
|
|
+ struct ixgbe_adapter *adapter = hw->back;
|
|
|
+
|
|
|
+ if (!hw->hw_addr)
|
|
|
+ return;
|
|
|
+ hw->hw_addr = NULL;
|
|
|
+ e_dev_err("Adapter removed\n");
|
|
|
+ ixgbe_service_event_schedule(adapter);
|
|
|
+}
|
|
|
+
|
|
|
+void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
|
|
|
+{
|
|
|
+ u32 value;
|
|
|
+
|
|
|
+ /* The following check not only optimizes a bit by not
|
|
|
+ * performing a read on the status register when the
|
|
|
+ * register just read was a status register read that
|
|
|
+ * returned IXGBE_FAILED_READ_REG. It also blocks any
|
|
|
+ * potential recursion.
|
|
|
+ */
|
|
|
+ if (reg == IXGBE_STATUS) {
|
|
|
+ ixgbe_remove_adapter(hw);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ value = ixgbe_read_reg(hw, IXGBE_STATUS);
|
|
|
+ if (value == IXGBE_FAILED_READ_REG)
|
|
|
+ ixgbe_remove_adapter(hw);
|
|
|
+}
|
|
|
+
|
|
|
static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
|
|
@@ -1314,7 +1345,7 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_ring *rx_ring, u32 val)
|
|
|
* such as IA-64).
|
|
|
*/
|
|
|
wmb();
|
|
|
- writel(val, rx_ring->tail);
|
|
|
+ ixgbe_write_tail(rx_ring, val);
|
|
|
}
|
|
|
|
|
|
static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
|
|
@@ -2969,7 +3000,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
|
|
|
ring->count * sizeof(union ixgbe_adv_tx_desc));
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
|
|
|
- ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx);
|
|
|
+ ring->tail = adapter->io_addr + IXGBE_TDT(reg_idx);
|
|
|
|
|
|
/*
|
|
|
* set WTHRESH to encourage burst writeback, it should not be set
|
|
@@ -3308,6 +3339,8 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
|
|
|
u32 rxdctl;
|
|
|
u8 reg_idx = ring->reg_idx;
|
|
|
|
|
|
+ if (ixgbe_removed(hw->hw_addr))
|
|
|
+ return;
|
|
|
/* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
|
|
|
if (hw->mac.type == ixgbe_mac_82598EB &&
|
|
|
!(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
|
|
@@ -3332,6 +3365,8 @@ void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
|
|
|
u32 rxdctl;
|
|
|
u8 reg_idx = ring->reg_idx;
|
|
|
|
|
|
+ if (ixgbe_removed(hw->hw_addr))
|
|
|
+ return;
|
|
|
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
|
|
|
rxdctl &= ~IXGBE_RXDCTL_ENABLE;
|
|
|
|
|
@@ -3372,7 +3407,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
|
|
|
ring->count * sizeof(union ixgbe_adv_rx_desc));
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
|
|
|
IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
|
|
|
- ring->tail = hw->hw_addr + IXGBE_RDT(reg_idx);
|
|
|
+ ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx);
|
|
|
|
|
|
ixgbe_configure_srrctl(adapter, ring);
|
|
|
ixgbe_configure_rscctl(adapter, ring);
|
|
@@ -4572,6 +4607,7 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
|
|
|
if (hw->mac.ops.enable_tx_laser)
|
|
|
hw->mac.ops.enable_tx_laser(hw);
|
|
|
|
|
|
+ smp_mb__before_clear_bit();
|
|
|
clear_bit(__IXGBE_DOWN, &adapter->state);
|
|
|
ixgbe_napi_enable_all(adapter);
|
|
|
|
|
@@ -4656,6 +4692,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
|
|
|
struct ixgbe_hw *hw = &adapter->hw;
|
|
|
int err;
|
|
|
|
|
|
+ if (ixgbe_removed(hw->hw_addr))
|
|
|
+ return;
|
|
|
/* lock SFP init bit to prevent race conditions with the watchdog */
|
|
|
while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
|
|
|
usleep_range(1000, 2000);
|
|
@@ -4783,7 +4821,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
|
|
|
int i;
|
|
|
|
|
|
/* signal that we are down to the interrupt handler */
|
|
|
- set_bit(__IXGBE_DOWN, &adapter->state);
|
|
|
+ if (test_and_set_bit(__IXGBE_DOWN, &adapter->state))
|
|
|
+ return; /* do nothing if already down */
|
|
|
|
|
|
/* disable receives */
|
|
|
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
|
|
@@ -5874,8 +5913,9 @@ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
|
|
|
u64 eics = 0;
|
|
|
int i;
|
|
|
|
|
|
- /* If we're down or resetting, just bail */
|
|
|
+ /* If we're down, removing or resetting, just bail */
|
|
|
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
|
|
|
+ test_bit(__IXGBE_REMOVING, &adapter->state) ||
|
|
|
test_bit(__IXGBE_RESETTING, &adapter->state))
|
|
|
return;
|
|
|
|
|
@@ -6122,8 +6162,9 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
|
|
|
**/
|
|
|
static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
|
|
|
{
|
|
|
- /* if interface is down do nothing */
|
|
|
+ /* if interface is down, removing or resetting, do nothing */
|
|
|
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
|
|
|
+ test_bit(__IXGBE_REMOVING, &adapter->state) ||
|
|
|
test_bit(__IXGBE_RESETTING, &adapter->state))
|
|
|
return;
|
|
|
|
|
@@ -6341,8 +6382,9 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
|
|
|
|
|
|
adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED;
|
|
|
|
|
|
- /* If we're already down or resetting, just bail */
|
|
|
+ /* If we're already down, removing or resetting, just bail */
|
|
|
if (test_bit(__IXGBE_DOWN, &adapter->state) ||
|
|
|
+ test_bit(__IXGBE_REMOVING, &adapter->state) ||
|
|
|
test_bit(__IXGBE_RESETTING, &adapter->state))
|
|
|
return;
|
|
|
|
|
@@ -6362,6 +6404,15 @@ static void ixgbe_service_task(struct work_struct *work)
|
|
|
struct ixgbe_adapter *adapter = container_of(work,
|
|
|
struct ixgbe_adapter,
|
|
|
service_task);
|
|
|
+ if (ixgbe_removed(adapter->hw.hw_addr)) {
|
|
|
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
|
|
|
+ rtnl_lock();
|
|
|
+ ixgbe_down(adapter);
|
|
|
+ rtnl_unlock();
|
|
|
+ }
|
|
|
+ ixgbe_service_event_complete(adapter);
|
|
|
+ return;
|
|
|
+ }
|
|
|
ixgbe_reset_subtask(adapter);
|
|
|
ixgbe_sfp_detection_subtask(adapter);
|
|
|
ixgbe_sfp_link_config_subtask(adapter);
|
|
@@ -6693,7 +6744,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
|
|
|
tx_ring->next_to_use = i;
|
|
|
|
|
|
/* notify HW of packet */
|
|
|
- writel(i, tx_ring->tail);
|
|
|
+ ixgbe_write_tail(tx_ring, i);
|
|
|
|
|
|
return;
|
|
|
dma_error:
|
|
@@ -7874,6 +7925,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
|
|
hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
|
|
|
pci_resource_len(pdev, 0));
|
|
|
+ adapter->io_addr = hw->hw_addr;
|
|
|
if (!hw->hw_addr) {
|
|
|
err = -EIO;
|
|
|
goto err_ioremap;
|
|
@@ -8182,7 +8234,7 @@ err_register:
|
|
|
err_sw_init:
|
|
|
ixgbe_disable_sriov(adapter);
|
|
|
adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
|
|
|
- iounmap(hw->hw_addr);
|
|
|
+ iounmap(adapter->io_addr);
|
|
|
err_ioremap:
|
|
|
free_netdev(netdev);
|
|
|
err_alloc_etherdev:
|
|
@@ -8210,7 +8262,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
|
|
|
|
|
|
ixgbe_dbg_adapter_exit(adapter);
|
|
|
|
|
|
- set_bit(__IXGBE_DOWN, &adapter->state);
|
|
|
+ set_bit(__IXGBE_REMOVING, &adapter->state);
|
|
|
cancel_work_sync(&adapter->service_task);
|
|
|
|
|
|
|
|
@@ -8249,7 +8301,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
|
|
|
kfree(adapter->ixgbe_ieee_ets);
|
|
|
|
|
|
#endif
|
|
|
- iounmap(adapter->hw.hw_addr);
|
|
|
+ iounmap(adapter->io_addr);
|
|
|
pci_release_selected_regions(pdev, pci_select_bars(pdev,
|
|
|
IORESOURCE_MEM));
|
|
|
|