/** * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung * @vsi: The VSI with the rings relevant to 1588 * * 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 i40e_ptp_rx_hang(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; struct i40e_ring *rx_ring; unsigned long rx_event; u32 prttsyn_stat; int n; /* Since we cannot turn off the Rx timestamp logic if the device is * configured for Tx timestamping, we check if Rx timestamping is * configured. We don't want to spuriously warn about Rx timestamp * hangs if we don't care about the timestamps. */ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); /* Unless all four receive timestamp registers are latched, we are not * concerned about a possible PTP Rx hang, so just update the timeout * counter and exit. */ if (!(prttsyn_stat & ((I40E_PRTTSYN_STAT_1_RXT0_MASK << I40E_PRTTSYN_STAT_1_RXT0_SHIFT) | (I40E_PRTTSYN_STAT_1_RXT1_MASK << I40E_PRTTSYN_STAT_1_RXT1_SHIFT) | (I40E_PRTTSYN_STAT_1_RXT2_MASK << I40E_PRTTSYN_STAT_1_RXT2_SHIFT) | (I40E_PRTTSYN_STAT_1_RXT3_MASK << I40E_PRTTSYN_STAT_1_RXT3_SHIFT)))) { pf->last_rx_ptp_check = jiffies; return; } /* Determine the most recent watchdog or rx_timestamp event. */ rx_event = pf->last_rx_ptp_check; for (n = 0; n < vsi->num_queue_pairs; n++) { rx_ring = vsi->rx_rings[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(hw, I40E_PRTTSYN_RXTIME_H(0)); rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); pf->last_rx_ptp_check = jiffies; pf->rx_hwtstamp_cleared++; dev_warn(&vsi->back->pdev->dev, "%s: clearing Rx timestamp hang\n", __func__); } }
/** * i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp * @pf: Board private structure * @skb: Particular skb to send timestamp with * @index: Index into the receive timestamp registers for the timestamp * * The XL710 receives a notification in the receive descriptor with an offset * into the set of RXTIME registers where the timestamp is for that skb. This * function goes and fetches the receive timestamp from that offset, if a valid * one exists. The RXTIME registers are in ns, so we must convert the result * first. **/ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) { u32 prttsyn_stat, hi, lo; struct i40e_hw *hw; u64 ns; /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; hw = &pf->hw; prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); if (!(prttsyn_stat & BIT(index))) return; lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index)); ns = (((u64)hi) << 32) | lo; i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns); }
/** * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung * @pf: The PF private data structure * @vsi: The VSI with the rings relevant to 1588 * * 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 i40e_ptp_rx_hang(struct i40e_pf *pf) { struct i40e_hw *hw = &pf->hw; unsigned int i, cleared = 0; /* Since we cannot turn off the Rx timestamp logic if the device is * configured for Tx timestamping, we check if Rx timestamping is * configured. We don't want to spuriously warn about Rx timestamp * hangs if we don't care about the timestamps. */ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; spin_lock_bh(&pf->ptp_rx_lock); /* Update current latch times for Rx events */ i40e_ptp_get_rx_events(pf); /* Check all the currently latched Rx events and see whether they have * been latched for over a second. It is assumed that any timestamp * should have been cleared within this time, or else it was captured * for a dropped frame that the driver never received. Thus, we will * clear any timestamp that has been latched for over 1 second. */ for (i = 0; i < 4; i++) { if ((pf->latch_event_flags & BIT(i)) && time_is_before_jiffies(pf->latch_events[i] + HZ)) { rd32(hw, I40E_PRTTSYN_RXTIME_H(i)); pf->latch_event_flags &= ~BIT(i); cleared++; } } spin_unlock_bh(&pf->ptp_rx_lock); /* Log a warning if more than 2 timestamps got dropped in the same * check. We don't want to warn about all drops because it can occur * in normal scenarios such as PTP frames on multicast addresses we * aren't listening to. However, administrator should know if this is * the reason packets aren't receiving timestamps. */ if (cleared > 2) dev_dbg(&pf->pdev->dev, "Dropped %d missed RXTIME timestamp events\n", cleared); /* Finally, update the rx_hwtstamp_cleared counter */ pf->rx_hwtstamp_cleared += cleared; }
/** * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung * @vsi: The VSI with the rings relevant to 1588 * * 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 i40e_ptp_rx_hang(struct i40e_vsi *vsi) { struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; int i; /* Since we cannot turn off the Rx timestamp logic if the device is * configured for Tx timestamping, we check if Rx timestamping is * configured. We don't want to spuriously warn about Rx timestamp * hangs if we don't care about the timestamps. */ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; spin_lock_bh(&pf->ptp_rx_lock); /* Update current latch times for Rx events */ i40e_ptp_get_rx_events(pf); /* Check all the currently latched Rx events and see whether they have * been latched for over a second. It is assumed that any timestamp * should have been cleared within this time, or else it was captured * for a dropped frame that the driver never received. Thus, we will * clear any timestamp that has been latched for over 1 second. */ for (i = 0; i < 4; i++) { if ((pf->latch_event_flags & BIT(i)) && time_is_before_jiffies(pf->latch_events[i] + HZ)) { rd32(hw, I40E_PRTTSYN_RXTIME_H(i)); pf->latch_event_flags &= ~BIT(i); pf->rx_hwtstamp_cleared++; dev_warn(&pf->pdev->dev, "Clearing a missed Rx timestamp event for RXTIME[%d]\n", i); } } spin_unlock_bh(&pf->ptp_rx_lock); }
/** * i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp * @pf: Board private structure * @skb: Particular skb to send timestamp with * @index: Index into the receive timestamp registers for the timestamp * * The XL710 receives a notification in the receive descriptor with an offset * into the set of RXTIME registers where the timestamp is for that skb. This * function goes and fetches the receive timestamp from that offset, if a valid * one exists. The RXTIME registers are in ns, so we must convert the result * first. **/ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) { u32 prttsyn_stat, hi, lo; struct i40e_hw *hw; u64 ns; /* Since we cannot turn off the Rx timestamp logic if the device is * doing Tx timestamping, check if Rx timestamping is configured. */ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx) return; hw = &pf->hw; spin_lock_bh(&pf->ptp_rx_lock); /* Get current Rx events and update latch times */ prttsyn_stat = i40e_ptp_get_rx_events(pf); /* TODO: Should we warn about missing Rx timestamp event? */ if (!(prttsyn_stat & BIT(index))) { spin_unlock_bh(&pf->ptp_rx_lock); return; } /* Clear the latched event since we're about to read its register */ pf->latch_event_flags &= ~BIT(index); lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index)); spin_unlock_bh(&pf->ptp_rx_lock); ns = (((u64)hi) << 32) | lo; i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns); }
/** * i40e_ptp_set_timestamp_mode - setup hardware for requested timestamp mode * @pf: Board private structure * @config: hwtstamp settings requested or saved * * Control hardware registers to enter the specific mode requested by the * user. Also used during reset path to ensure that timestamp settings are * maintained. * * Note: modifies config in place, and may update the requested mode to be * more broad if the specific filter is not directly supported. **/ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, struct hwtstamp_config *config) { struct i40e_hw *hw = &pf->hw; u32 tsyntype, regval; /* Reserved for future extensions. */ if (config->flags) return -EINVAL; switch (config->tx_type) { case HWTSTAMP_TX_OFF: pf->ptp_tx = false; break; case HWTSTAMP_TX_ON: pf->ptp_tx = true; break; default: return -ERANGE; } switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: pf->ptp_rx = false; /* We set the type to V1, but do not enable UDP packet * recognition. In this way, we should be as close to * disabling PTP Rx timestamps as possible since V1 packets * are always UDP, since L2 packets are a V2 feature. */ tsyntype = I40E_PRTTSYN_CTL1_TSYNTYPE_V1; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) return -ERANGE; pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V1 | I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) return -ERANGE; /* fall through */ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V2; if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE) { tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; } else { config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; } break; case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: default: return -ERANGE; } /* Clear out all 1588-related registers to clear and unlatch them. */ spin_lock_bh(&pf->ptp_rx_lock); rd32(hw, I40E_PRTTSYN_STAT_0); rd32(hw, I40E_PRTTSYN_TXTIME_H); rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); pf->latch_event_flags = 0; spin_unlock_bh(&pf->ptp_rx_lock); /* Enable/disable the Tx timestamp interrupt based on user input. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); if (pf->ptp_tx) regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; else regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; wr32(hw, I40E_PRTTSYN_CTL0, regval); regval = rd32(hw, I40E_PFINT_ICR0_ENA); if (pf->ptp_tx) regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; else regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, regval); /* Although there is no simple on/off switch for Rx, we "disable" Rx * timestamps by setting to V1 only mode and clear the UDP * recognition. This ought to disable all PTP Rx timestamps as V1 * packets are always over UDP. Note that software is configured to * ignore Rx timestamps via the pf->ptp_rx flag. */ regval = rd32(hw, I40E_PRTTSYN_CTL1); /* clear everything but the enable bit */ regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; /* now enable bits for desired Rx timestamps */ regval |= tsyntype; wr32(hw, I40E_PRTTSYN_CTL1, regval); return 0; }
/** * i40e_ptp_set_timestamp_mode - setup hardware for requested timestamp mode * @pf: Board private structure * @config: hwtstamp settings requested or saved * * Control hardware registers to enter the specific mode requested by the * user. Also used during reset path to ensure that timestamp settings are * maintained. * * Note: modifies config in place, and may update the requested mode to be * more broad if the specific filter is not directly supported. **/ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf, struct hwtstamp_config *config) { struct i40e_hw *hw = &pf->hw; u32 pf_id, tsyntype, regval; /* Reserved for future extensions. */ if (config->flags) return -EINVAL; /* Confirm that 1588 is supported on this PF. */ pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> I40E_PRTTSYN_CTL0_PF_ID_SHIFT; if (hw->pf_id != pf_id) { dev_err(&pf->pdev->dev, "PF %d attempted to control timestamp mode on port %d, which is owned by PF %d\n", hw->pf_id, hw->port, pf_id); return -EPERM; } switch (config->tx_type) { case HWTSTAMP_TX_OFF: pf->ptp_tx = false; break; case HWTSTAMP_TX_ON: pf->ptp_tx = true; break; default: return -ERANGE; } switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: pf->ptp_rx = false; tsyntype = 0; break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V1 | I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: pf->ptp_rx = true; tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | I40E_PRTTSYN_CTL1_TSYNTYPE_V2 | I40E_PRTTSYN_CTL1_UDP_ENA_MASK; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; case HWTSTAMP_FILTER_ALL: default: return -ERANGE; } /* Clear out all 1588-related registers to clear and unlatch them. */ rd32(hw, I40E_PRTTSYN_STAT_0); rd32(hw, I40E_PRTTSYN_TXTIME_H); rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); /* Enable/disable the Tx timestamp interrupt based on user input. */ regval = rd32(hw, I40E_PRTTSYN_CTL0); if (pf->ptp_tx) regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; else regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; wr32(hw, I40E_PRTTSYN_CTL0, regval); regval = rd32(hw, I40E_PFINT_ICR0_ENA); if (pf->ptp_tx) regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; else regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; wr32(hw, I40E_PFINT_ICR0_ENA, regval); /* There is no simple on/off switch for Rx. To "disable" Rx support, * ignore any received timestamps, rather than turn off the clock. */ if (pf->ptp_rx) { regval = rd32(hw, I40E_PRTTSYN_CTL1); /* clear everything but the enable bit */ regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; /* now enable bits for desired Rx timestamps */ regval |= tsyntype; wr32(hw, I40E_PRTTSYN_CTL1, regval); } return 0; }