Commit c363b658 authored by Fabrice Gasnier's avatar Fabrice Gasnier Committed by David S. Miller

stmmac: optimize tx clean function

This patch "inline" get_tx_owner and get_ls routines. It Results in a
unique read to tdes0, instead of three, to check TX_OWN and LS bits,
and other status bits.

It helps improve driver TX path by removing two uncached read/writes
inside TX clean loop for enhanced descriptors but not for normal ones
because the des1 must be read in any case.
Signed-off-by: default avatarFabrice Gasnier <fabrice.gasnier@st.com>
Acked-by: default avatarGiuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: default avatarAlexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent be434d50
...@@ -245,6 +245,14 @@ enum rx_frame_status { ...@@ -245,6 +245,14 @@ enum rx_frame_status {
dma_own = 0x8, dma_own = 0x8,
}; };
/* Tx status */
enum tx_frame_status {
tx_done = 0x0,
tx_not_ls = 0x1,
tx_err = 0x2,
tx_dma_own = 0x4,
};
enum dma_irq_status { enum dma_irq_status {
tx_hard_error = 0x1, tx_hard_error = 0x1,
tx_hard_error_bump_tc = 0x2, tx_hard_error_bump_tc = 0x2,
......
...@@ -31,7 +31,15 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -31,7 +31,15 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
{ {
struct net_device_stats *stats = (struct net_device_stats *)data; struct net_device_stats *stats = (struct net_device_stats *)data;
unsigned int tdes0 = p->des0; unsigned int tdes0 = p->des0;
int ret = 0; int ret = tx_done;
/* Get tx owner first */
if (unlikely(tdes0 & ETDES0_OWN))
return tx_dma_own;
/* Verify tx error by looking at the last segment. */
if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
return tx_not_ls;
if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) { if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT)) if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
...@@ -71,7 +79,7 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -71,7 +79,7 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
dwmac_dma_flush_tx_fifo(ioaddr); dwmac_dma_flush_tx_fifo(ioaddr);
} }
ret = -1; ret = tx_err;
} }
if (unlikely(tdes0 & ETDES0_DEFERRED)) if (unlikely(tdes0 & ETDES0_DEFERRED))
......
...@@ -31,7 +31,16 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -31,7 +31,16 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
{ {
struct net_device_stats *stats = (struct net_device_stats *)data; struct net_device_stats *stats = (struct net_device_stats *)data;
unsigned int tdes0 = p->des0; unsigned int tdes0 = p->des0;
int ret = 0; unsigned int tdes1 = p->des1;
int ret = tx_done;
/* Get tx owner first */
if (unlikely(tdes0 & TDES0_OWN))
return tx_dma_own;
/* Verify tx error by looking at the last segment. */
if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
return tx_not_ls;
if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) { if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) { if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
...@@ -54,7 +63,7 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, ...@@ -54,7 +63,7 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3; collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
stats->collisions += collisions; stats->collisions += collisions;
} }
ret = -1; ret = tx_err;
} }
if (tdes0 & TDES0_VLAN_FRAME) if (tdes0 & TDES0_VLAN_FRAME)
......
...@@ -1313,32 +1313,31 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) ...@@ -1313,32 +1313,31 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->xstats.tx_clean++; priv->xstats.tx_clean++;
while (entry != priv->cur_tx) { while (entry != priv->cur_tx) {
int last;
struct sk_buff *skb = priv->tx_skbuff[entry]; struct sk_buff *skb = priv->tx_skbuff[entry];
struct dma_desc *p; struct dma_desc *p;
int status;
if (priv->extend_desc) if (priv->extend_desc)
p = (struct dma_desc *)(priv->dma_etx + entry); p = (struct dma_desc *)(priv->dma_etx + entry);
else else
p = priv->dma_tx + entry; p = priv->dma_tx + entry;
/* Check if the descriptor is owned by the DMA. */ status = priv->hw->desc->tx_status(&priv->dev->stats,
if (priv->hw->desc->get_tx_owner(p))
break;
/* Verify tx error by looking at the last segment. */
last = priv->tx_skbuff_dma[entry].last_segment;
if (likely(last)) {
int tx_error =
priv->hw->desc->tx_status(&priv->dev->stats,
&priv->xstats, p, &priv->xstats, p,
priv->ioaddr); priv->ioaddr);
if (likely(tx_error == 0)) { /* Check if the descriptor is owned by the DMA */
if (unlikely(status & tx_dma_own))
break;
/* Just consider the last segment and ...*/
if (likely(!(status & tx_not_ls))) {
/* ... verify the status error condition */
if (unlikely(status & tx_err)) {
priv->dev->stats.tx_errors++;
} else {
priv->dev->stats.tx_packets++; priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++; priv->xstats.tx_pkt_n++;
} else }
priv->dev->stats.tx_errors++;
stmmac_get_tx_hwtstamp(priv, entry, skb); stmmac_get_tx_hwtstamp(priv, entry, skb);
} }
if (netif_msg_tx_done(priv)) if (netif_msg_tx_done(priv))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment