|
@@ -189,6 +189,16 @@ static void e1000_shutdown(struct pci_dev *pdev);
|
|
|
static void e1000_netpoll (struct net_device *netdev);
|
|
|
#endif
|
|
|
|
|
|
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
|
|
|
+ pci_channel_state_t state);
|
|
|
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
|
|
|
+static void e1000_io_resume(struct pci_dev *pdev);
|
|
|
+
|
|
|
+static struct pci_error_handlers e1000_err_handler = {
|
|
|
+ .error_detected = e1000_io_error_detected,
|
|
|
+ .slot_reset = e1000_io_slot_reset,
|
|
|
+ .resume = e1000_io_resume,
|
|
|
+};
|
|
|
|
|
|
static struct pci_driver e1000_driver = {
|
|
|
.name = e1000_driver_name,
|
|
@@ -200,7 +210,8 @@ static struct pci_driver e1000_driver = {
|
|
|
.suspend = e1000_suspend,
|
|
|
.resume = e1000_resume,
|
|
|
#endif
|
|
|
- .shutdown = e1000_shutdown
|
|
|
+ .shutdown = e1000_shutdown,
|
|
|
+ .err_handler = &e1000_err_handler
|
|
|
};
|
|
|
|
|
|
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
|
|
@@ -3039,6 +3050,10 @@ e1000_update_stats(struct e1000_adapter *adapter)
|
|
|
|
|
|
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
|
|
|
|
|
|
+ /* Prevent stats update while adapter is being reset */
|
|
|
+ if (adapter->link_speed == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
spin_lock_irqsave(&adapter->stats_lock, flags);
|
|
|
|
|
|
/* these counters are modified from e1000_adjust_tbi_stats,
|
|
@@ -4594,4 +4609,101 @@ e1000_netpoll(struct net_device *netdev)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/**
|
|
|
+ * e1000_io_error_detected - called when PCI error is detected
|
|
|
+ * @pdev: Pointer to PCI device
|
|
|
+ * @state: The current pci conneection state
|
|
|
+ *
|
|
|
+ * This function is called after a PCI bus error affecting
|
|
|
+ * this device has been detected.
|
|
|
+ */
|
|
|
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
|
|
+{
|
|
|
+ struct net_device *netdev = pci_get_drvdata(pdev);
|
|
|
+ struct e1000_adapter *adapter = netdev->priv;
|
|
|
+
|
|
|
+ netif_device_detach(netdev);
|
|
|
+
|
|
|
+ if (netif_running(netdev))
|
|
|
+ e1000_down(adapter);
|
|
|
+
|
|
|
+ /* Request a slot slot reset. */
|
|
|
+ return PCI_ERS_RESULT_NEED_RESET;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * e1000_io_slot_reset - called after the pci bus has been reset.
|
|
|
+ * @pdev: Pointer to PCI device
|
|
|
+ *
|
|
|
+ * Restart the card from scratch, as if from a cold-boot. Implementation
|
|
|
+ * resembles the first-half of the e1000_resume routine.
|
|
|
+ */
|
|
|
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct net_device *netdev = pci_get_drvdata(pdev);
|
|
|
+ struct e1000_adapter *adapter = netdev->priv;
|
|
|
+
|
|
|
+ if (pci_enable_device(pdev)) {
|
|
|
+ printk(KERN_ERR "e1000: Cannot re-enable PCI device after reset.\n");
|
|
|
+ return PCI_ERS_RESULT_DISCONNECT;
|
|
|
+ }
|
|
|
+ pci_set_master(pdev);
|
|
|
+
|
|
|
+ pci_enable_wake(pdev, 3, 0);
|
|
|
+ pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
|
|
|
+
|
|
|
+ /* Perform card reset only on one instance of the card */
|
|
|
+ if (PCI_FUNC (pdev->devfn) != 0)
|
|
|
+ return PCI_ERS_RESULT_RECOVERED;
|
|
|
+
|
|
|
+ e1000_reset(adapter);
|
|
|
+ E1000_WRITE_REG(&adapter->hw, WUS, ~0);
|
|
|
+
|
|
|
+ return PCI_ERS_RESULT_RECOVERED;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * e1000_io_resume - called when traffic can start flowing again.
|
|
|
+ * @pdev: Pointer to PCI device
|
|
|
+ *
|
|
|
+ * This callback is called when the error recovery driver tells us that
|
|
|
+ * its OK to resume normal operation. Implementation resembles the
|
|
|
+ * second-half of the e1000_resume routine.
|
|
|
+ */
|
|
|
+static void e1000_io_resume(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ struct net_device *netdev = pci_get_drvdata(pdev);
|
|
|
+ struct e1000_adapter *adapter = netdev->priv;
|
|
|
+ uint32_t manc, swsm;
|
|
|
+
|
|
|
+ if (netif_running(netdev)) {
|
|
|
+ if (e1000_up(adapter)) {
|
|
|
+ printk("e1000: can't bring device back up after reset\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ netif_device_attach(netdev);
|
|
|
+
|
|
|
+ if (adapter->hw.mac_type >= e1000_82540 &&
|
|
|
+ adapter->hw.media_type == e1000_media_type_copper) {
|
|
|
+ manc = E1000_READ_REG(&adapter->hw, MANC);
|
|
|
+ manc &= ~(E1000_MANC_ARP_EN);
|
|
|
+ E1000_WRITE_REG(&adapter->hw, MANC, manc);
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (adapter->hw.mac_type) {
|
|
|
+ case e1000_82573:
|
|
|
+ swsm = E1000_READ_REG(&adapter->hw, SWSM);
|
|
|
+ E1000_WRITE_REG(&adapter->hw, SWSM,
|
|
|
+ swsm | E1000_SWSM_DRV_LOAD);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (netif_running(netdev))
|
|
|
+ mod_timer(&adapter->watchdog_timer, jiffies);
|
|
|
+}
|
|
|
+
|
|
|
/* e1000_main.c */
|