Otherwise, we cannot undo our work if an error condition arises
later.

Signed-off-by: Troy Kisky <troy.ki...@boundarydevices.com>
---
 drivers/net/ethernet/freescale/fec_main.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c 
b/drivers/net/ethernet/freescale/fec_main.c
index b829c29..ee6cd69 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -590,7 +590,8 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, 
struct sk_buff *skb,
 static int
 fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
                         struct sk_buff *skb, struct net_device *ndev,
-                        struct bufdesc *bdp, int index)
+                        struct bufdesc *bdp, int index,
+                        unsigned short *pstatus)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
@@ -632,9 +633,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
                ebdp->cbd_bdu = 0;
                ebdp->cbd_esc = estatus;
        }
-
-       bdp->cbd_sc = status;
-
+       *pstatus = status;
        return 0;
 }
 
@@ -646,7 +645,10 @@ static int fec_enet_txq_submit_tso(struct 
fec_enet_priv_tx_q *txq,
        int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        int total_len, data_left;
        struct bufdesc *bdp = txq->bd.cur;
+       struct bufdesc *first_bdp = bdp;
        struct tso_t tso;
+       unsigned short status = 0;
+       unsigned short *pstatus = &status;
        unsigned int index = 0;
        int ret;
 
@@ -676,7 +678,8 @@ static int fec_enet_txq_submit_tso(struct 
fec_enet_priv_tx_q *txq,
                /* prepare packet headers: MAC + IP + TCP */
                hdr = txq->tso_hdrs + index * TSO_HEADER_SIZE;
                tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0);
-               ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index);
+               ret = fec_enet_txq_put_hdr_tso(txq, skb, ndev, bdp, index,
+                                              pstatus);
                if (ret)
                        goto err_release;
 
@@ -700,12 +703,23 @@ static int fec_enet_txq_submit_tso(struct 
fec_enet_priv_tx_q *txq,
                }
 
                bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
+               pstatus = &bdp->cbd_sc;
        }
 
        /* Save skb pointer */
        txq->tx_skbuff[index] = skb;
-
        skb_tx_timestamp(skb);
+       /* Make sure the updates to rest of the descriptor are performed before
+        * transferring ownership.
+        */
+       wmb();
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        */
+       first_bdp->cbd_sc = status;
+       /* Make sure ownership is transferred before the
+        * update to txq->bd.cur.
+        */
+       wmb();
        txq->bd.cur = bdp;
 
        /* Trigger transmission start */
-- 
2.5.0

Reply via email to