net: ftgmac100: Ensure tx descriptor updates are visible
[ Upstream commit 4186c8d9e6af57bab0687b299df10ebd47534a0a ] 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: Jacky Chou <jacky_chou@aspeedtech.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a5bfdf7e4d
commit
46974d97d5
@@ -579,7 +579,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);
|
||||||
@@ -663,6 +663,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;
|
||||||
@@ -816,6 +821,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;
|
||||||
|
|
||||||
@@ -836,7 +846,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");
|
||||||
|
|
||||||
@@ -858,7 +868,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++;
|
||||||
@@ -1444,7 +1454,7 @@ static void ftgmac100_reset_task(struct work_struct *work)
|
|||||||
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)
|
||||||
@@ -1515,15 +1525,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;
|
||||||
|
|||||||
Reference in New Issue
Block a user