From e19d0839e75718a0b06db66f6f7ec2df515ae0c2 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 23 Feb 2016 11:48:37 +0200 Subject: [PATCH 1/3] gianfar: Map head TxBD first Move the mapping of the head BD before the mapping of fragments. The TOE (h/w offload) decision logic block can be also moved up (as the TOE flag belongs to the head BD), resulting in more localized code (TOE logic vs BD mapping code blocks). Note that, for this h/w, the R (status) bit for the head BD of a S/G frame needs to be written last for a reliable transmission. For the fragmented skb case, a local variable is used to temporarily store the status info of the first BD, replacing a BD status read. A merge of 2 "if(do_tstamp)" blocks was also possible. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 104 +++++++++++------------ 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 2aa7b401cc3b..cb80dba8dd2b 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2389,52 +2389,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp = txbdp_start = tx_queue->cur_tx; lstatus = be32_to_cpu(txbdp->lstatus); - /* Time stamp insertion requires one additional TxBD */ - if (unlikely(do_tstamp)) - txbdp_tstamp = txbdp = next_txbd(txbdp, base, - tx_queue->tx_ring_size); - - if (nr_frags == 0) { - if (unlikely(do_tstamp)) { - u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus); - - lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts); - } else { - lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - } - } else { - /* Place the fragment addresses and lengths into the TxBDs */ - for (i = 0; i < nr_frags; i++) { - unsigned int frag_len; - /* Point at the next BD, wrapping as needed */ - txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); - - frag_len = skb_shinfo(skb)->frags[i].size; - - lstatus = be32_to_cpu(txbdp->lstatus) | frag_len | - BD_LFLAG(TXBD_READY); - - /* Handle the last BD specially */ - if (i == nr_frags - 1) - lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - - bufaddr = skb_frag_dma_map(priv->dev, - &skb_shinfo(skb)->frags[i], - 0, - frag_len, - DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(priv->dev, bufaddr))) - goto dma_map_err; - - /* set the TxBD length and buffer pointer */ - txbdp->bufPtr = cpu_to_be32(bufaddr); - txbdp->lstatus = cpu_to_be32(lstatus); - } - - lstatus = be32_to_cpu(txbdp_start->lstatus); - } - /* Add TxPAL between FCB and frame if required */ if (unlikely(do_tstamp)) { skb_push(skb, GMAC_TXPAL_LEN); @@ -2469,12 +2423,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) if (do_vlan) gfar_tx_vlan(skb, fcb); - /* Setup tx hardware time stamping if requested */ - if (unlikely(do_tstamp)) { - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - fcb->ptp = 1; - } - bufaddr = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); if (unlikely(dma_mapping_error(priv->dev, bufaddr))) @@ -2482,6 +2430,54 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp_start->bufPtr = cpu_to_be32(bufaddr); + /* Time stamp insertion requires one additional TxBD */ + if (unlikely(do_tstamp)) + txbdp_tstamp = txbdp = next_txbd(txbdp, base, + tx_queue->tx_ring_size); + + if (nr_frags == 0) { + if (unlikely(do_tstamp)) { + u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus); + + lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts); + } else { + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + } + } else { + u32 lstatus_start = lstatus; + + /* Place the fragment addresses and lengths into the TxBDs */ + for (i = 0; i < nr_frags; i++) { + unsigned int frag_len; + /* Point at the next BD, wrapping as needed */ + txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); + + frag_len = skb_shinfo(skb)->frags[i].size; + + lstatus = be32_to_cpu(txbdp->lstatus) | frag_len | + BD_LFLAG(TXBD_READY); + + /* Handle the last BD specially */ + if (i == nr_frags - 1) + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + + bufaddr = skb_frag_dma_map(priv->dev, + &skb_shinfo(skb)->frags[i], + 0, + frag_len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(priv->dev, bufaddr))) + goto dma_map_err; + + /* set the TxBD length and buffer pointer */ + txbdp->bufPtr = cpu_to_be32(bufaddr); + txbdp->lstatus = cpu_to_be32(lstatus); + } + + lstatus = lstatus_start; + } + /* If time stamping is requested one additional TxBD must be set up. The * first TxBD points to the FCB and must have a data length of * GMAC_FCB_LEN. The second TxBD points to the actual frame data with @@ -2498,6 +2494,10 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp_tstamp->bufPtr = cpu_to_be32(bufaddr); txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts); lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN; + + /* Setup tx hardware time stamping */ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + fcb->ptp = 1; } else { lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); } From 42f397adfc0a062a17119c08c82ed710b143a006 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 23 Feb 2016 11:48:38 +0200 Subject: [PATCH 2/3] gianfar: Use skb_frag_t pointers inside xmit() Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index cb80dba8dd2b..7b16ce637a8e 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2322,6 +2322,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) struct txfcb *fcb = NULL; struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL; u32 lstatus; + skb_frag_t *frag; int i, rq = 0; int do_tstamp, do_csum, do_vlan; u32 bufaddr; @@ -2448,25 +2449,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 lstatus_start = lstatus; /* Place the fragment addresses and lengths into the TxBDs */ - for (i = 0; i < nr_frags; i++) { - unsigned int frag_len; + frag = &skb_shinfo(skb)->frags[0]; + for (i = 0; i < nr_frags; i++, frag++) { + unsigned int size; + /* Point at the next BD, wrapping as needed */ txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); - frag_len = skb_shinfo(skb)->frags[i].size; + size = skb_frag_size(frag); - lstatus = be32_to_cpu(txbdp->lstatus) | frag_len | + lstatus = be32_to_cpu(txbdp->lstatus) | size | BD_LFLAG(TXBD_READY); /* Handle the last BD specially */ if (i == nr_frags - 1) lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - bufaddr = skb_frag_dma_map(priv->dev, - &skb_shinfo(skb)->frags[i], - 0, - frag_len, - DMA_TO_DEVICE); + bufaddr = skb_frag_dma_map(priv->dev, frag, 0, + size, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(priv->dev, bufaddr))) goto dma_map_err; From 48963b4492e98fd3b3040755a16215d72552f1bb Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 23 Feb 2016 11:48:39 +0200 Subject: [PATCH 3/3] gianfar: Remove redundant ops for do_tstamp from xmit() Timestamp BD status updates that can be merged into the same "do_tstamp" block, no need for extra save/restore to the BD area. The code is more readable too. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 7b16ce637a8e..1e1157fa77f4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2436,15 +2436,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) txbdp_tstamp = txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size); - if (nr_frags == 0) { - if (unlikely(do_tstamp)) { - u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus); - - lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts); - } else { - lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); - } + if (likely(!nr_frags)) { + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); } else { u32 lstatus_start = lstatus; @@ -2488,8 +2481,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) bufaddr = be32_to_cpu(txbdp_start->bufPtr); bufaddr += fcb_len; + lstatus_ts |= BD_LFLAG(TXBD_READY) | (skb_headlen(skb) - fcb_len); + if (!nr_frags) + lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); txbdp_tstamp->bufPtr = cpu_to_be32(bufaddr); txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);