Skip to content

Commit 3ed247e

Browse files
vcgomesanguy11
authored andcommitted
igc: Add support for multiple in-flight TX timestamps
Add support for using the four sets of timestamping registers that i225/i226 have available for TX. In some workloads, where multiple applications request hardware transmission timestamps, it was possible that some of those requests were denied because the only in use register was already occupied. This is also in preparation to future support for hardware timestamping with multiple PTP domains. With multiple domains chances of multiple TX timestamps being requested at the same time increase. Before: $ sudo ./ntpperf -i enp3s0 -m 10:22:22:22:22:21 -d 192.168.1.3 -s 172.18.0.0/16 -I -H -o 37 | responses | TX timestamp offset (ns) rate clients | lost invalid basic xleave | min mean max stddev 1000 100 0.00% 0.00% 0.00% 100.00% +1 +41 +73 13 1500 150 0.00% 0.00% 0.00% 100.00% +9 +49 +87 15 2250 225 0.00% 0.00% 0.00% 100.00% +9 +42 +79 13 3375 337 0.00% 0.00% 0.00% 100.00% +11 +46 +81 13 5062 506 0.00% 0.00% 0.00% 100.00% +7 +44 +80 13 7593 759 0.00% 0.00% 0.00% 100.00% +9 +44 +79 12 11389 1138 0.00% 0.00% 0.00% 100.00% +14 +51 +87 13 17083 1708 0.00% 0.00% 0.00% 100.00% +1 +41 +80 14 25624 2562 0.00% 0.00% 0.00% 100.00% +11 +50 +5107 51 38436 3843 0.00% 0.00% 0.00% 100.00% -2 +36 +7843 38 57654 5765 0.00% 0.00% 0.00% 100.00% +4 +42 +10503 69 86481 8648 0.00% 0.00% 0.00% 100.00% +11 +54 +5492 65 129721 12972 0.00% 0.00% 0.00% 100.00% +31 +2680 +6942 2606 194581 16384 16.79% 0.00% 0.87% 82.34% +73 +4444 +15879 3116 291871 16384 35.05% 0.00% 1.53% 63.42% +188 +5381 +17019 3035 437806 16384 54.95% 0.00% 2.55% 42.50% +233 +6302 +13885 2846 After: $ sudo ./ntpperf -i enp3s0 -m 10:22:22:22:22:21 -d 192.168.1.3 -s 172.18.0.0/16 -I -H -o 37 | responses | TX timestamp offset (ns) rate clients | lost invalid basic xleave | min mean max stddev 1000 100 0.00% 0.00% 0.00% 100.00% -20 +12 +43 13 1500 150 0.00% 0.00% 0.00% 100.00% -23 +18 +57 14 2250 225 0.00% 0.00% 0.00% 100.00% -2 +33 +67 13 3375 337 0.00% 0.00% 0.00% 100.00% +1 +38 +76 13 5062 506 0.00% 0.00% 0.00% 100.00% +9 +52 +93 14 7593 759 0.00% 0.00% 0.00% 100.00% +11 +47 +82 13 11389 1138 0.00% 0.00% 0.00% 100.00% -9 +27 +74 13 17083 1708 0.00% 0.00% 0.00% 100.00% -13 +25 +66 14 25624 2562 0.00% 0.00% 0.00% 100.00% -8 +28 +65 13 38436 3843 0.00% 0.00% 0.00% 100.00% -13 +28 +69 13 57654 5765 0.00% 0.00% 0.00% 100.00% -11 +32 +71 14 86481 8648 0.00% 0.00% 0.00% 100.00% +2 +44 +83 14 129721 12972 15.36% 0.00% 0.35% 84.29% -2 +2248 +22907 4252 194581 16384 42.98% 0.00% 1.98% 55.04% -4 +5278 +65039 5856 291871 16384 54.33% 0.00% 2.21% 43.46% -3 +6306 +22608 5665 We can see that with 4 registers, as expected, we are able to handle a increasing number of requests more consistently, but as soon as all registers are in use, the decrease in quality of service happens in a sharp step. Signed-off-by: Vinicius Costa Gomes <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Reviewed-by: Muhammad Husaini Zulkifli <[email protected]> Reviewed-by: Kurt Kanzenbach <[email protected]> Tested-by: Naama Meir <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent 35b4b6d commit 3ed247e

File tree

6 files changed

+192
-63
lines changed

6 files changed

+192
-63
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ void igc_ethtool_set_ops(struct net_device *);
3838

3939
#define MAX_FLEX_FILTER 32
4040

41+
#define IGC_MAX_TX_TSTAMP_REGS 4
42+
4143
enum igc_mac_filter_type {
4244
IGC_MAC_FILTER_TYPE_DST = 0,
4345
IGC_MAC_FILTER_TYPE_SRC
@@ -70,6 +72,15 @@ struct igc_rx_packet_stats {
7072
u64 other_packets;
7173
};
7274

75+
struct igc_tx_timestamp_request {
76+
struct sk_buff *skb; /* reference to the packet being timestamped */
77+
unsigned long start; /* when the tstamp request started (jiffies) */
78+
u32 mask; /* _TSYNCTXCTL_TXTT_{X} bit for this request */
79+
u32 regl; /* which TXSTMPL_{X} register should be used */
80+
u32 regh; /* which TXSTMPH_{X} register should be used */
81+
u32 flags; /* flags that should be added to the tx_buffer */
82+
};
83+
7384
struct igc_ring_container {
7485
struct igc_ring *ring; /* pointer to linked list of rings */
7586
unsigned int total_bytes; /* total bytes processed this int */
@@ -245,9 +256,8 @@ struct igc_adapter {
245256
* ptp_tx_lock.
246257
*/
247258
spinlock_t ptp_tx_lock;
248-
struct sk_buff *ptp_tx_skb;
259+
struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
249260
struct hwtstamp_config tstamp_config;
250-
unsigned long ptp_tx_start;
251261
unsigned int ptp_flags;
252262
/* System time value lock */
253263
spinlock_t tmreg_lock;
@@ -455,6 +465,10 @@ enum igc_tx_flags {
455465
/* olinfo flags */
456466
IGC_TX_FLAGS_IPV4 = 0x10,
457467
IGC_TX_FLAGS_CSUM = 0x20,
468+
469+
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
470+
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
471+
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
458472
};
459473

460474
enum igc_boards {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct igc_adv_tx_context_desc {
3434

3535
/* Adv Transmit Descriptor Config Masks */
3636
#define IGC_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */
37+
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
38+
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
39+
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
3740
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
3841
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
3942
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,13 +454,20 @@
454454

455455
/* Time Sync Transmit Control bit definitions */
456456
#define IGC_TSYNCTXCTL_TXTT_0 0x00000001 /* Tx timestamp reg 0 valid */
457+
#define IGC_TSYNCTXCTL_TXTT_1 0x00000002 /* Tx timestamp reg 1 valid */
458+
#define IGC_TSYNCTXCTL_TXTT_2 0x00000004 /* Tx timestamp reg 2 valid */
459+
#define IGC_TSYNCTXCTL_TXTT_3 0x00000008 /* Tx timestamp reg 3 valid */
457460
#define IGC_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
458461
#define IGC_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
459462
#define IGC_TSYNCTXCTL_SYNC_COMP_ERR 0x20000000 /* sync err */
460463
#define IGC_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
461464
#define IGC_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
462465
#define IGC_TSYNCTXCTL_TXSYNSIG 0x00000020 /* Sample TX tstamp in PHY sop */
463466

467+
#define IGC_TSYNCTXCTL_TXTT_ANY ( \
468+
IGC_TSYNCTXCTL_TXTT_0 | IGC_TSYNCTXCTL_TXTT_1 | \
469+
IGC_TSYNCTXCTL_TXTT_2 | IGC_TSYNCTXCTL_TXTT_3)
470+
464471
/* Timer selection bits */
465472
#define IGC_AUX_IO_TIMER_SEL_SYSTIM0 (0u << 30) /* Select SYSTIM0 for auxiliary time stamp */
466473
#define IGC_AUX_IO_TIMER_SEL_SYSTIM1 (1u << 30) /* Select SYSTIM1 for auxiliary time stamp */

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

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,10 +1271,21 @@ static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
12711271
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
12721272
(IGC_ADVTXD_DCMD_TSE));
12731273

1274-
/* set timestamp bit if present */
1274+
/* set timestamp bit if present, will select the register set
1275+
* based on the _TSTAMP(_X) bit.
1276+
*/
12751277
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
12761278
(IGC_ADVTXD_MAC_TSTAMP));
12771279

1280+
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_1,
1281+
(IGC_ADVTXD_TSTAMP_REG_1));
1282+
1283+
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_2,
1284+
(IGC_ADVTXD_TSTAMP_REG_2));
1285+
1286+
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_3,
1287+
(IGC_ADVTXD_TSTAMP_REG_3));
1288+
12781289
/* insert frame checksum */
12791290
cmd_type ^= IGC_SET_FLAG(skb->no_fcs, 1, IGC_ADVTXD_DCMD_IFCS);
12801291

@@ -1533,6 +1544,26 @@ static int igc_tso(struct igc_ring *tx_ring,
15331544
return 1;
15341545
}
15351546

1547+
static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *skb, u32 *flags)
1548+
{
1549+
int i;
1550+
1551+
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
1552+
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
1553+
1554+
if (tstamp->skb)
1555+
continue;
1556+
1557+
tstamp->skb = skb_get(skb);
1558+
tstamp->start = jiffies;
1559+
*flags = tstamp->flags;
1560+
1561+
return true;
1562+
}
1563+
1564+
return false;
1565+
}
1566+
15361567
static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
15371568
struct igc_ring *tx_ring)
15381569
{
@@ -1614,14 +1645,12 @@ static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
16141645
* timestamping request.
16151646
*/
16161647
unsigned long flags;
1648+
u32 tstamp_flags;
16171649

16181650
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
1619-
if (!adapter->ptp_tx_skb) {
1651+
if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
16201652
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
1621-
tx_flags |= IGC_TX_FLAGS_TSTAMP;
1622-
1623-
adapter->ptp_tx_skb = skb_get(skb);
1624-
adapter->ptp_tx_start = jiffies;
1653+
tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
16251654
} else {
16261655
adapter->tx_hwtstamp_skipped++;
16271656
}

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

Lines changed: 119 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -558,11 +558,16 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
558558
static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
559559
{
560560
unsigned long flags;
561+
int i;
561562

562563
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
563564

564-
dev_kfree_skb_any(adapter->ptp_tx_skb);
565-
adapter->ptp_tx_skb = NULL;
565+
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
566+
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
567+
568+
dev_kfree_skb_any(tstamp->skb);
569+
tstamp->skb = NULL;
570+
}
566571

567572
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
568573
}
@@ -659,61 +664,106 @@ static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter,
659664
}
660665

661666
/* Requires adapter->ptp_tx_lock held by caller. */
662-
static void igc_ptp_tx_timeout(struct igc_adapter *adapter)
667+
static void igc_ptp_tx_timeout(struct igc_adapter *adapter,
668+
struct igc_tx_timestamp_request *tstamp)
663669
{
664-
struct igc_hw *hw = &adapter->hw;
665-
666-
dev_kfree_skb_any(adapter->ptp_tx_skb);
667-
adapter->ptp_tx_skb = NULL;
670+
dev_kfree_skb_any(tstamp->skb);
671+
tstamp->skb = NULL;
668672
adapter->tx_hwtstamp_timeouts++;
669-
/* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */
670-
rd32(IGC_TXSTMPH);
673+
671674
netdev_warn(adapter->netdev, "Tx timestamp timeout\n");
672675
}
673676

674677
void igc_ptp_tx_hang(struct igc_adapter *adapter)
675678
{
679+
struct igc_tx_timestamp_request *tstamp;
680+
struct igc_hw *hw = &adapter->hw;
676681
unsigned long flags;
682+
bool found = false;
683+
int i;
677684

678685
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
679686

680-
if (!adapter->ptp_tx_skb)
681-
goto unlock;
687+
for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
688+
tstamp = &adapter->tx_tstamp[i];
689+
690+
if (!tstamp->skb)
691+
continue;
682692

683-
if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT))
684-
goto unlock;
693+
if (time_is_after_jiffies(tstamp->start + IGC_PTP_TX_TIMEOUT))
694+
continue;
685695

686-
igc_ptp_tx_timeout(adapter);
696+
igc_ptp_tx_timeout(adapter, tstamp);
697+
found = true;
698+
}
699+
700+
if (found) {
701+
/* Reading the high register of the first set of timestamp registers
702+
* clears all the equivalent bits in the TSYNCTXCTL register.
703+
*/
704+
rd32(IGC_TXSTMPH_0);
705+
}
687706

688-
unlock:
689707
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
690708
}
691709

710+
static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
711+
struct igc_tx_timestamp_request *tstamp, u64 regval)
712+
{
713+
struct skb_shared_hwtstamps shhwtstamps;
714+
struct sk_buff *skb;
715+
int adjust = 0;
716+
717+
skb = tstamp->skb;
718+
if (!skb)
719+
return;
720+
721+
if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
722+
return;
723+
724+
switch (adapter->link_speed) {
725+
case SPEED_10:
726+
adjust = IGC_I225_TX_LATENCY_10;
727+
break;
728+
case SPEED_100:
729+
adjust = IGC_I225_TX_LATENCY_100;
730+
break;
731+
case SPEED_1000:
732+
adjust = IGC_I225_TX_LATENCY_1000;
733+
break;
734+
case SPEED_2500:
735+
adjust = IGC_I225_TX_LATENCY_2500;
736+
break;
737+
}
738+
739+
shhwtstamps.hwtstamp =
740+
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
741+
742+
tstamp->skb = NULL;
743+
744+
skb_tstamp_tx(skb, &shhwtstamps);
745+
dev_kfree_skb_any(skb);
746+
}
747+
692748
/**
693749
* igc_ptp_tx_hwtstamp - utility function which checks for TX time stamp
694750
* @adapter: Board private structure
695751
*
696-
* If we were asked to do hardware stamping and such a time stamp is
697-
* available, then it must have been for this skb here because we only
698-
* allow only one such packet into the queue.
752+
* Check against the ready mask for which of the timestamp register
753+
* sets are ready to be retrieved, then retrieve that and notify the
754+
* rest of the stack.
699755
*
700756
* Context: Expects adapter->ptp_tx_lock to be held by caller.
701757
*/
702758
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
703759
{
704-
struct sk_buff *skb = adapter->ptp_tx_skb;
705-
struct skb_shared_hwtstamps shhwtstamps;
706760
struct igc_hw *hw = &adapter->hw;
707-
u32 tsynctxctl;
708-
int adjust = 0;
709761
u64 regval;
762+
u32 mask;
763+
int i;
710764

711-
if (WARN_ON_ONCE(!skb))
712-
return;
713-
714-
tsynctxctl = rd32(IGC_TSYNCTXCTL);
715-
tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0;
716-
if (tsynctxctl) {
765+
mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
766+
if (mask & IGC_TSYNCTXCTL_TXTT_0) {
717767
regval = rd32(IGC_TXSTMPL);
718768
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
719769
} else {
@@ -742,37 +792,30 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
742792
txstmpl_new = rd32(IGC_TXSTMPL);
743793

744794
if (txstmpl_old == txstmpl_new)
745-
return;
795+
goto done;
746796

747797
regval = txstmpl_new;
748798
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
749799
}
750-
if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
751-
return;
752800

753-
switch (adapter->link_speed) {
754-
case SPEED_10:
755-
adjust = IGC_I225_TX_LATENCY_10;
756-
break;
757-
case SPEED_100:
758-
adjust = IGC_I225_TX_LATENCY_100;
759-
break;
760-
case SPEED_1000:
761-
adjust = IGC_I225_TX_LATENCY_1000;
762-
break;
763-
case SPEED_2500:
764-
adjust = IGC_I225_TX_LATENCY_2500;
765-
break;
766-
}
801+
igc_ptp_tx_reg_to_stamp(adapter, &adapter->tx_tstamp[0], regval);
767802

768-
shhwtstamps.hwtstamp =
769-
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
803+
done:
804+
/* Now that the problematic first register was handled, we can
805+
* use retrieve the timestamps from the other registers
806+
* (starting from '1') with less complications.
807+
*/
808+
for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
809+
struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
770810

771-
adapter->ptp_tx_skb = NULL;
811+
if (!(tstamp->mask & mask))
812+
continue;
772813

773-
/* Notify the stack and free the skb after we've unlocked */
774-
skb_tstamp_tx(skb, &shhwtstamps);
775-
dev_kfree_skb_any(skb);
814+
regval = rd32(tstamp->regl);
815+
regval |= (u64)rd32(tstamp->regh) << 32;
816+
817+
igc_ptp_tx_reg_to_stamp(adapter, tstamp, regval);
818+
}
776819
}
777820

778821
/**
@@ -788,12 +831,8 @@ void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter)
788831

789832
spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
790833

791-
if (!adapter->ptp_tx_skb)
792-
goto unlock;
793-
794834
igc_ptp_tx_hwtstamp(adapter);
795835

796-
unlock:
797836
spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
798837
}
799838

@@ -1006,9 +1045,34 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
10061045
void igc_ptp_init(struct igc_adapter *adapter)
10071046
{
10081047
struct net_device *netdev = adapter->netdev;
1048+
struct igc_tx_timestamp_request *tstamp;
10091049
struct igc_hw *hw = &adapter->hw;
10101050
int i;
10111051

1052+
tstamp = &adapter->tx_tstamp[0];
1053+
tstamp->mask = IGC_TSYNCTXCTL_TXTT_0;
1054+
tstamp->regl = IGC_TXSTMPL_0;
1055+
tstamp->regh = IGC_TXSTMPH_0;
1056+
tstamp->flags = 0;
1057+
1058+
tstamp = &adapter->tx_tstamp[1];
1059+
tstamp->mask = IGC_TSYNCTXCTL_TXTT_1;
1060+
tstamp->regl = IGC_TXSTMPL_1;
1061+
tstamp->regh = IGC_TXSTMPH_1;
1062+
tstamp->flags = IGC_TX_FLAGS_TSTAMP_1;
1063+
1064+
tstamp = &adapter->tx_tstamp[2];
1065+
tstamp->mask = IGC_TSYNCTXCTL_TXTT_2;
1066+
tstamp->regl = IGC_TXSTMPL_2;
1067+
tstamp->regh = IGC_TXSTMPH_2;
1068+
tstamp->flags = IGC_TX_FLAGS_TSTAMP_2;
1069+
1070+
tstamp = &adapter->tx_tstamp[3];
1071+
tstamp->mask = IGC_TSYNCTXCTL_TXTT_3;
1072+
tstamp->regl = IGC_TXSTMPL_3;
1073+
tstamp->regh = IGC_TXSTMPH_3;
1074+
tstamp->flags = IGC_TX_FLAGS_TSTAMP_3;
1075+
10121076
switch (hw->mac.type) {
10131077
case igc_i225:
10141078
for (i = 0; i < IGC_N_SDP; i++) {

0 commit comments

Comments
 (0)