diff options
-rw-r--r-- | drivers/net/e1000e/e1000.h | 1 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 46 |
2 files changed, 39 insertions, 8 deletions
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 5ac8675b0c58..c9fcef7f8462 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -364,6 +364,7 @@ struct e1000_adapter { | |||
364 | struct work_struct downshift_task; | 364 | struct work_struct downshift_task; |
365 | struct work_struct update_phy_task; | 365 | struct work_struct update_phy_task; |
366 | struct work_struct led_blink_task; | 366 | struct work_struct led_blink_task; |
367 | struct work_struct print_hang_task; | ||
367 | }; | 368 | }; |
368 | 369 | ||
369 | struct e1000_info { | 370 | struct e1000_info { |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 39f01d998b4d..11a527484e18 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -544,15 +544,27 @@ static void e1000_put_txbuf(struct e1000_adapter *adapter, | |||
544 | buffer_info->time_stamp = 0; | 544 | buffer_info->time_stamp = 0; |
545 | } | 545 | } |
546 | 546 | ||
547 | static void e1000_print_tx_hang(struct e1000_adapter *adapter) | 547 | static void e1000_print_hw_hang(struct work_struct *work) |
548 | { | 548 | { |
549 | struct e1000_adapter *adapter = container_of(work, | ||
550 | struct e1000_adapter, | ||
551 | print_hang_task); | ||
549 | struct e1000_ring *tx_ring = adapter->tx_ring; | 552 | struct e1000_ring *tx_ring = adapter->tx_ring; |
550 | unsigned int i = tx_ring->next_to_clean; | 553 | unsigned int i = tx_ring->next_to_clean; |
551 | unsigned int eop = tx_ring->buffer_info[i].next_to_watch; | 554 | unsigned int eop = tx_ring->buffer_info[i].next_to_watch; |
552 | struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); | 555 | struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop); |
556 | struct e1000_hw *hw = &adapter->hw; | ||
557 | u16 phy_status, phy_1000t_status, phy_ext_status; | ||
558 | u16 pci_status; | ||
559 | |||
560 | e1e_rphy(hw, PHY_STATUS, &phy_status); | ||
561 | e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status); | ||
562 | e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status); | ||
553 | 563 | ||
554 | /* detected Tx unit hang */ | 564 | pci_read_config_word(adapter->pdev, PCI_STATUS, &pci_status); |
555 | e_err("Detected Tx Unit Hang:\n" | 565 | |
566 | /* detected Hardware unit hang */ | ||
567 | e_err("Detected Hardware Unit Hang:\n" | ||
556 | " TDH <%x>\n" | 568 | " TDH <%x>\n" |
557 | " TDT <%x>\n" | 569 | " TDT <%x>\n" |
558 | " next_to_use <%x>\n" | 570 | " next_to_use <%x>\n" |
@@ -561,7 +573,12 @@ static void e1000_print_tx_hang(struct e1000_adapter *adapter) | |||
561 | " time_stamp <%lx>\n" | 573 | " time_stamp <%lx>\n" |
562 | " next_to_watch <%x>\n" | 574 | " next_to_watch <%x>\n" |
563 | " jiffies <%lx>\n" | 575 | " jiffies <%lx>\n" |
564 | " next_to_watch.status <%x>\n", | 576 | " next_to_watch.status <%x>\n" |
577 | "MAC Status <%x>\n" | ||
578 | "PHY Status <%x>\n" | ||
579 | "PHY 1000BASE-T Status <%x>\n" | ||
580 | "PHY Extended Status <%x>\n" | ||
581 | "PCI Status <%x>\n", | ||
565 | readl(adapter->hw.hw_addr + tx_ring->head), | 582 | readl(adapter->hw.hw_addr + tx_ring->head), |
566 | readl(adapter->hw.hw_addr + tx_ring->tail), | 583 | readl(adapter->hw.hw_addr + tx_ring->tail), |
567 | tx_ring->next_to_use, | 584 | tx_ring->next_to_use, |
@@ -569,7 +586,12 @@ static void e1000_print_tx_hang(struct e1000_adapter *adapter) | |||
569 | tx_ring->buffer_info[eop].time_stamp, | 586 | tx_ring->buffer_info[eop].time_stamp, |
570 | eop, | 587 | eop, |
571 | jiffies, | 588 | jiffies, |
572 | eop_desc->upper.fields.status); | 589 | eop_desc->upper.fields.status, |
590 | er32(STATUS), | ||
591 | phy_status, | ||
592 | phy_1000t_status, | ||
593 | phy_ext_status, | ||
594 | pci_status); | ||
573 | } | 595 | } |
574 | 596 | ||
575 | /** | 597 | /** |
@@ -643,14 +665,16 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) | |||
643 | } | 665 | } |
644 | 666 | ||
645 | if (adapter->detect_tx_hung) { | 667 | if (adapter->detect_tx_hung) { |
646 | /* Detect a transmit hang in hardware, this serializes the | 668 | /* |
647 | * check with the clearing of time_stamp and movement of i */ | 669 | * Detect a transmit hang in hardware, this serializes the |
670 | * check with the clearing of time_stamp and movement of i | ||
671 | */ | ||
648 | adapter->detect_tx_hung = 0; | 672 | adapter->detect_tx_hung = 0; |
649 | if (tx_ring->buffer_info[i].time_stamp && | 673 | if (tx_ring->buffer_info[i].time_stamp && |
650 | time_after(jiffies, tx_ring->buffer_info[i].time_stamp | 674 | time_after(jiffies, tx_ring->buffer_info[i].time_stamp |
651 | + (adapter->tx_timeout_factor * HZ)) | 675 | + (adapter->tx_timeout_factor * HZ)) |
652 | && !(er32(STATUS) & E1000_STATUS_TXOFF)) { | 676 | && !(er32(STATUS) & E1000_STATUS_TXOFF)) { |
653 | e1000_print_tx_hang(adapter); | 677 | schedule_work(&adapter->print_hang_task); |
654 | netif_stop_queue(netdev); | 678 | netif_stop_queue(netdev); |
655 | } | 679 | } |
656 | } | 680 | } |
@@ -5118,6 +5142,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
5118 | INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); | 5142 | INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); |
5119 | INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); | 5143 | INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround); |
5120 | INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); | 5144 | INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task); |
5145 | INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang); | ||
5121 | 5146 | ||
5122 | /* Initialize link parameters. User can change them with ethtool */ | 5147 | /* Initialize link parameters. User can change them with ethtool */ |
5123 | adapter->hw.mac.autoneg = 1; | 5148 | adapter->hw.mac.autoneg = 1; |
@@ -5241,6 +5266,11 @@ static void __devexit e1000_remove(struct pci_dev *pdev) | |||
5241 | del_timer_sync(&adapter->watchdog_timer); | 5266 | del_timer_sync(&adapter->watchdog_timer); |
5242 | del_timer_sync(&adapter->phy_info_timer); | 5267 | del_timer_sync(&adapter->phy_info_timer); |
5243 | 5268 | ||
5269 | cancel_work_sync(&adapter->reset_task); | ||
5270 | cancel_work_sync(&adapter->watchdog_task); | ||
5271 | cancel_work_sync(&adapter->downshift_task); | ||
5272 | cancel_work_sync(&adapter->update_phy_task); | ||
5273 | cancel_work_sync(&adapter->print_hang_task); | ||
5244 | flush_scheduled_work(); | 5274 | flush_scheduled_work(); |
5245 | 5275 | ||
5246 | /* | 5276 | /* |