aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/e1000e/e1000.h1
-rw-r--r--drivers/net/e1000e/netdev.c46
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 {
struct work_struct downshift_task;
struct work_struct update_phy_task;
struct work_struct led_blink_task;
+ struct work_struct print_hang_task;
};
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,
buffer_info->time_stamp = 0;
}
-static void e1000_print_tx_hang(struct e1000_adapter *adapter)
+static void e1000_print_hw_hang(struct work_struct *work)
{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter,
+ print_hang_task);
struct e1000_ring *tx_ring = adapter->tx_ring;
unsigned int i = tx_ring->next_to_clean;
unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 phy_status, phy_1000t_status, phy_ext_status;
+ u16 pci_status;
+
+ e1e_rphy(hw, PHY_STATUS, &phy_status);
+ e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status);
+ e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status);
- /* detected Tx unit hang */
- e_err("Detected Tx Unit Hang:\n"
+ pci_read_config_word(adapter->pdev, PCI_STATUS, &pci_status);
+
+ /* detected Hardware unit hang */
+ e_err("Detected Hardware Unit Hang:\n"
" TDH <%x>\n"
" TDT <%x>\n"
" next_to_use <%x>\n"
@@ -561,7 +573,12 @@ static void e1000_print_tx_hang(struct e1000_adapter *adapter)
" time_stamp <%lx>\n"
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
- " next_to_watch.status <%x>\n",
+ " next_to_watch.status <%x>\n"
+ "MAC Status <%x>\n"
+ "PHY Status <%x>\n"
+ "PHY 1000BASE-T Status <%x>\n"
+ "PHY Extended Status <%x>\n"
+ "PCI Status <%x>\n",
readl(adapter->hw.hw_addr + tx_ring->head),
readl(adapter->hw.hw_addr + tx_ring->tail),
tx_ring->next_to_use,
@@ -569,7 +586,12 @@ static void e1000_print_tx_hang(struct e1000_adapter *adapter)
tx_ring->buffer_info[eop].time_stamp,
eop,
jiffies,
- eop_desc->upper.fields.status);
+ eop_desc->upper.fields.status,
+ er32(STATUS),
+ phy_status,
+ phy_1000t_status,
+ phy_ext_status,
+ pci_status);
}
/**
@@ -643,14 +665,16 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
if (adapter->detect_tx_hung) {
- /* Detect a transmit hang in hardware, this serializes the
- * check with the clearing of time_stamp and movement of i */
+ /*
+ * Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i
+ */
adapter->detect_tx_hung = 0;
if (tx_ring->buffer_info[i].time_stamp &&
time_after(jiffies, tx_ring->buffer_info[i].time_stamp
+ (adapter->tx_timeout_factor * HZ))
&& !(er32(STATUS) & E1000_STATUS_TXOFF)) {
- e1000_print_tx_hang(adapter);
+ schedule_work(&adapter->print_hang_task);
netif_stop_queue(netdev);
}
}
@@ -5118,6 +5142,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
+ INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang);
/* Initialize link parameters. User can change them with ethtool */
adapter->hw.mac.autoneg = 1;
@@ -5241,6 +5266,11 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
+ cancel_work_sync(&adapter->reset_task);
+ cancel_work_sync(&adapter->watchdog_task);
+ cancel_work_sync(&adapter->downshift_task);
+ cancel_work_sync(&adapter->update_phy_task);
+ cancel_work_sync(&adapter->print_hang_task);
flush_scheduled_work();
/*