Skip to content

Commit

Permalink
igc: fix page fault when thunderbolt is unplugged
Browse files Browse the repository at this point in the history
After unplug thunderbolt dock with i225, pciehp interrupt is triggered,
remove call will read/write mmio address which is already disconnected,
then cause page fault and make system hang.

Check PCI state to remove device safely.

Trace:
BUG: unable to handle page fault for address: 000000000000b604
Oops: 0000 [#1] SMP NOPTI
RIP: 0010:igc_rd32+0x1c/0x90 [igc]
Call Trace:
igc_ptp_suspend+0x6c/0xa0 [igc]
igc_ptp_stop+0x12/0x50 [igc]
igc_remove+0x7f/0x1c0 [igc]
pci_device_remove+0x3e/0xb0
__device_release_driver+0x181/0x240

Fixes: 13b5b7f ("igc: Add support for Tx/Rx rings")
Fixes: b03c49c ("igc: Save PTP time before a reset")
Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
Tested-by: Dvora Fuxbrumer <dvorax.fuxbrumer@linux.intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
  • Loading branch information
Aaron Ma authored and Tony Nguyen committed Aug 20, 2021
1 parent ffc9c3e commit 4b79959
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 14 deletions.
32 changes: 19 additions & 13 deletions drivers/net/ethernet/intel/igc/igc_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ static void igc_release_hw_control(struct igc_adapter *adapter)
struct igc_hw *hw = &adapter->hw;
u32 ctrl_ext;

if (!pci_device_is_present(adapter->pdev))
return;

/* Let firmware take over control of h/w */
ctrl_ext = rd32(IGC_CTRL_EXT);
wr32(IGC_CTRL_EXT,
Expand Down Expand Up @@ -4449,26 +4452,29 @@ void igc_down(struct igc_adapter *adapter)

igc_ptp_suspend(adapter);

/* disable receives in the hardware */
rctl = rd32(IGC_RCTL);
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
/* flush and sleep below */

if (pci_device_is_present(adapter->pdev)) {
/* disable receives in the hardware */
rctl = rd32(IGC_RCTL);
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
/* flush and sleep below */
}
/* set trans_start so we don't get spurious watchdogs during reset */
netif_trans_update(netdev);

netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);

/* disable transmits in the hardware */
tctl = rd32(IGC_TCTL);
tctl &= ~IGC_TCTL_EN;
wr32(IGC_TCTL, tctl);
/* flush both disables and wait for them to finish */
wrfl();
usleep_range(10000, 20000);
if (pci_device_is_present(adapter->pdev)) {
/* disable transmits in the hardware */
tctl = rd32(IGC_TCTL);
tctl &= ~IGC_TCTL_EN;
wr32(IGC_TCTL, tctl);
/* flush both disables and wait for them to finish */
wrfl();
usleep_range(10000, 20000);

igc_irq_disable(adapter);
igc_irq_disable(adapter);
}

adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;

Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/intel/igc/igc_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter)
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state);

igc_ptp_time_save(adapter);
if (pci_device_is_present(adapter->pdev))
igc_ptp_time_save(adapter);
}

/**
Expand Down

0 comments on commit 4b79959

Please sign in to comment.