/** * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @adapter: Board private structure. * * If we were asked to do hardware stamping and such a time stamp is * available, then it must have been for this skb here because we only * allow only one such packet into the queue. **/ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; u64 regval; int adjust = 0; regval = rd32(E1000_TXSTMPL); regval |= (u64)rd32(E1000_TXSTMPH) << 32; igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); /* adjust timestamp for the TX latency based on link speed */ if (adapter->hw.mac.type == e1000_i210) { switch (adapter->link_speed) { case SPEED_10: adjust = IGB_I210_TX_LATENCY_10; break; case SPEED_100: adjust = IGB_I210_TX_LATENCY_100; break; case SPEED_1000: adjust = IGB_I210_TX_LATENCY_1000; break; } } shhwtstamps.hwtstamp = ktime_sub_ns(shhwtstamps.hwtstamp, adjust); skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); dev_kfree_skb_any(adapter->ptp_tx_skb); adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); }
/** * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp * @q_vector: Pointer to interrupt specific structure * @va: Pointer to address containing Rx buffer * @skb: Buffer containing timestamp and packet * * This function is meant to retrieve a timestamp from the first buffer of an * incoming frame. The value is stored in little endian format starting on * byte 8. **/ void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va, struct sk_buff *skb) { __le64 *regval = (__le64 *)va; struct igb_adapter *adapter = q_vector->adapter; int adjust = 0; /* The timestamp is recorded in little endian format. * DWORD: 0 1 2 3 * Field: Reserved Reserved SYSTIML SYSTIMH */ igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), le64_to_cpu(regval[1])); /* adjust timestamp for the RX latency based on link speed */ if (adapter->hw.mac.type == e1000_i210) { switch (adapter->link_speed) { case SPEED_10: adjust = IGB_I210_RX_LATENCY_10; break; case SPEED_100: adjust = IGB_I210_RX_LATENCY_100; break; case SPEED_1000: adjust = IGB_I210_RX_LATENCY_1000; break; } } skb_hwtstamps(skb)->hwtstamp = ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); }
/** * igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register * @q_vector: Pointer to interrupt specific structure * @skb: Buffer containing timestamp and packet * * This function is meant to retrieve a timestamp from the internal registers * of the adapter and store it in the skb. **/ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb) { struct igb_adapter *adapter = q_vector->adapter; struct e1000_hw *hw = &adapter->hw; u64 regval; int adjust = 0; /* If this bit is set, then the RX registers contain the time stamp. No * other packet will be time stamped until we read these registers, so * read the registers to make them available again. Because only one * packet can be time stamped at a time, we know that the register * values must belong to this one here and therefore we don't need to * compare any of the additional attributes stored for it. * * If nothing went wrong, then it should have a shared tx_flags that we * can turn into a skb_shared_hwtstamps. */ if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) return; regval = rd32(E1000_RXSTMPL); regval |= (u64)rd32(E1000_RXSTMPH) << 32; igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); /* adjust timestamp for the RX latency based on link speed */ if (adapter->hw.mac.type == e1000_i210) { switch (adapter->link_speed) { case SPEED_10: adjust = IGB_I210_RX_LATENCY_10; break; case SPEED_100: adjust = IGB_I210_RX_LATENCY_100; break; case SPEED_1000: adjust = IGB_I210_RX_LATENCY_1000; break; } } skb_hwtstamps(skb)->hwtstamp = ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); /* Update the last_rx_timestamp timer in order to enable watchdog check * for error case of latched timestamp on a dropped packet. */ adapter->last_rx_timestamp = jiffies; }
static ktime_t ptp_to_ktime(u64 ptptime) { ktime_t ktimebase; u64 ptpbase; unsigned long flags; local_irq_save(flags); /* Fill the icache with the code */ ktime_get_real(); /* Flush all pending operations */ mb(); /* Read the time and PTP clock as close together as * possible. It is important that this sequence take the same * amount of time to reduce jitter */ ktimebase = ktime_get_real(); ptpbase = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_HI); local_irq_restore(flags); return ktime_sub_ns(ktimebase, ptpbase - ptptime); }