diff options
author | Linas Vepstas <linas@austin.ibm.com> | 2007-05-14 19:37:30 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-08 22:16:38 -0400 |
commit | d796fdb708fc5b10112934cba43e832c36ce4923 (patch) | |
tree | 433063c793bd095721bcbb811cf8460ff3ec228f /drivers/net | |
parent | bd5824f138153f407e300728919e814ab7dcfadb (diff) |
s2io: add PCI error recovery support
This patch adds PCI error recovery support to the
s2io 10-Gigabit ethernet device driver. Third revision,
blocks interrupts and the watchdog.
Tested, seems to work well.
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Acked-by: Ramkrishna Vepa <Ramkrishna.Vepa@neterion.com>
Cc: Raghavendra Koushik <raghavendra.koushik@neterion.com>
Cc: Wen Xiong <wenxiong@us.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/s2io.c | 116 | ||||
-rw-r--r-- | drivers/net/s2io.h | 5 |
2 files changed, 116 insertions, 5 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 09078ff84cd2..392ad4a42291 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) { |
@@ -4314,6 +4326,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) | |||
4314 | struct mac_info *mac_control; | 4326 | struct mac_info *mac_control; |
4315 | struct config_param *config; | 4327 | struct config_param *config; |
4316 | 4328 | ||
4329 | /* Pretend we handled any irq's from a disconnected card */ | ||
4330 | if (pci_channel_offline(sp->pdev)) | ||
4331 | return IRQ_NONE; | ||
4332 | |||
4317 | atomic_inc(&sp->isr_cnt); | 4333 | atomic_inc(&sp->isr_cnt); |
4318 | mac_control = &sp->mac_control; | 4334 | mac_control = &sp->mac_control; |
4319 | config = &sp->config; | 4335 | config = &sp->config; |
@@ -6569,7 +6585,7 @@ static void s2io_rem_isr(struct s2io_nic * sp) | |||
6569 | } while(cnt < 5); | 6585 | } while(cnt < 5); |
6570 | } | 6586 | } |
6571 | 6587 | ||
6572 | static void s2io_card_down(struct s2io_nic * sp) | 6588 | static void do_s2io_card_down(struct s2io_nic * sp, int do_io) |
6573 | { | 6589 | { |
6574 | int cnt = 0; | 6590 | int cnt = 0; |
6575 | struct XENA_dev_config __iomem *bar0 = sp->bar0; | 6591 | struct XENA_dev_config __iomem *bar0 = sp->bar0; |
@@ -6584,7 +6600,8 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6584 | atomic_set(&sp->card_state, CARD_DOWN); | 6600 | atomic_set(&sp->card_state, CARD_DOWN); |
6585 | 6601 | ||
6586 | /* disable Tx and Rx traffic on the NIC */ | 6602 | /* disable Tx and Rx traffic on the NIC */ |
6587 | stop_nic(sp); | 6603 | if (do_io) |
6604 | stop_nic(sp); | ||
6588 | 6605 | ||
6589 | s2io_rem_isr(sp); | 6606 | s2io_rem_isr(sp); |
6590 | 6607 | ||
@@ -6592,7 +6609,7 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6592 | tasklet_kill(&sp->task); | 6609 | tasklet_kill(&sp->task); |
6593 | 6610 | ||
6594 | /* Check if the device is Quiescent and then Reset the NIC */ | 6611 | /* Check if the device is Quiescent and then Reset the NIC */ |
6595 | do { | 6612 | while(do_io) { |
6596 | /* As per the HW requirement we need to replenish the | 6613 | /* As per the HW requirement we need to replenish the |
6597 | * receive buffer to avoid the ring bump. Since there is | 6614 | * receive buffer to avoid the ring bump. Since there is |
6598 | * no intention of processing the Rx frame at this pointwe are | 6615 | * no intention of processing the Rx frame at this pointwe are |
@@ -6617,8 +6634,9 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6617 | (unsigned long long) val64); | 6634 | (unsigned long long) val64); |
6618 | break; | 6635 | break; |
6619 | } | 6636 | } |
6620 | } while (1); | 6637 | } |
6621 | s2io_reset(sp); | 6638 | if (do_io) |
6639 | s2io_reset(sp); | ||
6622 | 6640 | ||
6623 | spin_lock_irqsave(&sp->tx_lock, flags); | 6641 | spin_lock_irqsave(&sp->tx_lock, flags); |
6624 | /* Free all Tx buffers */ | 6642 | /* Free all Tx buffers */ |
@@ -6633,6 +6651,11 @@ static void s2io_card_down(struct s2io_nic * sp) | |||
6633 | clear_bit(0, &(sp->link_state)); | 6651 | clear_bit(0, &(sp->link_state)); |
6634 | } | 6652 | } |
6635 | 6653 | ||
6654 | static void s2io_card_down(struct s2io_nic * sp) | ||
6655 | { | ||
6656 | do_s2io_card_down(sp, 1); | ||
6657 | } | ||
6658 | |||
6636 | static int s2io_card_up(struct s2io_nic * sp) | 6659 | static int s2io_card_up(struct s2io_nic * sp) |
6637 | { | 6660 | { |
6638 | int i, ret = 0; | 6661 | int i, ret = 0; |
@@ -8010,3 +8033,86 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, | |||
8010 | sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; | 8033 | sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; |
8011 | return; | 8034 | return; |
8012 | } | 8035 | } |
8036 | |||
8037 | /** | ||
8038 | * s2io_io_error_detected - called when PCI error is detected | ||
8039 | * @pdev: Pointer to PCI device | ||
8040 | * @state: The current pci conneection state | ||
8041 | * | ||
8042 | * This function is called after a PCI bus error affecting | ||
8043 | * this device has been detected. | ||
8044 | */ | ||
8045 | static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, | ||
8046 | pci_channel_state_t state) | ||
8047 | { | ||
8048 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8049 | struct s2io_nic *sp = netdev->priv; | ||
8050 | |||
8051 | netif_device_detach(netdev); | ||
8052 | |||
8053 | if (netif_running(netdev)) { | ||
8054 | /* Bring down the card, while avoiding PCI I/O */ | ||
8055 | do_s2io_card_down(sp, 0); | ||
8056 | sp->device_close_flag = TRUE; /* Device is shut down. */ | ||
8057 | } | ||
8058 | pci_disable_device(pdev); | ||
8059 | |||
8060 | return PCI_ERS_RESULT_NEED_RESET; | ||
8061 | } | ||
8062 | |||
8063 | /** | ||
8064 | * s2io_io_slot_reset - called after the pci bus has been reset. | ||
8065 | * @pdev: Pointer to PCI device | ||
8066 | * | ||
8067 | * Restart the card from scratch, as if from a cold-boot. | ||
8068 | * At this point, the card has exprienced a hard reset, | ||
8069 | * followed by fixups by BIOS, and has its config space | ||
8070 | * set up identically to what it was at cold boot. | ||
8071 | */ | ||
8072 | static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) | ||
8073 | { | ||
8074 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8075 | struct s2io_nic *sp = netdev->priv; | ||
8076 | |||
8077 | if (pci_enable_device(pdev)) { | ||
8078 | printk(KERN_ERR "s2io: " | ||
8079 | "Cannot re-enable PCI device after reset.\n"); | ||
8080 | return PCI_ERS_RESULT_DISCONNECT; | ||
8081 | } | ||
8082 | |||
8083 | pci_set_master(pdev); | ||
8084 | s2io_reset(sp); | ||
8085 | |||
8086 | return PCI_ERS_RESULT_RECOVERED; | ||
8087 | } | ||
8088 | |||
8089 | /** | ||
8090 | * s2io_io_resume - called when traffic can start flowing again. | ||
8091 | * @pdev: Pointer to PCI device | ||
8092 | * | ||
8093 | * This callback is called when the error recovery driver tells | ||
8094 | * us that its OK to resume normal operation. | ||
8095 | */ | ||
8096 | static void s2io_io_resume(struct pci_dev *pdev) | ||
8097 | { | ||
8098 | struct net_device *netdev = pci_get_drvdata(pdev); | ||
8099 | struct s2io_nic *sp = netdev->priv; | ||
8100 | |||
8101 | if (netif_running(netdev)) { | ||
8102 | if (s2io_card_up(sp)) { | ||
8103 | printk(KERN_ERR "s2io: " | ||
8104 | "Can't bring device back up after reset.\n"); | ||
8105 | return; | ||
8106 | } | ||
8107 | |||
8108 | if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) { | ||
8109 | s2io_card_down(sp); | ||
8110 | printk(KERN_ERR "s2io: " | ||
8111 | "Can't resetore mac addr after reset.\n"); | ||
8112 | return; | ||
8113 | } | ||
8114 | } | ||
8115 | |||
8116 | netif_device_attach(netdev); | ||
8117 | netif_wake_queue(netdev); | ||
8118 | } | ||
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 54baa0b8ec7c..b9b660702abd 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h | |||
@@ -1052,6 +1052,11 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, | |||
1052 | struct sk_buff *skb, u32 tcp_len); | 1052 | struct sk_buff *skb, u32 tcp_len); |
1053 | static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring); | 1053 | static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring); |
1054 | 1054 | ||
1055 | static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, | ||
1056 | pci_channel_state_t state); | ||
1057 | static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev); | ||
1058 | static void s2io_io_resume(struct pci_dev *pdev); | ||
1059 | |||
1055 | #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size | 1060 | #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size |
1056 | #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size | 1061 | #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size |
1057 | #define s2io_offload_type(skb) skb_shinfo(skb)->gso_type | 1062 | #define s2io_offload_type(skb) skb_shinfo(skb)->gso_type |