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 <claudiu.manoil@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9e4e6206c6
commit
e19d0839e7
1 changed files with 52 additions and 52 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue