diff options
author | Linas Vepstas <linas@austin.ibm.com> | 2006-08-31 17:27:52 -0400 |
---|---|---|
committer | Auke Kok <juke-jan.h.kok@intel.com> | 2006-08-31 17:27:52 -0400 |
commit | 01748fbb413d6f3b36c330544969d1d7254ee509 (patch) | |
tree | 1148455cf4d76d0b4bc17186790710282339449c /drivers/net/ixgb/ixgb_main.c | |
parent | adc5413965e6ca2cd18f0ec89933f762b5605574 (diff) |
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>
Diffstat (limited to 'drivers/net/ixgb/ixgb_main.c')
-rw-r--r-- | drivers/net/ixgb/ixgb_main.c | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index a5da48a1fca0..abca75fd2892 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c | |||
@@ -118,15 +118,26 @@ static void ixgb_restore_vlan(struct ixgb_adapter *adapter); | |||
118 | static void ixgb_netpoll(struct net_device *dev); | 118 | static void ixgb_netpoll(struct net_device *dev); |
119 | #endif | 119 | #endif |
120 | 120 | ||
121 | /* Exported from other modules */ | 121 | static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev, |
122 | enum pci_channel_state state); | ||
123 | static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev); | ||
124 | static void ixgb_io_resume (struct pci_dev *pdev); | ||
122 | 125 | ||
126 | /* Exported from other modules */ | ||
123 | extern void ixgb_check_options(struct ixgb_adapter *adapter); | 127 | extern void ixgb_check_options(struct ixgb_adapter *adapter); |
124 | 128 | ||
129 | static struct pci_error_handlers ixgb_err_handler = { | ||
130 | .error_detected = ixgb_io_error_detected, | ||
131 | .slot_reset = ixgb_io_slot_reset, | ||
132 | .resume = ixgb_io_resume, | ||
133 | }; | ||
134 | |||
125 | static struct pci_driver ixgb_driver = { | 135 | static struct pci_driver ixgb_driver = { |
126 | .name = ixgb_driver_name, | 136 | .name = ixgb_driver_name, |
127 | .id_table = ixgb_pci_tbl, | 137 | .id_table = ixgb_pci_tbl, |
128 | .probe = ixgb_probe, | 138 | .probe = ixgb_probe, |
129 | .remove = __devexit_p(ixgb_remove), | 139 | .remove = __devexit_p(ixgb_remove), |
140 | .err_handler = &ixgb_err_handler | ||
130 | }; | 141 | }; |
131 | 142 | ||
132 | MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>"); | 143 | MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>"); |
@@ -1550,6 +1561,11 @@ void | |||
1550 | ixgb_update_stats(struct ixgb_adapter *adapter) | 1561 | ixgb_update_stats(struct ixgb_adapter *adapter) |
1551 | { | 1562 | { |
1552 | struct net_device *netdev = adapter->netdev; | 1563 | struct net_device *netdev = adapter->netdev; |
1564 | struct pci_dev *pdev = adapter->pdev; | ||
1565 | |||
1566 | /* Prevent stats update while adapter is being reset */ | ||
1567 | if (pdev->error_state && pdev->error_state != pci_channel_io_normal) | ||
1568 | return; | ||
1553 | 1569 | ||
1554 | if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || | 1570 | if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || |
1555 | (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { | 1571 | (netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) { |
@@ -2205,4 +2221,98 @@ static void ixgb_netpoll(struct net_device *dev) | |||
2205 | } | 2221 | } |
2206 | #endif | 2222 | #endif |
2207 | 2223 | ||
2224 | /** | ||
2225 | * ixgb_io_error_detected() - called when PCI error is detected | ||
2226 | * @pdev pointer to pci device with error | ||
2227 | * @state pci channel state after error | ||
2228 | * | ||
2229 | * This callback is called by the PCI subsystem whenever | ||
2230 | * a PCI bus error is detected. | ||
2231 | */ | ||
2232 | static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev, | ||
2233 | enum pci_channel_state state) | ||
2234 | { | ||
2235 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
2236 | struct ixgb_adapter *adapter = netdev->priv; | ||
2237 | |||
2238 | if(netif_running(netdev)) | ||
2239 | ixgb_down(adapter, TRUE); | ||
2240 | |||
2241 | pci_disable_device(pdev); | ||
2242 | |||
2243 | /* Request a slot reset. */ | ||
2244 | return PCI_ERS_RESULT_NEED_RESET; | ||
2245 | } | ||
2246 | |||
2247 | /** | ||
2248 | * ixgb_io_slot_reset - called after the pci bus has been reset. | ||
2249 | * @pdev pointer to pci device with error | ||
2250 | * | ||
2251 | * This callback is called after the PCI buss has been reset. | ||
2252 | * Basically, this tries to restart the card from scratch. | ||
2253 | * This is a shortened version of the device probe/discovery code, | ||
2254 | * it resembles the first-half of the ixgb_probe() routine. | ||
2255 | */ | ||
2256 | static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev) | ||
2257 | { | ||
2258 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
2259 | struct ixgb_adapter *adapter = netdev->priv; | ||
2260 | |||
2261 | if(pci_enable_device(pdev)) { | ||
2262 | DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); | ||
2263 | return PCI_ERS_RESULT_DISCONNECT; | ||
2264 | } | ||
2265 | |||
2266 | /* Perform card reset only on one instance of the card */ | ||
2267 | if (0 != PCI_FUNC (pdev->devfn)) | ||
2268 | return PCI_ERS_RESULT_RECOVERED; | ||
2269 | |||
2270 | pci_set_master(pdev); | ||
2271 | |||
2272 | netif_carrier_off(netdev); | ||
2273 | netif_stop_queue(netdev); | ||
2274 | ixgb_reset(adapter); | ||
2275 | |||
2276 | /* Make sure the EEPROM is good */ | ||
2277 | if(!ixgb_validate_eeprom_checksum(&adapter->hw)) { | ||
2278 | DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n"); | ||
2279 | return PCI_ERS_RESULT_DISCONNECT; | ||
2280 | } | ||
2281 | ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr); | ||
2282 | memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); | ||
2283 | |||
2284 | if(!is_valid_ether_addr(netdev->perm_addr)) { | ||
2285 | DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n"); | ||
2286 | return PCI_ERS_RESULT_DISCONNECT; | ||
2287 | } | ||
2288 | |||
2289 | return PCI_ERS_RESULT_RECOVERED; | ||
2290 | } | ||
2291 | |||
2292 | /** | ||
2293 | * ixgb_io_resume - called when its OK to resume normal operations | ||
2294 | * @pdev pointer to pci device with error | ||
2295 | * | ||
2296 | * The error recovery driver tells us that its OK to resume | ||
2297 | * normal operation. Implementation resembles the second-half | ||
2298 | * of the ixgb_probe() routine. | ||
2299 | */ | ||
2300 | static void ixgb_io_resume (struct pci_dev *pdev) | ||
2301 | { | ||
2302 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
2303 | struct ixgb_adapter *adapter = netdev->priv; | ||
2304 | |||
2305 | pci_set_master(pdev); | ||
2306 | |||
2307 | if(netif_running(netdev)) { | ||
2308 | if(ixgb_up(adapter)) { | ||
2309 | printk ("ixgb: can't bring device back up after reset\n"); | ||
2310 | return; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2314 | netif_device_attach(netdev); | ||
2315 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
2316 | } | ||
2317 | |||
2208 | /* ixgb_main.c */ | 2318 | /* ixgb_main.c */ |