igc: fix page fault when thunderbolt is unplugged
[ Upstream commit 4b79959510e6612d80f8d86022e0cb44eee6f4a2 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
384dea502e
commit
ae6480ba06
@@ -138,6 +138,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,
|
||||||
@@ -3782,17 +3785,19 @@ void igc_down(struct igc_adapter *adapter)
|
|||||||
|
|
||||||
igc_ptp_suspend(adapter);
|
igc_ptp_suspend(adapter);
|
||||||
|
|
||||||
|
if (pci_device_is_present(adapter->pdev)) {
|
||||||
/* disable receives in the hardware */
|
/* disable receives in the hardware */
|
||||||
rctl = rd32(IGC_RCTL);
|
rctl = rd32(IGC_RCTL);
|
||||||
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
|
wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN);
|
||||||
/* flush and sleep below */
|
/* 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);
|
||||||
|
|
||||||
|
if (pci_device_is_present(adapter->pdev)) {
|
||||||
/* disable transmits in the hardware */
|
/* disable transmits in the hardware */
|
||||||
tctl = rd32(IGC_TCTL);
|
tctl = rd32(IGC_TCTL);
|
||||||
tctl &= ~IGC_TCTL_EN;
|
tctl &= ~IGC_TCTL_EN;
|
||||||
@@ -3802,6 +3807,7 @@ void igc_down(struct igc_adapter *adapter)
|
|||||||
usleep_range(10000, 20000);
|
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;
|
||||||
|
|
||||||
|
@@ -557,6 +557,7 @@ 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);
|
||||||
|
|
||||||
|
if (pci_device_is_present(adapter->pdev))
|
||||||
igc_ptp_time_save(adapter);
|
igc_ptp_time_save(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user