mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
igc: fix page fault when thunderbolt is unplugged
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:13b5b7fd6a
("igc: Add support for Tx/Rx rings") Fixes:b03c49cde6
("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>
This commit is contained in:
parent
ffc9c3ebb4
commit
4b79959510
2 changed files with 21 additions and 14 deletions
|
@ -149,6 +149,9 @@ static void igc_release_hw_control(struct igc_adapter *adapter)
|
||||||
struct igc_hw *hw = &adapter->hw;
|
struct igc_hw *hw = &adapter->hw;
|
||||||
u32 ctrl_ext;
|
u32 ctrl_ext;
|
||||||
|
|
||||||
|
if (!pci_device_is_present(adapter->pdev))
|
||||||
|
return;
|
||||||
|
|
||||||
/* Let firmware take over control of h/w */
|
/* Let firmware take over control of h/w */
|
||||||
ctrl_ext = rd32(IGC_CTRL_EXT);
|
ctrl_ext = rd32(IGC_CTRL_EXT);
|
||||||
wr32(IGC_CTRL_EXT,
|
wr32(IGC_CTRL_EXT,
|
||||||
|
@ -4449,26 +4452,29 @@ void igc_down(struct igc_adapter *adapter)
|
||||||
|
|
||||||
igc_ptp_suspend(adapter);
|
igc_ptp_suspend(adapter);
|
||||||
|
|
||||||
/* disable receives in the hardware */
|
if (pci_device_is_present(adapter->pdev)) {
|
||||||
rctl = rd32(IGC_RCTL);
|
/* disable receives in the hardware */
|
||||||
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
|
rctl = rd32(IGC_RCTL);
|
||||||
/* flush and sleep below */
|
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
|
||||||
|
/* flush and sleep below */
|
||||||
|
}
|
||||||
/* set trans_start so we don't get spurious watchdogs during reset */
|
/* set trans_start so we don't get spurious watchdogs during reset */
|
||||||
netif_trans_update(netdev);
|
netif_trans_update(netdev);
|
||||||
|
|
||||||
netif_carrier_off(netdev);
|
netif_carrier_off(netdev);
|
||||||
netif_tx_stop_all_queues(netdev);
|
netif_tx_stop_all_queues(netdev);
|
||||||
|
|
||||||
/* disable transmits in the hardware */
|
if (pci_device_is_present(adapter->pdev)) {
|
||||||
tctl = rd32(IGC_TCTL);
|
/* disable transmits in the hardware */
|
||||||
tctl &= ~IGC_TCTL_EN;
|
tctl = rd32(IGC_TCTL);
|
||||||
wr32(IGC_TCTL, tctl);
|
tctl &= ~IGC_TCTL_EN;
|
||||||
/* flush both disables and wait for them to finish */
|
wr32(IGC_TCTL, tctl);
|
||||||
wrfl();
|
/* flush both disables and wait for them to finish */
|
||||||
usleep_range(10000, 20000);
|
wrfl();
|
||||||
|
usleep_range(10000, 20000);
|
||||||
|
|
||||||
igc_irq_disable(adapter);
|
igc_irq_disable(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
|
adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE;
|
||||||
|
|
||||||
|
|
|
@ -849,7 +849,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter)
|
||||||
adapter->ptp_tx_skb = NULL;
|
adapter->ptp_tx_skb = NULL;
|
||||||
clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue