diff mbox series

[net,1/2] gianfar: Fix TX timestamping with stacked (DSA and PHY) drivers

Message ID 20191227004435.21692-2-olteanv@gmail.com
State Superseded
Delegated to: David Miller
Headers show
Series The DSA TX timestamping situation | expand

Commit Message

Vladimir Oltean Dec. 27, 2019, 12:44 a.m. UTC
The driver wrongly assumes that it is the only entity that can set the
SKBTX_IN_PROGRESS bit of the current skb. Therefore, in the
gfar_clean_tx_ring function, where the TX timestamp is collected if
necessary, the aforementioned bit is used to discriminate whether or not
the TX timestamp should be delivered to the socket's error queue.

But a stacked driver such as a DSA switch or a PTP-capable PHY can
also set SKBTX_IN_PROGRESS, which is actually exactly what it should do
in order to denote that the hardware timestamping process is undergoing.

Therefore, gianfar would misinterpret the "in progress" bit as being its
own, and deliver a second skb clone in the socket's error queue,
completely throwing off a PTP process which is not expecting to receive
it.

There have been discussions [0] as to whether non-MAC drivers need or not to
set SKBTX_IN_PROGRESS at all (whose purpose is to avoid sending 2
timestamps, a sw and a hw one, to applications which only expect one).
But as of this patch, there are at least 2 PTP drivers that would break
in conjunction with gianfar: the sja1105 DSA switch and the TI PHYTER
(dp83640). So until we reach a conclusion, fix the gianfar driver to not
do stuff based on flags set by others and not intended for it.

[0]: https://www.spinics.net/lists/netdev/msg619699.html

Fixes: f0ee7acfcdd4 ("gianfar: Add hardware TX timestamping support")
Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
---
 drivers/net/ethernet/freescale/gianfar.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

Comments

Richard Cochran Dec. 27, 2019, 6 p.m. UTC | #1
On Fri, Dec 27, 2019 at 02:44:34AM +0200, Vladimir Oltean wrote:

> But a stacked driver such as a DSA switch or a PTP-capable PHY can
> also set SKBTX_IN_PROGRESS, which is actually exactly what it should do
> in order to denote that the hardware timestamping process is undergoing.

Please remove the text about the PHY.  This driver does not call
skb_tx_timestamp(), and so it isn't possible for a PHY driver to set
the flag.
 
> There have been discussions [0] as to whether non-MAC drivers need or not to
> set SKBTX_IN_PROGRESS at all (whose purpose is to avoid sending 2
> timestamps, a sw and a hw one, to applications which only expect one).
> But as of this patch, there are at least 2 PTP drivers that would break
> in conjunction with gianfar: the sja1105 DSA switch and the TI PHYTER
> (dp83640).

Again, please drop the bit about the phyter.  It is a non-issue here.
The clash with the DSA layer is reason enough for this patch.

> Fixes: f0ee7acfcdd4 ("gianfar: Add hardware TX timestamping support")
> Signed-off-by: Vladimir Oltean <olteanv@gmail.com>

Acked-by: Richard Cochran <richardcochran@gmail.com>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 72868a28b621..7d08bf6370ae 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2205,13 +2205,17 @@  static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 	skb_dirtytx = tx_queue->skb_dirtytx;
 
 	while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
+		bool do_tstamp;
+
+		do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+			    priv->hwts_tx_en;
 
 		frags = skb_shinfo(skb)->nr_frags;
 
 		/* When time stamping, one additional TxBD must be freed.
 		 * Also, we need to dma_unmap_single() the TxPAL.
 		 */
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))
+		if (unlikely(do_tstamp))
 			nr_txbds = frags + 2;
 		else
 			nr_txbds = frags + 1;
@@ -2225,7 +2229,7 @@  static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 		    (lstatus & BD_LENGTH_MASK))
 			break;
 
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+		if (unlikely(do_tstamp)) {
 			next = next_txbd(bdp, base, tx_ring_size);
 			buflen = be16_to_cpu(next->length) +
 				 GMAC_FCB_LEN + GMAC_TXPAL_LEN;
@@ -2235,7 +2239,7 @@  static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 		dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr),
 				 buflen, DMA_TO_DEVICE);
 
-		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
+		if (unlikely(do_tstamp)) {
 			struct skb_shared_hwtstamps shhwtstamps;
 			u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) &
 					  ~0x7UL);