net: stmmac: set total length of the packet to be transmitted in TDES3
authorNiklas Cassel <niklas.cassel@axis.com>
Mon, 10 Apr 2017 18:33:29 +0000 (20:33 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 13 Apr 2017 16:40:09 +0000 (12:40 -0400)
Field FL/TPL in register TDES3 is not correctly set on GMAC4.
TX appears to be functional on GMAC 4.10a even if this field is not set,
however, to avoid relying on undefined behavior, set the length in TDES3.

The field has a different meaning depending on if the TSE bit in TDES3
is set or not (TSO). However, regardless of the TSE bit, the field is
not optional. The field is already set correctly when the TSE bit is set.

Since there is no limit for the number of descriptors that can be
used for a single packet, the field should be set to the sum of
the buffers contained in:
[<desc with First Descriptor bit set> ... <desc n> ...
<desc with Last Descriptor bit set>], which should be equal to skb->len.

Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index 37881f81319e760df60a47944f56bab3658142b4..e93c40b4631ecfd706cb0b7c16d58fa5089aa35f 100644 (file)
@@ -52,7 +52,7 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
        tx_q->tx_skbuff_dma[entry].len = bmax;
        /* do not close the descriptor and do not set own bit */
        priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
-                                       0, false);
+                                       0, false, skb->len);
 
        while (len != 0) {
                tx_q->tx_skbuff[entry] = NULL;
@@ -70,7 +70,7 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        tx_q->tx_skbuff_dma[entry].len = bmax;
                        priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
                                                        STMMAC_CHAIN_MODE, 1,
-                                                       false);
+                                                       false, skb->len);
                        len -= bmax;
                        i++;
                } else {
@@ -85,7 +85,7 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        /* last descriptor can be set now */
                        priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
                                                        STMMAC_CHAIN_MODE, 1,
-                                                       true);
+                                                       true, skb->len);
                        len = 0;
                }
        }
index 90d28bcad8804f9a60c5c84a994ead8fca3cee7c..b7ce3fbb53757a4cb4dd7405e1683d0fc784870c 100644 (file)
@@ -373,7 +373,7 @@ struct stmmac_desc_ops {
        /* Invoked by the xmit function to prepare the tx descriptor */
        void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
                                 bool csum_flag, int mode, bool tx_own,
-                                bool ls);
+                                bool ls, unsigned int tot_pkt_len);
        void (*prepare_tso_tx_desc)(struct dma_desc *p, int is_fs, int len1,
                                    int len2, bool tx_own, bool ls,
                                    unsigned int tcphdrlen,
index 843ec69222eacd69f6107a0f6f1cceac83b2667f..aa6476439aee7f4c65784af4a451a8ffe5173561 100644 (file)
@@ -304,12 +304,13 @@ static void dwmac4_rd_init_tx_desc(struct dma_desc *p, int mode, int end)
 
 static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                                      bool csum_flag, int mode, bool tx_own,
-                                     bool ls)
+                                     bool ls, unsigned int tot_pkt_len)
 {
        unsigned int tdes3 = le32_to_cpu(p->des3);
 
        p->des2 |= cpu_to_le32(len & TDES2_BUFFER1_SIZE_MASK);
 
+       tdes3 |= tot_pkt_len & TDES3_PACKET_SIZE_MASK;
        if (is_fs)
                tdes3 |= TDES3_FIRST_DESCRIPTOR;
        else
index 323b59ec74a35f4f318060f02d74c3b17af40d5d..7546b3664113a3d776fe19094df71b2adfb99e98 100644 (file)
@@ -315,7 +315,7 @@ static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
 
 static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                                     bool csum_flag, int mode, bool tx_own,
-                                    bool ls)
+                                    bool ls, unsigned int tot_pkt_len)
 {
        unsigned int tdes0 = le32_to_cpu(p->des0);
 
index efb818ebd55e26c13b899c2180faf0ba0ed64609..f817f8f365696d3388e73f85710d30dde43a7d41 100644 (file)
@@ -191,7 +191,7 @@ static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 
 static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
                                  bool csum_flag, int mode, bool tx_own,
-                                 bool ls)
+                                 bool ls, unsigned int tot_pkt_len)
 {
        unsigned int tdes1 = le32_to_cpu(p->des1);
 
index 31213e64513dba604eb9ead1f052a1d7289cb223..28e4b5d50ce6c0afc9c0e03dd5dc312009acda02 100644 (file)
@@ -59,7 +59,8 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 
                desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
                priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
-                                               STMMAC_RING_MODE, 0, false);
+                                               STMMAC_RING_MODE, 0,
+                                               false, skb->len);
                tx_q->tx_skbuff[entry] = NULL;
                entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
 
@@ -79,7 +80,8 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 
                desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
-                                               STMMAC_RING_MODE, 1, true);
+                                               STMMAC_RING_MODE, 1,
+                                               true, skb->len);
        } else {
                des2 = dma_map_single(priv->device, skb->data,
                                      nopaged_len, DMA_TO_DEVICE);
@@ -91,7 +93,8 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                tx_q->tx_skbuff_dma[entry].is_jumbo = true;
                desc->des3 = cpu_to_le32(des2 + BUF_SIZE_4KiB);
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
-                                               STMMAC_RING_MODE, 0, true);
+                                               STMMAC_RING_MODE, 0,
+                                               true, skb->len);
        }
 
        tx_q->cur_tx = entry;
index 85f315e01c1d8f6b7c524edf9aa40e7c54a4dc83..cd8c601323905a7ded2504fa69faa54a1c728066 100644 (file)
@@ -3033,7 +3033,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* Prepare the descriptor and set the own bit too */
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
-                                               priv->mode, 1, last_segment);
+                                               priv->mode, 1, last_segment,
+                                               skb->len);
        }
 
        entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
@@ -3116,7 +3117,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Prepare the first descriptor setting the OWN bit too */
                priv->hw->desc->prepare_tx_desc(first, 1, nopaged_len,
                                                csum_insertion, priv->mode, 1,
-                                               last_segment);
+                                               last_segment, skb->len);
 
                /* The own bit must be the latest setting done when prepare the
                 * descriptor and then barrier is needed to make sure that