Commit 4186c8d9 authored by Jacky Chou's avatar Jacky Chou Committed by David S. Miller

net: ftgmac100: Ensure tx descriptor updates are visible

The driver must ensure TX descriptor updates are visible
before updating TX pointer and TX clear pointer.

This resolves TX hangs observed on AST2600 when running
iperf3.
Signed-off-by: default avatarJacky Chou <jacky_chou@aspeedtech.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8af174ea
...@@ -572,7 +572,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) ...@@ -572,7 +572,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
(*processed)++; (*processed)++;
return true; return true;
drop: drop:
/* Clean rxdes0 (which resets own bit) */ /* Clean rxdes0 (which resets own bit) */
rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask); rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);
priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer); priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
...@@ -656,6 +656,11 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) ...@@ -656,6 +656,11 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat); ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask); txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
/* Ensure the descriptor config is visible before setting the tx
* pointer.
*/
smp_wmb();
priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer); priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer);
return true; return true;
...@@ -809,6 +814,11 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -809,6 +814,11 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
dma_wmb(); dma_wmb();
first->txdes0 = cpu_to_le32(f_ctl_stat); first->txdes0 = cpu_to_le32(f_ctl_stat);
/* Ensure the descriptor config is visible before setting the tx
* pointer.
*/
smp_wmb();
/* Update next TX pointer */ /* Update next TX pointer */
priv->tx_pointer = pointer; priv->tx_pointer = pointer;
...@@ -829,7 +839,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -829,7 +839,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
dma_err: dma_err:
if (net_ratelimit()) if (net_ratelimit())
netdev_err(netdev, "map tx fragment failed\n"); netdev_err(netdev, "map tx fragment failed\n");
...@@ -851,7 +861,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -851,7 +861,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
* last fragment, so we know ftgmac100_free_tx_packet() * last fragment, so we know ftgmac100_free_tx_packet()
* hasn't freed the skb yet. * hasn't freed the skb yet.
*/ */
drop: drop:
/* Drop the packet */ /* Drop the packet */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
netdev->stats.tx_dropped++; netdev->stats.tx_dropped++;
...@@ -1344,7 +1354,7 @@ static void ftgmac100_reset(struct ftgmac100 *priv) ...@@ -1344,7 +1354,7 @@ static void ftgmac100_reset(struct ftgmac100 *priv)
ftgmac100_init_all(priv, true); ftgmac100_init_all(priv, true);
netdev_dbg(netdev, "Reset done !\n"); netdev_dbg(netdev, "Reset done !\n");
bail: bail:
if (priv->mii_bus) if (priv->mii_bus)
mutex_unlock(&priv->mii_bus->mdio_lock); mutex_unlock(&priv->mii_bus->mdio_lock);
if (netdev->phydev) if (netdev->phydev)
...@@ -1543,15 +1553,15 @@ static int ftgmac100_open(struct net_device *netdev) ...@@ -1543,15 +1553,15 @@ static int ftgmac100_open(struct net_device *netdev)
return 0; return 0;
err_ncsi: err_ncsi:
napi_disable(&priv->napi); napi_disable(&priv->napi);
netif_stop_queue(netdev); netif_stop_queue(netdev);
err_alloc: err_alloc:
ftgmac100_free_buffers(priv); ftgmac100_free_buffers(priv);
free_irq(netdev->irq, netdev); free_irq(netdev->irq, netdev);
err_irq: err_irq:
netif_napi_del(&priv->napi); netif_napi_del(&priv->napi);
err_hw: err_hw:
iowrite32(0, priv->base + FTGMAC100_OFFSET_IER); iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
ftgmac100_free_rings(priv); ftgmac100_free_rings(priv);
return err; return err;
......
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