net: renesas: rswitch: Fix timestamp feature after all descriptors are used
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Thu, 8 Jun 2023 01:57:27 +0000 (10:57 +0900)
committerDavid S. Miller <davem@davemloft.net>
Fri, 9 Jun 2023 09:41:09 +0000 (10:41 +0100)
The timestamp descriptors were intended to act cyclically. Descriptors
from index 0 through gq->ring_size - 1 contain actual information, and
the last index (gq->ring_size) should have LINKFIX to indicate
the first index 0 descriptor. However, the LINKFIX value is missing,
causing the timestamp feature to stop after all descriptors are used.
To resolve this issue, set the LINKFIX to the timestamp descritors.

Reported-by: Phong Hoang <phong.hoang.wz@renesas.com>
Fixes: 33f5d733b589 ("net: renesas: rswitch: Improve TX timestamp accuracy")
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/renesas/rswitch.c

index aace871..fa6d620 100644 (file)
@@ -347,17 +347,6 @@ out:
        return -ENOMEM;
 }
 
-static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
-{
-       struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
-
-       gq->ring_size = TS_RING_SIZE;
-       gq->ts_ring = dma_alloc_coherent(&priv->pdev->dev,
-                                        sizeof(struct rswitch_ts_desc) *
-                                        (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
-       return !gq->ts_ring ? -ENOMEM : 0;
-}
-
 static void rswitch_desc_set_dptr(struct rswitch_desc *desc, dma_addr_t addr)
 {
        desc->dptrl = cpu_to_le32(lower_32_bits(addr));
@@ -533,6 +522,28 @@ static void rswitch_gwca_linkfix_free(struct rswitch_private *priv)
        gwca->linkfix_table = NULL;
 }
 
+static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
+{
+       struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
+       struct rswitch_ts_desc *desc;
+
+       gq->ring_size = TS_RING_SIZE;
+       gq->ts_ring = dma_alloc_coherent(&priv->pdev->dev,
+                                        sizeof(struct rswitch_ts_desc) *
+                                        (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
+
+       if (!gq->ts_ring)
+               return -ENOMEM;
+
+       rswitch_gwca_ts_queue_fill(priv, 0, TS_RING_SIZE);
+       desc = &gq->ts_ring[gq->ring_size];
+       desc->desc.die_dt = DT_LINKFIX;
+       rswitch_desc_set_dptr(&desc->desc, gq->ring_dma);
+       INIT_LIST_HEAD(&priv->gwca.ts_info_list);
+
+       return 0;
+}
+
 static struct rswitch_gwca_queue *rswitch_gwca_get(struct rswitch_private *priv)
 {
        struct rswitch_gwca_queue *gq;
@@ -1780,9 +1791,6 @@ static int rswitch_init(struct rswitch_private *priv)
        if (err < 0)
                goto err_ts_queue_alloc;
 
-       rswitch_gwca_ts_queue_fill(priv, 0, TS_RING_SIZE);
-       INIT_LIST_HEAD(&priv->gwca.ts_info_list);
-
        for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
                err = rswitch_device_alloc(priv, i);
                if (err < 0) {