mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
igb: Add mechanism for detecting latched hardware Rx timestamp
Add a check against possible Rx timestamp freezing in the hardware via watchdog mechanism. This situation can occur when an Rx timestamp has been latched, but the packet has been dropped because the Rx ring is full. Whenever a packet comes in that should be timestamped, the Rx timestamp gets latched into the hardware registers and we will store the jiffy value in the rx_ring. The watchdog will keep track of his own jiffy timer whenever there is no valid timestamp in the registers. If the watchdog detects a valid timestamp in the registers, meaning that no Rx packet has consumed it yet, it will check which time is most recent: the last time in the watchdog or any time in the rx_rings. If the most recent "event" was more than 5 seconds ago, it will flush the Rx timestamp and print a warning message to the syslog. Cc: Richard Cochran <richardcochran@gmail.com> Signed-off-by: Matthew Vick <matthew.vick@intel.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Jacob Keller <Jacob.e.keller@intel.com> Tested-by: Aaron Brown <aaron.f.brown@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
428f1f7151
commit
fc58075116
@ -221,6 +221,7 @@ struct igb_ring {
|
||||
struct igb_tx_buffer *tx_buffer_info;
|
||||
struct igb_rx_buffer *rx_buffer_info;
|
||||
};
|
||||
unsigned long last_rx_timestamp;
|
||||
void *desc; /* descriptor ring memory */
|
||||
unsigned long flags; /* ring specific flags */
|
||||
void __iomem *tail; /* pointer to ring tail register */
|
||||
@ -415,10 +416,12 @@ struct igb_adapter {
|
||||
struct work_struct ptp_tx_work;
|
||||
struct sk_buff *ptp_tx_skb;
|
||||
unsigned long ptp_tx_start;
|
||||
unsigned long last_rx_ptp_check;
|
||||
spinlock_t tmreg_lock;
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
u32 tx_hwtstamp_timeouts;
|
||||
u32 rx_hwtstamp_cleared;
|
||||
|
||||
char fw_version[32];
|
||||
#ifdef CONFIG_IGB_HWMON
|
||||
@ -486,6 +489,7 @@ extern void igb_ptp_init(struct igb_adapter *adapter);
|
||||
extern void igb_ptp_stop(struct igb_adapter *adapter);
|
||||
extern void igb_ptp_reset(struct igb_adapter *adapter);
|
||||
extern void igb_ptp_tx_work(struct work_struct *work);
|
||||
extern void igb_ptp_rx_hang(struct igb_adapter *adapter);
|
||||
extern void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
|
||||
extern void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
|
||||
struct sk_buff *skb);
|
||||
|
@ -93,6 +93,7 @@ static const struct igb_stats igb_gstrings_stats[] = {
|
||||
IGB_STAT("os2bmc_tx_by_host", stats.o2bspc),
|
||||
IGB_STAT("os2bmc_rx_by_host", stats.b2ogprc),
|
||||
IGB_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
|
||||
IGB_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
|
||||
};
|
||||
|
||||
#define IGB_NETDEV_STAT(_net_stat) { \
|
||||
|
@ -3991,6 +3991,7 @@ static void igb_watchdog_task(struct work_struct *work)
|
||||
}
|
||||
|
||||
igb_spoof_check(adapter);
|
||||
igb_ptp_rx_hang(adapter);
|
||||
|
||||
/* Reset the timer */
|
||||
if (!test_bit(__IGB_DOWN, &adapter->state))
|
||||
|
@ -428,6 +428,51 @@ static void igb_ptp_overflow_check(struct work_struct *work)
|
||||
IGB_SYSTIM_OVERFLOW_PERIOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_rx_hang - detect error case when Rx timestamp registers latched
|
||||
* @adapter: private network adapter structure
|
||||
*
|
||||
* This watchdog task is scheduled to detect error case where hardware has
|
||||
* dropped an Rx packet that was timestamped when the ring is full. The
|
||||
* particular error is rare but leaves the device in a state unable to timestamp
|
||||
* any future packets.
|
||||
*/
|
||||
void igb_ptp_rx_hang(struct igb_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct igb_ring *rx_ring;
|
||||
u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL);
|
||||
unsigned long rx_event;
|
||||
int n;
|
||||
|
||||
if (hw->mac.type != e1000_82576)
|
||||
return;
|
||||
|
||||
/* If we don't have a valid timestamp in the registers, just update the
|
||||
* timeout counter and exit
|
||||
*/
|
||||
if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) {
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine the most recent watchdog or rx_timestamp event */
|
||||
rx_event = adapter->last_rx_ptp_check;
|
||||
for (n = 0; n < adapter->num_rx_queues; n++) {
|
||||
rx_ring = adapter->rx_ring[n];
|
||||
if (time_after(rx_ring->last_rx_timestamp, rx_event))
|
||||
rx_event = rx_ring->last_rx_timestamp;
|
||||
}
|
||||
|
||||
/* Only need to read the high RXSTMP register to clear the lock */
|
||||
if (time_is_before_jiffies(rx_event + 5 * HZ)) {
|
||||
rd32(E1000_RXSTMPH);
|
||||
adapter->last_rx_ptp_check = jiffies;
|
||||
adapter->rx_hwtstamp_cleared++;
|
||||
dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp
|
||||
* @adapter: Board private structure.
|
||||
|
Loading…
Reference in New Issue
Block a user