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);
|
static void ixgb_netpoll(struct net_device *dev);
|
||||||
#endif
|
#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);
|
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 = {
|
static struct pci_driver ixgb_driver = {
|
||||||
.name = ixgb_driver_name,
|
.name = ixgb_driver_name,
|
||||||
.id_table = ixgb_pci_tbl,
|
.id_table = ixgb_pci_tbl,
|
||||||
.probe = ixgb_probe,
|
.probe = ixgb_probe,
|
||||||
.remove = __devexit_p(ixgb_remove),
|
.remove = __devexit_p(ixgb_remove),
|
||||||
|
.err_handler = &ixgb_err_handler
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
|
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
|
||||||
|
@ -1550,6 +1561,11 @@ void
|
||||||
ixgb_update_stats(struct ixgb_adapter *adapter)
|
ixgb_update_stats(struct ixgb_adapter *adapter)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = adapter->netdev;
|
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) ||
|
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
|
||||||
(netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
|
(netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
|
||||||
|
@ -2205,4 +2221,98 @@ static void ixgb_netpoll(struct net_device *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/* ixgb_main.c */
|
||||||
|
|
Loading…
Reference in New Issue