/** * wx_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state * @wx: the private board structure * * This function should be called whenever the state related to a Tx timestamp * needs to be cleared. This helps ensure that all related bits are reset for * the next Tx timestamp event.
*/ staticvoid wx_ptp_clear_tx_timestamp(struct wx *wx)
{
rd32ptp(wx, WX_TSC_1588_STMPH); if (wx->ptp_tx_skb) {
dev_kfree_skb_any(wx->ptp_tx_skb);
wx->ptp_tx_skb = NULL;
}
clear_bit_unlock(WX_STATE_PTP_TX_IN_PROGRESS, wx->state);
}
/** * wx_ptp_convert_to_hwtstamp - convert register value to hw timestamp * @wx: private board structure * @hwtstamp: stack timestamp structure * @timestamp: unsigned 64bit system time value * * We need to convert the adapter's RX/TXSTMP registers into a hwtstamp value * which can be used by the stack's ptp functions. * * The lock is used to protect consistency of the cyclecounter and the SYSTIME * registers. However, it does not need to protect against the Rx or Tx * timestamp registers, as there can't be a new timestamp until the old one is * unlatched by reading. * * In addition to the timestamp in hardware, some controllers need a software * overflow cyclecounter, and this function takes this into account as well.
**/ staticvoid wx_ptp_convert_to_hwtstamp(struct wx *wx, struct skb_shared_hwtstamps *hwtstamp,
u64 timestamp)
{
u64 ns;
/** * wx_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @wx: the private board struct * * if the timestamp is valid, we convert it into the timecounter ns * value, then store that result into the shhwtstamps structure which * is passed up the network stack
*/ staticvoid wx_ptp_tx_hwtstamp(struct wx *wx)
{ struct skb_shared_hwtstamps shhwtstamps; struct sk_buff *skb = wx->ptp_tx_skb;
u64 regval = 0;
/* we have to have a valid skb to poll for a timestamp */ if (!wx->ptp_tx_skb) {
wx_ptp_clear_tx_timestamp(wx); return 0;
}
/* stop polling once we have a valid timestamp */
tsynctxctl = rd32ptp(wx, WX_TSC_1588_CTL); if (tsynctxctl & WX_TSC_1588_CTL_VALID) {
wx_ptp_tx_hwtstamp(wx); return 0;
}
return -1;
}
/** * wx_ptp_overflow_check - watchdog task to detect SYSTIME overflow * @wx: pointer to wx struct * * this watchdog task periodically reads the timecounter * in order to prevent missing when the system time registers wrap * around. This needs to be run approximately twice a minute for the fastest * overflowing hardware. We run it for all hardware since it shouldn't have a * large impact.
*/ staticvoid wx_ptp_overflow_check(struct wx *wx)
{ bool timeout = time_is_before_jiffies(wx->last_overflow_check +
WX_OVERFLOW_PERIOD); unsignedlong flags;
if (timeout) { /* Update the timecounter */
write_seqlock_irqsave(&wx->hw_tc_lock, flags);
timecounter_read(&wx->hw_tc);
write_sequnlock_irqrestore(&wx->hw_tc_lock, flags);
wx->last_overflow_check = jiffies;
}
}
/** * wx_ptp_rx_hang - detect error case when Rx timestamp registers latched * @wx: pointer to wx struct * * 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.
*/ staticvoid wx_ptp_rx_hang(struct wx *wx)
{ struct wx_ring *rx_ring; unsignedlong rx_event;
u32 tsyncrxctl; int n;
tsyncrxctl = rd32(wx, WX_PSR_1588_CTL);
/* if we don't have a valid timestamp in the registers, just update the * timeout counter and exit
*/ if (!(tsyncrxctl & WX_PSR_1588_CTL_VALID)) {
wx->last_rx_ptp_check = jiffies; return;
}
/* determine the most recent watchdog or rx_timestamp event */
rx_event = wx->last_rx_ptp_check; for (n = 0; n < wx->num_rx_queues; n++) {
rx_ring = wx->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(wx, WX_PSR_1588_STMPH);
wx->last_rx_ptp_check = jiffies;
/** * wx_ptp_tx_hang - detect error case where Tx timestamp never finishes * @wx: private network wx structure
*/ staticvoid wx_ptp_tx_hang(struct wx *wx)
{ bool timeout = time_is_before_jiffies(wx->ptp_tx_start +
WX_PTP_TX_TIMEOUT);
if (!wx->ptp_tx_skb) return;
if (!test_bit(WX_STATE_PTP_TX_IN_PROGRESS, wx->state)) return;
/* If we haven't received a timestamp within the timeout, it is * reasonable to assume that it will never occur, so we can unlock the * timestamp bit when this occurs.
*/ if (timeout) {
wx_ptp_clear_tx_timestamp(wx);
wx->tx_hwtstamp_timeouts++;
dev_warn(&wx->pdev->dev, "clearing Tx timestamp hang\n");
}
}
/* Read the current clock time, and save the cycle counter value */
write_seqlock_irqsave(&wx->hw_tc_lock, flags);
ns = timecounter_read(&wx->hw_tc);
wx->pps_edge_start = wx->hw_tc.cycle_last;
write_sequnlock_irqrestore(&wx->hw_tc_lock, flags);
wx->pps_edge_end = wx->pps_edge_start;
/* Figure out how far past the next second we are */
div_u64_rem(ns, WX_NS_PER_SEC, &rem);
/* Figure out how many nanoseconds to add to round the clock edge up * to the next full second
*/
rem = (WX_NS_PER_SEC - rem);
/* Adjust the clock edge to align with the next full second. */
wx->pps_edge_start += div_u64(((u64)rem << cc->shift), cc->mult);
wx->pps_edge_end += div_u64(((u64)(rem + wx->pps_width) <<
cc->shift), cc->mult);
/** * When PPS is enabled, unmask the interrupt for the ClockOut * feature, so that the interrupt handler can send the PPS * event when the clock SDP triggers. Clear mask when PPS is * disabled
*/ if (rq->type != PTP_CLK_REQ_PEROUT || !wx->ptp_setup_sdp) return -EOPNOTSUPP;
/* Reject requests with unsupported flags */ if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
PTP_PEROUT_PHASE)) return -EOPNOTSUPP;
if (rq->perout.phase.sec || rq->perout.phase.nsec) {
wx_err(wx, "Absolute start time not supported.\n"); return -EINVAL;
}
if (rq->perout.period.sec != 1 || rq->perout.period.nsec) {
wx_err(wx, "Only 1pps is supported.\n"); return -EINVAL;
}
if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) { struct timespec64 ts_on;
/* this check is necessary in case the interrupt was enabled via some * alternative means (ex. debug_fs). Better to check here than * everywhere that calls this function.
*/ if (!wx->ptp_clock) return;
int_status = rd32ptp(wx, WX_TSC_1588_INT_ST); if (int_status & WX_TSC_1588_INT_ST_TT1) { /* disable the pin first */
wr32ptp(wx, WX_TSC_1588_AUX_CTL, 0);
WX_WRITE_FLUSH(wx);
/* Set the default timestamp mode to disabled here. We do this in * create_clock instead of initialization, because we don't want to * override the previous settings during a suspend/resume cycle.
*/
wx->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
wx->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
switch (config->tx_type) { case HWTSTAMP_TX_OFF:
tsync_tx_ctl = 0; break; case HWTSTAMP_TX_ON: break; default: return -ERANGE;
}
switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE:
tsync_rx_ctl = 0;
tsync_rx_mtrl = 0;
clear_bit(WX_FLAG_RX_HWTSTAMP_ENABLED, flags);
clear_bit(WX_FLAG_RX_HWTSTAMP_IN_REGISTER, flags); break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
tsync_rx_ctl |= WX_PSR_1588_CTL_TYPE_L4_V1;
tsync_rx_mtrl |= WX_PSR_1588_MSG_V1_SYNC;
set_bit(WX_FLAG_RX_HWTSTAMP_ENABLED, flags);
set_bit(WX_FLAG_RX_HWTSTAMP_IN_REGISTER, flags); break; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
tsync_rx_ctl |= WX_PSR_1588_CTL_TYPE_L4_V1;
tsync_rx_mtrl |= WX_PSR_1588_MSG_V1_DELAY_REQ;
set_bit(WX_FLAG_RX_HWTSTAMP_ENABLED, flags);
set_bit(WX_FLAG_RX_HWTSTAMP_IN_REGISTER, flags); 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:
tsync_rx_ctl |= WX_PSR_1588_CTL_TYPE_EVENT_V2;
is_l2 = true;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
set_bit(WX_FLAG_RX_HWTSTAMP_ENABLED, flags);
set_bit(WX_FLAG_RX_HWTSTAMP_IN_REGISTER, flags); break; default: /* register PSR_1588_MSG must be set in order to do V1 packets, * therefore it is not possible to time stamp both V1 Sync and * Delay_Req messages unless hardware supports timestamping all * packets => return error
*/
config->rx_filter = HWTSTAMP_FILTER_NONE; return -ERANGE;
}
/* define ethertype filter for timestamping L2 packets */ if (is_l2)
wr32(wx, WX_PSR_ETYPE_SWC(WX_PSR_ETYPE_SWC_FILTER_1588),
(WX_PSR_ETYPE_SWC_FILTER_EN | /* enable filter */
WX_PSR_ETYPE_SWC_1588 | /* enable timestamping */
ETH_P_1588)); /* 1588 eth protocol type */ else
wr32(wx, WX_PSR_ETYPE_SWC(WX_PSR_ETYPE_SWC_FILTER_1588), 0);
/** * wx_ptp_reset_cyclecounter - create the cycle counter from hw * @wx: pointer to the wx structure * * This function should be called to set the proper values for the TSC_1588_INC * register and tell the cyclecounter structure what the tick rate of SYSTIME * is. It does not directly modify SYSTIME registers or the timecounter * structure. It should be called whenever a new TSC_1588_INC value is * necessary, such as during initialization or when the link speed changes.
*/ void wx_ptp_reset_cyclecounter(struct wx *wx)
{
u32 incval = 0, mask = 0; struct cyclecounter cc; unsignedlong flags;
/* For some of the boards below this mask is technically incorrect. * The timestamp mask overflows at approximately 61bits. However the * particular hardware does not overflow on an even bitmask value. * Instead, it overflows due to conversion of upper 32bits billions of * cycles. Timecounters are not really intended for this purpose so * they do not properly function if the overflow point isn't 2^N-1. * However, the actual SYSTIME values in question take ~138 years to * overflow. In practice this means they won't actually overflow. A * proper fix to this problem would require modification of the * timecounter delta calculations.
*/
cc.mask = CLOCKSOURCE_MASK(64);
cc.mult = 1;
cc.shift = 0;
/* Now that the shift has been calculated and the systime * registers reset, (re-)enable the Clock out feature
*/ if (wx->ptp_setup_sdp)
wx->ptp_setup_sdp(wx);
}
EXPORT_SYMBOL(wx_ptp_reset);
void wx_ptp_init(struct wx *wx)
{ /* Initialize the seqlock_t first, since the user might call the clock * functions any time after we've initialized the ptp clock device.
*/
seqlock_init(&wx->hw_tc_lock);
/* obtain a ptp clock device, or re-use an existing device */ if (wx_ptp_create_clock(wx)) return;
/* enter the WX_STATE_PTP_RUNNING state */
set_bit(WX_STATE_PTP_RUNNING, wx->state);
}
EXPORT_SYMBOL(wx_ptp_init);
/** * wx_ptp_suspend - stop ptp work items * @wx: pointer to wx struct * * This function suspends ptp activity, and prevents more work from being * generated, but does not destroy the clock device.
*/ void wx_ptp_suspend(struct wx *wx)
{ /* leave the WX_STATE_PTP_RUNNING STATE */ if (!test_and_clear_bit(WX_STATE_PTP_RUNNING, wx->state)) return;
clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags); if (wx->ptp_setup_sdp)
wx->ptp_setup_sdp(wx);
/** * wx_ptp_stop - destroy the ptp_clock device * @wx: pointer to wx struct * * Completely destroy the ptp_clock device, and disable all PTP related * features. Intended to be run when the device is being closed.
*/ void wx_ptp_stop(struct wx *wx)
{ /* first, suspend ptp activity */
wx_ptp_suspend(wx);
/* now destroy the ptp clock device */ if (wx->ptp_clock) {
ptp_clock_unregister(wx->ptp_clock);
wx->ptp_clock = NULL;
dev_info(&wx->pdev->dev, "removed PHC on %s\n", wx->netdev->name);
}
}
EXPORT_SYMBOL(wx_ptp_stop);
/** * wx_ptp_rx_hwtstamp - utility function which checks for RX time stamp * @wx: pointer to wx struct * @skb: particular skb to send timestamp with * * if the timestamp is valid, we convert it into the timecounter ns * value, then store that result into the shhwtstamps structure which * is passed up the network stack
*/ void wx_ptp_rx_hwtstamp(struct wx *wx, struct sk_buff *skb)
{
u64 regval = 0;
u32 tsyncrxctl;
/* Read the tsyncrxctl register afterwards in order to prevent taking an * I/O hit on every packet.
*/
tsyncrxctl = rd32(wx, WX_PSR_1588_CTL); if (!(tsyncrxctl & WX_PSR_1588_CTL_VALID)) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.