aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/synopsys
diff options
context:
space:
mode:
authorLars Persson <lars.persson@axis.com>2016-02-29 10:22:34 -0500
committerDavid S. Miller <davem@davemloft.net>2016-03-02 14:57:15 -0500
commitcd5e41234729966153595fd3c2a7912cc4f95bc2 (patch)
tree78358e05f119d0b5b0859e55c4c1ed1bc608c580 /drivers/net/ethernet/synopsys
parent016a91c64de6621e5917b2ddfe2afc0abb0a884c (diff)
dwc_eth_qos: do phy_start before resetting hardware
This reverts the changed init order from commit 3647bc35bd42 ("dwc_eth_qos: Reset hardware before PHY start") and makes another fix for the race. It turned out that the reset state machine of the dwceqos hardware requires PHY clocks to be present in order to complete the reset cycle. To plug the race with the phy state machine we defer link speed setting until the hardware init has finished. Signed-off-by: Lars Persson <larper@axis.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/synopsys')
-rw-r--r--drivers/net/ethernet/synopsys/dwc_eth_qos.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
index 6897c1d0f86e..af11ed1e0bcc 100644
--- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c
+++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
@@ -650,6 +650,11 @@ struct net_local {
650 u32 mmc_tx_counters_mask; 650 u32 mmc_tx_counters_mask;
651 651
652 struct dwceqos_flowcontrol flowcontrol; 652 struct dwceqos_flowcontrol flowcontrol;
653
654 /* Tracks the intermediate state of phy started but hardware
655 * init not finished yet.
656 */
657 bool phy_defer;
653}; 658};
654 659
655static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask, 660static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask,
@@ -901,6 +906,9 @@ static void dwceqos_adjust_link(struct net_device *ndev)
901 struct phy_device *phydev = lp->phy_dev; 906 struct phy_device *phydev = lp->phy_dev;
902 int status_change = 0; 907 int status_change = 0;
903 908
909 if (lp->phy_defer)
910 return;
911
904 if (phydev->link) { 912 if (phydev->link) {
905 if ((lp->speed != phydev->speed) || 913 if ((lp->speed != phydev->speed) ||
906 (lp->duplex != phydev->duplex)) { 914 (lp->duplex != phydev->duplex)) {
@@ -1635,6 +1643,12 @@ static void dwceqos_init_hw(struct net_local *lp)
1635 regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG); 1643 regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG);
1636 dwceqos_write(lp, REG_DWCEQOS_MAC_CFG, 1644 dwceqos_write(lp, REG_DWCEQOS_MAC_CFG,
1637 regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE); 1645 regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE);
1646
1647 lp->phy_defer = false;
1648 mutex_lock(&lp->phy_dev->lock);
1649 phy_read_status(lp->phy_dev);
1650 dwceqos_adjust_link(lp->ndev);
1651 mutex_unlock(&lp->phy_dev->lock);
1638} 1652}
1639 1653
1640static void dwceqos_tx_reclaim(unsigned long data) 1654static void dwceqos_tx_reclaim(unsigned long data)
@@ -1880,9 +1894,13 @@ static int dwceqos_open(struct net_device *ndev)
1880 } 1894 }
1881 netdev_reset_queue(ndev); 1895 netdev_reset_queue(ndev);
1882 1896
1897 /* The dwceqos reset state machine requires all phy clocks to complete,
1898 * hence the unusual init order with phy_start first.
1899 */
1900 lp->phy_defer = true;
1901 phy_start(lp->phy_dev);
1883 dwceqos_init_hw(lp); 1902 dwceqos_init_hw(lp);
1884 napi_enable(&lp->napi); 1903 napi_enable(&lp->napi);
1885 phy_start(lp->phy_dev);
1886 1904
1887 netif_start_queue(ndev); 1905 netif_start_queue(ndev);
1888 tasklet_enable(&lp->tx_bdreclaim_tasklet); 1906 tasklet_enable(&lp->tx_bdreclaim_tasklet);
@@ -1915,8 +1933,6 @@ static int dwceqos_stop(struct net_device *ndev)
1915{ 1933{
1916 struct net_local *lp = netdev_priv(ndev); 1934 struct net_local *lp = netdev_priv(ndev);
1917 1935
1918 phy_stop(lp->phy_dev);
1919
1920 tasklet_disable(&lp->tx_bdreclaim_tasklet); 1936 tasklet_disable(&lp->tx_bdreclaim_tasklet);
1921 napi_disable(&lp->napi); 1937 napi_disable(&lp->napi);
1922 1938
@@ -1927,6 +1943,7 @@ static int dwceqos_stop(struct net_device *ndev)
1927 1943
1928 dwceqos_drain_dma(lp); 1944 dwceqos_drain_dma(lp);
1929 dwceqos_reset_hw(lp); 1945 dwceqos_reset_hw(lp);
1946 phy_stop(lp->phy_dev);
1930 1947
1931 dwceqos_descriptor_free(lp); 1948 dwceqos_descriptor_free(lp);
1932 1949