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"
" 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,
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);
}
/**
}
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);
}
}
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;
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();
/*