tsnep: fix timestamping with a stacked DSA driver
[ Upstream commit b3ca9eef6646576ad506a96d941d87a69f66732a ] This driver is susceptible to a form of the bug explained in commitc26a2c2ddc
("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:403f69bbdb
("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
0980e62ab8
commit
c1dd9ccc0f
@@ -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)
|
||||
@@ -385,8 +387,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
|
||||
@@ -478,7 +479,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;
|
||||
@@ -504,6 +506,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];
|
||||
|
||||
@@ -557,11 +562,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;
|
||||
@@ -578,7 +584,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);
|
||||
@@ -590,9 +602,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);
|
||||
@@ -843,8 +852,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;
|
||||
|
Reference in New Issue
Block a user