diff options
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r-- | drivers/net/s2io.c | 116 |
1 files changed, 110 insertions, 6 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 09078ff84cd2..2d826fff7e2e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -469,11 +469,18 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { | |||
469 | 469 | ||
470 | MODULE_DEVICE_TABLE(pci, s2io_tbl); | 470 | MODULE_DEVICE_TABLE(pci, s2io_tbl); |
471 | 471 | ||
472 | static struct pci_error_handlers s2io_err_handler = { | ||
473 | .error_detected = s2io_io_error_detected, | ||
474 | .slot_reset = s2io_io_slot_reset, | ||
475 | .resume = s2io_io_resume, | ||
476 | }; | ||
477 | |||
472 | static struct pci_driver s2io_driver = { | 478 | static struct pci_driver s2io_driver = { |
473 | .name = "S2IO", | 479 | .name = "S2IO", |
474 | .id_table = s2io_tbl, | 480 | .id_table = s2io_tbl, |
475 | .probe = s2io_init_nic, | 481 | .probe = s2io_init_nic, |
476 | .remove = __devexit_p(s2io_rem_nic), | 482 | .remove = __devexit_p(s2io_rem_nic), |
483 | .err_handler = &s2io_err_handler, | ||
477 | }; | 484 | }; |
478 | 485 | ||
479 | /* A simplifier macro used both by init and free shared_mem Fns(). */ | 486 | /* A simplifier macro used both by init and free shared_mem Fns(). */ |
@@ -2689,6 +2696,9 @@ static void s2io_netpoll(struct net_device *dev) | |||
2689 | u64 val64 = 0xFFFFFFFFFFFFFFFFULL; | 2696 | u64 val64 = 0xFFFFFFFFFFFFFFFFULL; |
2690 | int i; | 2697 | int i; |
2691 | 2698 | ||
2699 | if (pci_channel_offline(nic->pdev)) | ||
2700 | return; | ||
2701 | |||
2692 | disable_irq(dev->irq); | 2702 | disable_irq(dev->irq); |
2693 | 2703 | ||
2694 | atomic_inc(&nic->isr_cnt); | 2704 | atomic_inc(&nic->isr_cnt); |
@@ -3215,6 +3225,8 @@ static void alarm_intr_handler(struct s2io_nic *nic) | |||
3215 | int i; | 3225 | int i; |
3216 | if (atomic_read(&nic->card_state) == CARD_DOWN) | 3226 | if (atomic_read(&nic->card_state) == CARD_DOWN) |
3217 | return; | 3227 | return; |
3228 | if (pci_channel_offline(nic->pdev)) | ||
3229 | return; | ||
3218 | nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; | 3230 | nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; |
3219 | /* Handling the XPAK counters update */ | 3231 | /* Handling the XPAK counters update */ |
3220 | if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { | 3232 | if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { |
@@ -3958,7 +3970,6 @@ static int s2io_close(struct net_device *dev) | |||
3958 | /* Reset card, kill tasklet and free Tx and Rx buffers. */ | 3970 | /* Reset card, kill tasklet and free Tx and Rx buffers. */ |
3959 | s2io_card_down(sp); | 3971 | s2io_card_down(sp); |
3960 | 3972 | ||
3961 | sp->device_close_flag = TRUE; /* Device is shut down. */ | ||
3962 | return 0; | 3973 | return 0; |
3963 | } | 3974 | } |
3964 | 3975 | ||
@@ -4314,6 +4325,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) | |||
4314 | struct mac_info *mac_control; | 4325 | struct mac_info *mac_control; |
4315 | struct config_param *config; | 4326 | struct config_param *config; |
4316 | 4327 | ||
4328 | /* Pretend we handled any irq's from a disconnected card */ | ||
4329 | if (pci_channel_offline(sp->pdev)) | ||
4330 | return IRQ_NONE; | ||
4331 | |||
4317 | atomic_inc(&sp->isr_cnt); | 4332 | atomic_inc(&sp->isr_cnt); |
4318 | mac_control = &sp->mac_control; | 4333 | mac_control = &sp->mac_control; |
4319 | config = &sp->config; | 4334 | config = &sp->config; |
@@ -6569,7 +6584,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) | |||
6569 | } while(cnt < 5); | 6584 | } while(cnt < 5); |
6570 | } | 6585 | } |
6571 | 6586 | ||
6572 | static void s2io_card_down(struct s2io_nic * sp) | 6587 | static void do_s2io_card_down(struct s2io_nic * sp, int do_io) |
6573 | { | 6588 | { |
6574 | int cnt = 0; | 6589 | int cnt = 0; |
6575 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 6590 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
@@ -6584,7 +6599,8 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6584 | atomic_set(&sp->card_state, CARD_DOWN); | 6599 | atomic_set(&sp->card_state, CARD_DOWN); |
6585 | 6600 | ||
6586 | /* disable Tx and Rx traffic on the NIC */ | 6601 | /* disable Tx and Rx traffic on the NIC */ |
6587 | stop_nic(sp); | 6602 | if (do_io) |
6603 | stop_nic(sp); | ||
6588 | 6604 | ||
6589 | s2io_rem_isr(sp); | 6605 | s2io_rem_isr(sp); |
6590 | 6606 | ||
@@ -6592,7 +6608,7 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6592 | tasklet_kill(&sp->task); | 6608 | tasklet_kill(&sp->task); |
6593 | 6609 | ||
6594 | /* Check if the device is Quiescent and then Reset the NIC */ | 6610 | /* Check if the device is Quiescent and then Reset the NIC */ |
6595 | do { | 6611 | while(do_io) { |
6596 | /* As per the HW requirement we need to replenish the | 6612 | /* As per the HW requirement we need to replenish the |
6597 | * receive buffer to avoid the ring bump. Since there is | 6613 | * receive buffer to avoid the ring bump. Since there is |
6598 | * no intention of processing the Rx frame at this pointwe are | 6614 | * no intention of processing the Rx frame at this pointwe are |
@@ -6617,8 +6633,9 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6617 | (unsigned long long) val64); | 6633 | (unsigned long long) val64); |
6618 | break; | 6634 | break; |
6619 | } | 6635 | } |
6620 | } while (1); | 6636 | } |
6621 | s2io_reset(sp); | 6637 | if (do_io) |
6638 | s2io_reset(sp); | ||
6622 | 6639 | ||
6623 | spin_lock_irqsave(&sp->tx_lock, flags); | 6640 | spin_lock_irqsave(&sp->tx_lock, flags); |
6624 | /* Free all Tx buffers */ | 6641 | /* Free all Tx buffers */ |
@@ -6633,6 +6650,11 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6633 | clear_bit(0, &(sp->link_state)); | 6650 | clear_bit(0, &(sp->link_state)); |
6634 | } | 6651 | } |
6635 | 6652 | ||
6653 | static void s2io_card_down(struct s2io_nic * sp) | ||
6654 | { | ||
6655 | do_s2io_card_down(sp, 1); | ||
6656 | } | ||
6657 | |||
6636 | static int s2io_card_up(struct s2io_nic * sp) | 6658 | static int s2io_card_up(struct s2io_nic * sp) |
6637 | { | 6659 | { |
6638 | int i, ret = 0; | 6660 | int i, ret = 0; |
@@ -8010,3 +8032,85 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, | |||
8010 | sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; | 8032 | sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; |
8011 | return; | 8033 | return; |
8012 | } | 8034 | } |
8035 | |||
8036 | /** | ||
8037 | * s2io_io_error_detected - called when PCI error is detected | ||
8038 | * @pdev: Pointer to PCI device | ||
8039 | * @state: The current pci conneection state | ||
8040 | * | ||
8041 | * This function is called after a PCI bus error affecting | ||
8042 | * this device has been detected. | ||
8043 | */ | ||
8044 | static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, | ||
8045 | pci_channel_state_t state) | ||
8046 | { | ||
8047 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8048 | struct s2io_nic *sp = netdev->priv; | ||
8049 | |||
8050 | netif_device_detach(netdev); | ||
8051 | |||
8052 | if (netif_running(netdev)) { | ||
8053 | /* Bring down the card, while avoiding PCI I/O */ | ||
8054 | do_s2io_card_down(sp, 0); | ||
8055 | } | ||
8056 | pci_disable_device(pdev); | ||
8057 | |||
8058 | return PCI_ERS_RESULT_NEED_RESET; | ||
8059 | } | ||
8060 | |||
8061 | /** | ||
8062 | * s2io_io_slot_reset - called after the pci bus has been reset. | ||
8063 | * @pdev: Pointer to PCI device | ||
8064 | * | ||
8065 | * Restart the card from scratch, as if from a cold-boot. | ||
8066 | * At this point, the card has exprienced a hard reset, | ||
8067 | * followed by fixups by BIOS, and has its config space | ||
8068 | * set up identically to what it was at cold boot. | ||
8069 | */ | ||
8070 | static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) | ||
8071 | { | ||
8072 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8073 | struct s2io_nic *sp = netdev->priv; | ||
8074 | |||
8075 | if (pci_enable_device(pdev)) { | ||
8076 | printk(KERN_ERR "s2io: " | ||
8077 | "Cannot re-enable PCI device after reset.\n"); | ||
8078 | return PCI_ERS_RESULT_DISCONNECT; | ||
8079 | } | ||
8080 | |||
8081 | pci_set_master(pdev); | ||
8082 | s2io_reset(sp); | ||
8083 | |||
8084 | return PCI_ERS_RESULT_RECOVERED; | ||
8085 | } | ||
8086 | |||
8087 | /** | ||
8088 | * s2io_io_resume - called when traffic can start flowing again. | ||
8089 | * @pdev: Pointer to PCI device | ||
8090 | * | ||
8091 | * This callback is called when the error recovery driver tells | ||
8092 | * us that its OK to resume normal operation. | ||
8093 | */ | ||
8094 | static void s2io_io_resume(struct pci_dev *pdev) | ||
8095 | { | ||
8096 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8097 | struct s2io_nic *sp = netdev->priv; | ||
8098 | |||
8099 | if (netif_running(netdev)) { | ||
8100 | if (s2io_card_up(sp)) { | ||
8101 | printk(KERN_ERR "s2io: " | ||
8102 | "Can't bring device back up after reset.\n"); | ||
8103 | return; | ||
8104 | } | ||
8105 | |||
8106 | if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) { | ||
8107 | s2io_card_down(sp); | ||
8108 | printk(KERN_ERR "s2io: " | ||
8109 | "Can't resetore mac addr after reset.\n"); | ||
8110 | return; | ||
8111 | } | ||
8112 | } | ||
8113 | |||
8114 | netif_device_attach(netdev); | ||
8115 | netif_wake_queue(netdev); | ||
8116 | } | ||