]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
tsnep: fix timestamping with a stacked DSA driver
authorGerhard Engleder <gerhard@engleder-embedded.com>
Wed, 14 May 2025 19:56:57 +0000 (21:56 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 15 May 2025 14:58:18 +0000 (07:58 -0700)
This driver is susceptible to a form of the bug explained in commit
c26a2c2ddc01 ("gianfar: Fix TX timestamping with a stacked DSA driver")
and in Documentation/networking/timestamping.rst section "Other caveats
for MAC drivers", specifically it timestamps any skb which has
SKBTX_HW_TSTAMP, and does not consider if timestamping has been enabled
in adapter->hwtstamp_config.tx_type.

Evaluate the proper TX timestamping condition only once on the TX
path (in tsnep_xmit_frame_ring()) and store the result in an additional
TX entry flag. Evaluate the new TX entry flag in the TX confirmation path
(in tsnep_tx_poll()).

This way SKBTX_IN_PROGRESS is set by the driver as required, but never
evaluated. SKBTX_IN_PROGRESS shall not be evaluated as it can be set
by a stacked DSA driver and evaluating it would lead to unwanted
timestamps.

Fixes: 403f69bbdbad ("tsnep: Add TSN endpoint Ethernet MAC driver")
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Gerhard Engleder <gerhard@engleder-embedded.com>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20250514195657.25874-1-gerhard@engleder-embedded.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/engleder/tsnep_main.c

index 625245b0845c7a8b40089f9fd410adecb8ee30fd..eba73246f986649328c02e779e1ee896e29e6896 100644 (file)
@@ -67,6 +67,8 @@
 #define TSNEP_TX_TYPE_XDP_NDO_MAP_PAGE (TSNEP_TX_TYPE_XDP_NDO | TSNEP_TX_TYPE_MAP_PAGE)
 #define TSNEP_TX_TYPE_XDP              (TSNEP_TX_TYPE_XDP_TX | TSNEP_TX_TYPE_XDP_NDO)
 #define TSNEP_TX_TYPE_XSK              BIT(12)
+#define TSNEP_TX_TYPE_TSTAMP           BIT(13)
+#define TSNEP_TX_TYPE_SKB_TSTAMP       (TSNEP_TX_TYPE_SKB | TSNEP_TX_TYPE_TSTAMP)
 
 #define TSNEP_XDP_TX           BIT(0)
 #define TSNEP_XDP_REDIRECT     BIT(1)
@@ -386,8 +388,7 @@ static void tsnep_tx_activate(struct tsnep_tx *tx, int index, int length,
        if (entry->skb) {
                entry->properties = length & TSNEP_DESC_LENGTH_MASK;
                entry->properties |= TSNEP_DESC_INTERRUPT_FLAG;
-               if ((entry->type & TSNEP_TX_TYPE_SKB) &&
-                   (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS))
+               if ((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP)
                        entry->properties |= TSNEP_DESC_EXTENDED_WRITEBACK_FLAG;
 
                /* toggle user flag to prevent false acknowledge
@@ -479,7 +480,8 @@ static int tsnep_tx_map_frag(skb_frag_t *frag, struct tsnep_tx_entry *entry,
        return mapped;
 }
 
-static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count)
+static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count,
+                       bool do_tstamp)
 {
        struct device *dmadev = tx->adapter->dmadev;
        struct tsnep_tx_entry *entry;
@@ -505,6 +507,9 @@ static int tsnep_tx_map(struct sk_buff *skb, struct tsnep_tx *tx, int count)
                                entry->type = TSNEP_TX_TYPE_SKB_INLINE;
                                mapped = 0;
                        }
+
+                       if (do_tstamp)
+                               entry->type |= TSNEP_TX_TYPE_TSTAMP;
                } else {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
 
@@ -558,11 +563,12 @@ static int tsnep_tx_unmap(struct tsnep_tx *tx, int index, int count)
 static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
                                         struct tsnep_tx *tx)
 {
-       int count = 1;
        struct tsnep_tx_entry *entry;
+       bool do_tstamp = false;
+       int count = 1;
        int length;
-       int i;
        int retval;
+       int i;
 
        if (skb_shinfo(skb)->nr_frags > 0)
                count += skb_shinfo(skb)->nr_frags;
@@ -579,7 +585,13 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
        entry = &tx->entry[tx->write];
        entry->skb = skb;
 
-       retval = tsnep_tx_map(skb, tx, count);
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+           tx->adapter->hwtstamp_config.tx_type == HWTSTAMP_TX_ON) {
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               do_tstamp = true;
+       }
+
+       retval = tsnep_tx_map(skb, tx, count, do_tstamp);
        if (retval < 0) {
                tsnep_tx_unmap(tx, tx->write, count);
                dev_kfree_skb_any(entry->skb);
@@ -591,9 +603,6 @@ static netdev_tx_t tsnep_xmit_frame_ring(struct sk_buff *skb,
        }
        length = retval;
 
-       if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
-               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-
        for (i = 0; i < count; i++)
                tsnep_tx_activate(tx, (tx->write + i) & TSNEP_RING_MASK, length,
                                  i == count - 1);
@@ -844,8 +853,7 @@ static bool tsnep_tx_poll(struct tsnep_tx *tx, int napi_budget)
 
                length = tsnep_tx_unmap(tx, tx->read, count);
 
-               if ((entry->type & TSNEP_TX_TYPE_SKB) &&
-                   (skb_shinfo(entry->skb)->tx_flags & SKBTX_IN_PROGRESS) &&
+               if (((entry->type & TSNEP_TX_TYPE_SKB_TSTAMP) == TSNEP_TX_TYPE_SKB_TSTAMP) &&
                    (__le32_to_cpu(entry->desc_wb->properties) &
                     TSNEP_DESC_EXTENDED_WRITEBACK_FLAG)) {
                        struct skb_shared_hwtstamps hwtstamps;