Skip to content

Commit 069b142

Browse files
vcgomesanguy11
authored andcommitted
igc: Add support for PTP .getcyclesx64()
Add support for using Timer 1 (i225/i226 have 4 timer registers) as a free-running clock (the "cycles" clock) in addition to Timer 0 (the default, "adjustable clock"). The objective is to allow taprio/etf offloading to coexist with PTP vclocks. Besides the implementation of .getcyclesx64() for i225/i226, to keep timestamping working when vclocks are in use, we also need to add support for TX and RX timestamping using the free running timer, when the requesting socket is bound to a vclock. On the RX side, i225/i226 can be configured to store the values of two timers in the received packet metadata area, so it's a matter of configuring the right registers and retrieving the right timestamp. The TX is a bit more involved because the hardware stores a single timestamp (with the selected timer in the TX descriptor) into one of the timestamp registers. Note some changes at how the timestamps are done for RX, the conversion and adjustment of timestamps are now done closer to the consumption of the timestamp instead of near the reception. Signed-off-by: Vinicius Costa Gomes <[email protected]> Tested-by: Naama Meir <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent fbe5677 commit 069b142

File tree

6 files changed

+101
-36
lines changed

6 files changed

+101
-36
lines changed

drivers/net/ethernet/intel/igc/igc.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ struct igc_tx_timestamp_request {
8181
u32 flags; /* flags that should be added to the tx_buffer */
8282
};
8383

84+
struct igc_inline_rx_tstamps {
85+
/* Timestamps are saved in little endian at the beginning of the packet
86+
* buffer following the layout:
87+
*
88+
* DWORD: | 0 | 1 | 2 | 3 |
89+
* Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH |
90+
*
91+
* SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds
92+
* part of the timestamp.
93+
*
94+
*/
95+
__le32 timer1[2];
96+
__le32 timer0[2];
97+
};
98+
8499
struct igc_ring_container {
85100
struct igc_ring *ring; /* pointer to linked list of rings */
86101
unsigned int total_bytes; /* total bytes processed this int */
@@ -261,6 +276,8 @@ struct igc_adapter {
261276
unsigned int ptp_flags;
262277
/* System time value lock */
263278
spinlock_t tmreg_lock;
279+
/* Free-running timer lock */
280+
spinlock_t free_timer_lock;
264281
struct cyclecounter cc;
265282
struct timecounter tc;
266283
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
@@ -469,6 +486,8 @@ enum igc_tx_flags {
469486
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
470487
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
471488
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
489+
490+
IGC_TX_FLAGS_TSTAMP_TIMER_1 = 0x800,
472491
};
473492

474493
enum igc_boards {
@@ -531,7 +550,7 @@ struct igc_rx_buffer {
531550
struct igc_xdp_buff {
532551
struct xdp_buff xdp;
533552
union igc_adv_rx_desc *rx_desc;
534-
ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
553+
struct igc_inline_rx_tstamps *rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
535554
};
536555

537556
struct igc_q_vector {

drivers/net/ethernet/intel/igc/igc_base.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ struct igc_adv_tx_context_desc {
3737
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
3838
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
3939
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
40+
#define IGC_ADVTXD_TSTAMP_TIMER_1 0x00010000 /* Select timer 1 for timestamp */
41+
#define IGC_ADVTXD_TSTAMP_TIMER_2 0x00020000 /* Select timer 2 for timestamp */
42+
#define IGC_ADVTXD_TSTAMP_TIMER_3 0x00030000 /* Select timer 3 for timestamp */
43+
4044
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
4145
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
4246
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */

drivers/net/ethernet/intel/igc/igc_defines.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@
317317
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
318318
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
319319

320+
#define IGC_TXD_PTP2_TIMER_1 0x00000020
321+
320322
/* IPSec Encrypt Enable */
321323
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
322324
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */

drivers/net/ethernet/intel/igc/igc_main.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,10 @@ static void igc_tx_olinfo_status(struct igc_ring *tx_ring,
13061306
olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_IPV4,
13071307
(IGC_TXD_POPTS_IXSM << 8));
13081308

1309+
/* Use the second timer (free running, in general) for the timestamp */
1310+
olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_TIMER_1,
1311+
IGC_TXD_PTP2_TIMER_1);
1312+
13091313
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
13101314
}
13111315

@@ -1649,6 +1653,8 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
16491653
if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
16501654
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
16511655
tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
1656+
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_USE_CYCLES)
1657+
tx_flags |= IGC_TX_FLAGS_TSTAMP_TIMER_1;
16521658
} else {
16531659
adapter->tx_hwtstamp_skipped++;
16541660
}
@@ -1961,9 +1967,9 @@ static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring,
19611967

19621968
static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
19631969
struct igc_rx_buffer *rx_buffer,
1964-
struct xdp_buff *xdp,
1965-
ktime_t timestamp)
1970+
struct igc_xdp_buff *ctx)
19661971
{
1972+
struct xdp_buff *xdp = &ctx->xdp;
19671973
unsigned int metasize = xdp->data - xdp->data_meta;
19681974
unsigned int size = xdp->data_end - xdp->data;
19691975
unsigned int truesize = igc_get_rx_frame_truesize(rx_ring, size);
@@ -1980,8 +1986,10 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
19801986
if (unlikely(!skb))
19811987
return NULL;
19821988

1983-
if (timestamp)
1984-
skb_hwtstamps(skb)->hwtstamp = timestamp;
1989+
if (ctx->rx_ts) {
1990+
skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
1991+
skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
1992+
}
19851993

19861994
/* Determine available headroom for copy */
19871995
headlen = size;
@@ -2581,11 +2589,10 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
25812589
int xdp_status = 0, rx_buffer_pgcnt;
25822590

25832591
while (likely(total_packets < budget)) {
2584-
union igc_adv_rx_desc *rx_desc;
2592+
struct igc_xdp_buff ctx = { .rx_ts = NULL };
25852593
struct igc_rx_buffer *rx_buffer;
2594+
union igc_adv_rx_desc *rx_desc;
25862595
unsigned int size, truesize;
2587-
struct igc_xdp_buff ctx;
2588-
ktime_t timestamp = 0;
25892596
int pkt_offset = 0;
25902597
void *pktbuf;
25912598

@@ -2612,9 +2619,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
26122619
pktbuf = page_address(rx_buffer->page) + rx_buffer->page_offset;
26132620

26142621
if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) {
2615-
timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
2616-
pktbuf);
2617-
ctx.rx_ts = timestamp;
2622+
ctx.rx_ts = pktbuf;
26182623
pkt_offset = IGC_TS_HDR_LEN;
26192624
size -= IGC_TS_HDR_LEN;
26202625
}
@@ -2651,8 +2656,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
26512656
else if (ring_uses_build_skb(rx_ring))
26522657
skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp);
26532658
else
2654-
skb = igc_construct_skb(rx_ring, rx_buffer, &ctx.xdp,
2655-
timestamp);
2659+
skb = igc_construct_skb(rx_ring, rx_buffer, &ctx);
26562660

26572661
/* exit if we failed to retrieve a buffer */
26582662
if (!skb) {
@@ -2801,9 +2805,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget)
28012805
ctx->rx_desc = desc;
28022806

28032807
if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) {
2804-
timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
2805-
bi->xdp->data);
2806-
ctx->rx_ts = timestamp;
2808+
ctx->rx_ts = bi->xdp->data;
28072809

28082810
bi->xdp->data += IGC_TS_HDR_LEN;
28092811

@@ -6560,6 +6562,24 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
65606562
return 0;
65616563
}
65626564

6565+
static ktime_t igc_get_tstamp(struct net_device *dev,
6566+
const struct skb_shared_hwtstamps *hwtstamps,
6567+
bool cycles)
6568+
{
6569+
struct igc_adapter *adapter = netdev_priv(dev);
6570+
struct igc_inline_rx_tstamps *tstamp;
6571+
ktime_t timestamp;
6572+
6573+
tstamp = hwtstamps->netdev_data;
6574+
6575+
if (cycles)
6576+
timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer1);
6577+
else
6578+
timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0);
6579+
6580+
return timestamp;
6581+
}
6582+
65636583
static const struct net_device_ops igc_netdev_ops = {
65646584
.ndo_open = igc_open,
65656585
.ndo_stop = igc_close,
@@ -6577,6 +6597,7 @@ static const struct net_device_ops igc_netdev_ops = {
65776597
.ndo_bpf = igc_bpf,
65786598
.ndo_xdp_xmit = igc_xdp_xmit,
65796599
.ndo_xsk_wakeup = igc_xsk_wakeup,
6600+
.ndo_get_tstamp = igc_get_tstamp,
65806601
};
65816602

65826603
/* PCIe configuration access */
@@ -6680,9 +6701,11 @@ static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
66806701
static int igc_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
66816702
{
66826703
const struct igc_xdp_buff *ctx = (void *)_ctx;
6704+
struct igc_adapter *adapter = netdev_priv(ctx->xdp.rxq->dev);
6705+
struct igc_inline_rx_tstamps *tstamp = ctx->rx_ts;
66836706

66846707
if (igc_test_staterr(ctx->rx_desc, IGC_RXDADV_STAT_TSIP)) {
6685-
*timestamp = ctx->rx_ts;
6708+
*timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0);
66866709

66876710
return 0;
66886711
}

drivers/net/ethernet/intel/igc/igc_ptp.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -459,12 +459,10 @@ static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
459459
/**
460460
* igc_ptp_rx_pktstamp - Retrieve timestamp from Rx packet buffer
461461
* @adapter: Pointer to adapter the packet buffer belongs to
462-
* @buf: Pointer to packet buffer
462+
* @buf: Pointer to start of timestamp in HW format (2 32-bit words)
463463
*
464-
* This function retrieves the timestamp saved in the beginning of packet
465-
* buffer. While two timestamps are available, one in timer0 reference and the
466-
* other in timer1 reference, this function considers only the timestamp in
467-
* timer0 reference.
464+
* This function retrieves and converts the timestamp stored at @buf
465+
* to ktime_t, adjusting for hardware latencies.
468466
*
469467
* Returns timestamp value.
470468
*/
@@ -474,17 +472,8 @@ ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf)
474472
u32 secs, nsecs;
475473
int adjust;
476474

477-
/* Timestamps are saved in little endian at the beginning of the packet
478-
* buffer following the layout:
479-
*
480-
* DWORD: | 0 | 1 | 2 | 3 |
481-
* Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH |
482-
*
483-
* SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds
484-
* part of the timestamp.
485-
*/
486-
nsecs = le32_to_cpu(buf[2]);
487-
secs = le32_to_cpu(buf[3]);
475+
nsecs = le32_to_cpu(buf[0]);
476+
secs = le32_to_cpu(buf[1]);
488477

489478
timestamp = ktime_set(secs, nsecs);
490479

@@ -542,10 +531,11 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
542531

543532
for (i = 0; i < adapter->num_rx_queues; i++) {
544533
val = rd32(IGC_SRRCTL(i));
545-
/* FIXME: For now, only support retrieving RX timestamps from
546-
* timer 0.
534+
/* Enable retrieving timestamps from timer 0, the
535+
* "adjustable clock" and timer 1 the "free running
536+
* clock".
547537
*/
548-
val |= IGC_SRRCTL_TIMER1SEL(0) | IGC_SRRCTL_TIMER0SEL(0) |
538+
val |= IGC_SRRCTL_TIMER1SEL(1) | IGC_SRRCTL_TIMER0SEL(0) |
549539
IGC_SRRCTL_TIMESTAMP;
550540
wr32(IGC_SRRCTL(i), val);
551541
}
@@ -1035,6 +1025,26 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
10351025
adapter, &adapter->snapshot, cts);
10361026
}
10371027

1028+
static int igc_ptp_getcyclesx64(struct ptp_clock_info *ptp,
1029+
struct timespec64 *ts,
1030+
struct ptp_system_timestamp *sts)
1031+
{
1032+
struct igc_adapter *igc = container_of(ptp, struct igc_adapter, ptp_caps);
1033+
struct igc_hw *hw = &igc->hw;
1034+
unsigned long flags;
1035+
1036+
spin_lock_irqsave(&igc->free_timer_lock, flags);
1037+
1038+
ptp_read_system_prets(sts);
1039+
ts->tv_nsec = rd32(IGC_SYSTIML_1);
1040+
ts->tv_sec = rd32(IGC_SYSTIMH_1);
1041+
ptp_read_system_postts(sts);
1042+
1043+
spin_unlock_irqrestore(&igc->free_timer_lock, flags);
1044+
1045+
return 0;
1046+
}
1047+
10381048
/**
10391049
* igc_ptp_init - Initialize PTP functionality
10401050
* @adapter: Board private structure
@@ -1088,6 +1098,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
10881098
adapter->ptp_caps.adjfine = igc_ptp_adjfine_i225;
10891099
adapter->ptp_caps.adjtime = igc_ptp_adjtime_i225;
10901100
adapter->ptp_caps.gettimex64 = igc_ptp_gettimex64_i225;
1101+
adapter->ptp_caps.getcyclesx64 = igc_ptp_getcyclesx64;
10911102
adapter->ptp_caps.settime64 = igc_ptp_settime_i225;
10921103
adapter->ptp_caps.enable = igc_ptp_feature_enable_i225;
10931104
adapter->ptp_caps.pps = 1;
@@ -1108,6 +1119,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
11081119
}
11091120

11101121
spin_lock_init(&adapter->ptp_tx_lock);
1122+
spin_lock_init(&adapter->free_timer_lock);
11111123
spin_lock_init(&adapter->tmreg_lock);
11121124

11131125
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;

drivers/net/ethernet/intel/igc/igc_regs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@
243243
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
244244
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
245245

246+
#define IGC_SYSTIML_1 0x0B688 /* System time register Low - RO (timer 1) */
247+
#define IGC_SYSTIMH_1 0x0B68C /* System time register High - RO (timer 1) */
248+
#define IGC_SYSTIMR_1 0x0B684 /* System time register Residue (timer 1) */
249+
#define IGC_TIMINCA_1 0x0B690 /* Increment attributes register - RW (timer 1) */
250+
246251
/* TX Timestamp Low */
247252
#define IGC_TXSTMPL_0 0x0B618
248253
#define IGC_TXSTMPL_1 0x0B698

0 commit comments

Comments
 (0)