mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 18:13:04 +00:00
ixgb: Add PCI Error recovery callbacks
Adds PCI Error recovery callbacks to the Intel 10-gigabit ethernet ixgb device driver. Lightly tested, works. "Zhang, Yanmin" <yanmin_zhang@linux.intel.com> wrote: Both pci_disable_device and ixgb_down would access the device. It doesn't follow Documentation/pci-error-recovery.txt that error_detected shouldn't do any access to the device. Signed-off-by: Linas Vepstas <linas@austin.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
This commit is contained in:
parent
adc5413965
commit
01748fbb41
@ -118,15 +118,26 @@ static void ixgb_restore_vlan(struct ixgb_adapter *adapter);
|
||||
static void ixgb_netpoll(struct net_device *dev);
|
||||
#endif
|
||||
|
||||
/* Exported from other modules */
|
||||
static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
|
||||
enum pci_channel_state state);
|
||||
static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
|
||||
static void ixgb_io_resume (struct pci_dev *pdev);
|
||||
|
||||
/* Exported from other modules */
|
||||
extern void ixgb_check_options(struct ixgb_adapter *adapter);
|
||||
|
||||
static struct pci_error_handlers ixgb_err_handler = {
|
||||
.error_detected = ixgb_io_error_detected,
|
||||
.slot_reset = ixgb_io_slot_reset,
|
||||
.resume = ixgb_io_resume,
|
||||
};
|
||||
|
||||
static struct pci_driver ixgb_driver = {
|
||||
.name = ixgb_driver_name,
|
||||
.id_table = ixgb_pci_tbl,
|
||||
.probe = ixgb_probe,
|
||||
.remove = __devexit_p(ixgb_remove),
|
||||
.err_handler = &ixgb_err_handler
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
|
||||
@ -1550,6 +1561,11 @@ void
|
||||
ixgb_update_stats(struct ixgb_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
|
||||
/* Prevent stats update while adapter is being reset */
|
||||
if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
|
||||
return;
|
||||
|
||||
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
|
||||
(netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
|
||||
@ -2205,4 +2221,98 @@ static void ixgb_netpoll(struct net_device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ixgb_io_error_detected() - called when PCI error is detected
|
||||
* @pdev pointer to pci device with error
|
||||
* @state pci channel state after error
|
||||
*
|
||||
* This callback is called by the PCI subsystem whenever
|
||||
* a PCI bus error is detected.
|
||||
*/
|
||||
static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
|
||||
enum pci_channel_state state)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct ixgb_adapter *adapter = netdev->priv;
|
||||
|
||||
if(netif_running(netdev))
|
||||
ixgb_down(adapter, TRUE);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
|
||||
/* Request a slot reset. */
|
||||
return PCI_ERS_RESULT_NEED_RESET;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgb_io_slot_reset - called after the pci bus has been reset.
|
||||
* @pdev pointer to pci device with error
|
||||
*
|
||||
* This callback is called after the PCI buss has been reset.
|
||||
* Basically, this tries to restart the card from scratch.
|
||||
* This is a shortened version of the device probe/discovery code,
|
||||
* it resembles the first-half of the ixgb_probe() routine.
|
||||
*/
|
||||
static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct ixgb_adapter *adapter = netdev->priv;
|
||||
|
||||
if(pci_enable_device(pdev)) {
|
||||
DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
/* Perform card reset only on one instance of the card */
|
||||
if (0 != PCI_FUNC (pdev->devfn))
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
netif_carrier_off(netdev);
|
||||
netif_stop_queue(netdev);
|
||||
ixgb_reset(adapter);
|
||||
|
||||
/* Make sure the EEPROM is good */
|
||||
if(!ixgb_validate_eeprom_checksum(&adapter->hw)) {
|
||||
DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
|
||||
memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
|
||||
|
||||
if(!is_valid_ether_addr(netdev->perm_addr)) {
|
||||
DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n");
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgb_io_resume - called when its OK to resume normal operations
|
||||
* @pdev pointer to pci device with error
|
||||
*
|
||||
* The error recovery driver tells us that its OK to resume
|
||||
* normal operation. Implementation resembles the second-half
|
||||
* of the ixgb_probe() routine.
|
||||
*/
|
||||
static void ixgb_io_resume (struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||
struct ixgb_adapter *adapter = netdev->priv;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if(netif_running(netdev)) {
|
||||
if(ixgb_up(adapter)) {
|
||||
printk ("ixgb: can't bring device back up after reset\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
netif_device_attach(netdev);
|
||||
mod_timer(&adapter->watchdog_timer, jiffies);
|
||||
}
|
||||
|
||||
/* ixgb_main.c */
|
||||
|
Loading…
Reference in New Issue
Block a user