Skip to content

Commit a49296e

Browse files
committed
Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue
Tony Nguyen says: ==================== igc: Add support for physical + free-running timers Vinicius Costa Gomes says: The objective is to allow having functionality that depends on the physical timer (taprio and ETF offloads, for example) and vclocks operating together. The "big" missing piece is the implementation of the .getcyclesx64() function in igc, as i225/i226 have multiple timers, we use one of those timers (timer 1) as a free-running (non adjustable) timer. The complication is that only implementing .getcyclesx64() and nothing else will break synchronization when using vclocks, as reading the clock will retrieve the free-running value but timnestamps will come from the adjustable timer. The solution is to modify "in one go" the timestamping code to be able to retrieve the timestamp from the correct timer (if a socket is "phc_bound" to a vclock the timestamp will come from the free-running timer). I was debating whether or not to do the adjustments for the internal latencies for the free-running timestamps, decided to do the adjustments so the path delay when using vclocks is similar to the one when using the physical clock. One future improvement is to implement the .getcrosscycles() function. * '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue: igc: Add support for PTP .getcyclesx64() igc: Simplify setting flags in the TX data descriptor ==================== Link: https://lore.kernel.org/r/20231114183640.1303163-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 516cba9 + 069b142 commit a49296e

File tree

6 files changed

+105
-42
lines changed

6 files changed

+105
-42
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: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,14 +1299,16 @@ static void igc_tx_olinfo_status(struct igc_ring *tx_ring,
12991299
u32 olinfo_status = paylen << IGC_ADVTXD_PAYLEN_SHIFT;
13001300

13011301
/* insert L4 checksum */
1302-
olinfo_status |= (tx_flags & IGC_TX_FLAGS_CSUM) *
1303-
((IGC_TXD_POPTS_TXSM << 8) /
1304-
IGC_TX_FLAGS_CSUM);
1302+
olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_CSUM,
1303+
(IGC_TXD_POPTS_TXSM << 8));
13051304

13061305
/* insert IPv4 checksum */
1307-
olinfo_status |= (tx_flags & IGC_TX_FLAGS_IPV4) *
1308-
(((IGC_TXD_POPTS_IXSM << 8)) /
1309-
IGC_TX_FLAGS_IPV4);
1306+
olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_IPV4,
1307+
(IGC_TXD_POPTS_IXSM << 8));
1308+
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);
13101312

13111313
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
13121314
}
@@ -1651,6 +1653,8 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
16511653
if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
16521654
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
16531655
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;
16541658
} else {
16551659
adapter->tx_hwtstamp_skipped++;
16561660
}
@@ -1963,9 +1967,9 @@ static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring,
19631967

19641968
static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
19651969
struct igc_rx_buffer *rx_buffer,
1966-
struct xdp_buff *xdp,
1967-
ktime_t timestamp)
1970+
struct igc_xdp_buff *ctx)
19681971
{
1972+
struct xdp_buff *xdp = &ctx->xdp;
19691973
unsigned int metasize = xdp->data - xdp->data_meta;
19701974
unsigned int size = xdp->data_end - xdp->data;
19711975
unsigned int truesize = igc_get_rx_frame_truesize(rx_ring, size);
@@ -1982,8 +1986,10 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
19821986
if (unlikely(!skb))
19831987
return NULL;
19841988

1985-
if (timestamp)
1986-
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+
}
19871993

19881994
/* Determine available headroom for copy */
19891995
headlen = size;
@@ -2583,11 +2589,10 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
25832589
int xdp_status = 0, rx_buffer_pgcnt;
25842590

25852591
while (likely(total_packets < budget)) {
2586-
union igc_adv_rx_desc *rx_desc;
2592+
struct igc_xdp_buff ctx = { .rx_ts = NULL };
25872593
struct igc_rx_buffer *rx_buffer;
2594+
union igc_adv_rx_desc *rx_desc;
25882595
unsigned int size, truesize;
2589-
struct igc_xdp_buff ctx;
2590-
ktime_t timestamp = 0;
25912596
int pkt_offset = 0;
25922597
void *pktbuf;
25932598

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

26162621
if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) {
2617-
timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
2618-
pktbuf);
2619-
ctx.rx_ts = timestamp;
2622+
ctx.rx_ts = pktbuf;
26202623
pkt_offset = IGC_TS_HDR_LEN;
26212624
size -= IGC_TS_HDR_LEN;
26222625
}
@@ -2653,8 +2656,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
26532656
else if (ring_uses_build_skb(rx_ring))
26542657
skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp);
26552658
else
2656-
skb = igc_construct_skb(rx_ring, rx_buffer, &ctx.xdp,
2657-
timestamp);
2659+
skb = igc_construct_skb(rx_ring, rx_buffer, &ctx);
26582660

26592661
/* exit if we failed to retrieve a buffer */
26602662
if (!skb) {
@@ -2803,9 +2805,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget)
28032805
ctx->rx_desc = desc;
28042806

28052807
if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) {
2806-
timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
2807-
bi->xdp->data);
2808-
ctx->rx_ts = timestamp;
2808+
ctx->rx_ts = bi->xdp->data;
28092809

28102810
bi->xdp->data += IGC_TS_HDR_LEN;
28112811

@@ -6562,6 +6562,24 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
65626562
return 0;
65636563
}
65646564

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+
65656583
static const struct net_device_ops igc_netdev_ops = {
65666584
.ndo_open = igc_open,
65676585
.ndo_stop = igc_close,
@@ -6579,6 +6597,7 @@ static const struct net_device_ops igc_netdev_ops = {
65796597
.ndo_bpf = igc_bpf,
65806598
.ndo_xdp_xmit = igc_xdp_xmit,
65816599
.ndo_xsk_wakeup = igc_xsk_wakeup,
6600+
.ndo_get_tstamp = igc_get_tstamp,
65826601
};
65836602

65846603
/* PCIe configuration access */
@@ -6682,9 +6701,11 @@ static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
66826701
static int igc_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
66836702
{
66846703
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;
66856706

66866707
if (igc_test_staterr(ctx->rx_desc, IGC_RXDADV_STAT_TSIP)) {
6687-
*timestamp = ctx->rx_ts;
6708+
*timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0);
66886709

66896710
return 0;
66906711
}

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)