diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2014-09-22 14:54:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-22 18:38:40 -0400 |
commit | 4a0c081eff43a11c65dee3ad6c457f7f58bcebe0 (patch) | |
tree | 055ff5d64bf6a601eb5165c0820fcb18db998121 /drivers/net/ethernet/broadcom/genet/bcmgenet.c | |
parent | 478a010c9235ca92e66cc5058b42e30e33275ad4 (diff) |
net: bcmgenet: call bcmgenet_dma_teardown in bcmgenet_fini_dma
We should not be manipulaging the DMA_CTRL registers directly by writing
0 to them to disable DMA. This is an operation that needs to be timed to
make sure the DMA engines have been properly stopped since their state
machine stops on a packet boundary, not immediately.
Make sure that tha bcmgenet_fini_dma() calls bcmgenet_dma_teardown() to
ensure a proper DMA engine state. As a result, we need to reorder the
function bodies to resolve the use dependency.
Fixes: 1c1008c793fa ("net: bcmgenet: add main driver file")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/genet/bcmgenet.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 105 |
1 files changed, 52 insertions, 53 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 11a96437862d..5cc9cae21ed5 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | |||
@@ -1744,13 +1744,63 @@ static void bcmgenet_init_multiq(struct net_device *dev) | |||
1744 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); | 1744 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); |
1745 | } | 1745 | } |
1746 | 1746 | ||
1747 | static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) | ||
1748 | { | ||
1749 | int ret = 0; | ||
1750 | int timeout = 0; | ||
1751 | u32 reg; | ||
1752 | |||
1753 | /* Disable TDMA to stop add more frames in TX DMA */ | ||
1754 | reg = bcmgenet_tdma_readl(priv, DMA_CTRL); | ||
1755 | reg &= ~DMA_EN; | ||
1756 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); | ||
1757 | |||
1758 | /* Check TDMA status register to confirm TDMA is disabled */ | ||
1759 | while (timeout++ < DMA_TIMEOUT_VAL) { | ||
1760 | reg = bcmgenet_tdma_readl(priv, DMA_STATUS); | ||
1761 | if (reg & DMA_DISABLED) | ||
1762 | break; | ||
1763 | |||
1764 | udelay(1); | ||
1765 | } | ||
1766 | |||
1767 | if (timeout == DMA_TIMEOUT_VAL) { | ||
1768 | netdev_warn(priv->dev, "Timed out while disabling TX DMA\n"); | ||
1769 | ret = -ETIMEDOUT; | ||
1770 | } | ||
1771 | |||
1772 | /* Wait 10ms for packet drain in both tx and rx dma */ | ||
1773 | usleep_range(10000, 20000); | ||
1774 | |||
1775 | /* Disable RDMA */ | ||
1776 | reg = bcmgenet_rdma_readl(priv, DMA_CTRL); | ||
1777 | reg &= ~DMA_EN; | ||
1778 | bcmgenet_rdma_writel(priv, reg, DMA_CTRL); | ||
1779 | |||
1780 | timeout = 0; | ||
1781 | /* Check RDMA status register to confirm RDMA is disabled */ | ||
1782 | while (timeout++ < DMA_TIMEOUT_VAL) { | ||
1783 | reg = bcmgenet_rdma_readl(priv, DMA_STATUS); | ||
1784 | if (reg & DMA_DISABLED) | ||
1785 | break; | ||
1786 | |||
1787 | udelay(1); | ||
1788 | } | ||
1789 | |||
1790 | if (timeout == DMA_TIMEOUT_VAL) { | ||
1791 | netdev_warn(priv->dev, "Timed out while disabling RX DMA\n"); | ||
1792 | ret = -ETIMEDOUT; | ||
1793 | } | ||
1794 | |||
1795 | return ret; | ||
1796 | } | ||
1797 | |||
1747 | static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) | 1798 | static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) |
1748 | { | 1799 | { |
1749 | int i; | 1800 | int i; |
1750 | 1801 | ||
1751 | /* disable DMA */ | 1802 | /* disable DMA */ |
1752 | bcmgenet_rdma_writel(priv, 0, DMA_CTRL); | 1803 | bcmgenet_dma_teardown(priv); |
1753 | bcmgenet_tdma_writel(priv, 0, DMA_CTRL); | ||
1754 | 1804 | ||
1755 | for (i = 0; i < priv->num_tx_bds; i++) { | 1805 | for (i = 0; i < priv->num_tx_bds; i++) { |
1756 | if (priv->tx_cbs[i].skb != NULL) { | 1806 | if (priv->tx_cbs[i].skb != NULL) { |
@@ -2109,57 +2159,6 @@ err_clk_disable: | |||
2109 | return ret; | 2159 | return ret; |
2110 | } | 2160 | } |
2111 | 2161 | ||
2112 | static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) | ||
2113 | { | ||
2114 | int ret = 0; | ||
2115 | int timeout = 0; | ||
2116 | u32 reg; | ||
2117 | |||
2118 | /* Disable TDMA to stop add more frames in TX DMA */ | ||
2119 | reg = bcmgenet_tdma_readl(priv, DMA_CTRL); | ||
2120 | reg &= ~DMA_EN; | ||
2121 | bcmgenet_tdma_writel(priv, reg, DMA_CTRL); | ||
2122 | |||
2123 | /* Check TDMA status register to confirm TDMA is disabled */ | ||
2124 | while (timeout++ < DMA_TIMEOUT_VAL) { | ||
2125 | reg = bcmgenet_tdma_readl(priv, DMA_STATUS); | ||
2126 | if (reg & DMA_DISABLED) | ||
2127 | break; | ||
2128 | |||
2129 | udelay(1); | ||
2130 | } | ||
2131 | |||
2132 | if (timeout == DMA_TIMEOUT_VAL) { | ||
2133 | netdev_warn(priv->dev, "Timed out while disabling TX DMA\n"); | ||
2134 | ret = -ETIMEDOUT; | ||
2135 | } | ||
2136 | |||
2137 | /* Wait 10ms for packet drain in both tx and rx dma */ | ||
2138 | usleep_range(10000, 20000); | ||
2139 | |||
2140 | /* Disable RDMA */ | ||
2141 | reg = bcmgenet_rdma_readl(priv, DMA_CTRL); | ||
2142 | reg &= ~DMA_EN; | ||
2143 | bcmgenet_rdma_writel(priv, reg, DMA_CTRL); | ||
2144 | |||
2145 | timeout = 0; | ||
2146 | /* Check RDMA status register to confirm RDMA is disabled */ | ||
2147 | while (timeout++ < DMA_TIMEOUT_VAL) { | ||
2148 | reg = bcmgenet_rdma_readl(priv, DMA_STATUS); | ||
2149 | if (reg & DMA_DISABLED) | ||
2150 | break; | ||
2151 | |||
2152 | udelay(1); | ||
2153 | } | ||
2154 | |||
2155 | if (timeout == DMA_TIMEOUT_VAL) { | ||
2156 | netdev_warn(priv->dev, "Timed out while disabling RX DMA\n"); | ||
2157 | ret = -ETIMEDOUT; | ||
2158 | } | ||
2159 | |||
2160 | return ret; | ||
2161 | } | ||
2162 | |||
2163 | static void bcmgenet_netif_stop(struct net_device *dev) | 2162 | static void bcmgenet_netif_stop(struct net_device *dev) |
2164 | { | 2163 | { |
2165 | struct bcmgenet_priv *priv = netdev_priv(dev); | 2164 | struct bcmgenet_priv *priv = netdev_priv(dev); |