Skip to content

Commit cd5e412

Browse files
larperaxisdavem330
authored andcommitted
dwc_eth_qos: do phy_start before resetting hardware
This reverts the changed init order from commit 3647bc3 ("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>
1 parent 016a91c commit cd5e412

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

drivers/net/ethernet/synopsys/dwc_eth_qos.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,11 @@ struct net_local {
650650
u32 mmc_tx_counters_mask;
651651

652652
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;
653658
};
654659

655660
static 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)
901906
struct phy_device *phydev = lp->phy_dev;
902907
int status_change = 0;
903908

909+
if (lp->phy_defer)
910+
return;
911+
904912
if (phydev->link) {
905913
if ((lp->speed != phydev->speed) ||
906914
(lp->duplex != phydev->duplex)) {
@@ -1635,6 +1643,12 @@ static void dwceqos_init_hw(struct net_local *lp)
16351643
regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG);
16361644
dwceqos_write(lp, REG_DWCEQOS_MAC_CFG,
16371645
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);
16381652
}
16391653

16401654
static void dwceqos_tx_reclaim(unsigned long data)
@@ -1880,9 +1894,13 @@ static int dwceqos_open(struct net_device *ndev)
18801894
}
18811895
netdev_reset_queue(ndev);
18821896

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);
18831902
dwceqos_init_hw(lp);
18841903
napi_enable(&lp->napi);
1885-
phy_start(lp->phy_dev);
18861904

18871905
netif_start_queue(ndev);
18881906
tasklet_enable(&lp->tx_bdreclaim_tasklet);
@@ -1915,8 +1933,6 @@ static int dwceqos_stop(struct net_device *ndev)
19151933
{
19161934
struct net_local *lp = netdev_priv(ndev);
19171935

1918-
phy_stop(lp->phy_dev);
1919-
19201936
tasklet_disable(&lp->tx_bdreclaim_tasklet);
19211937
napi_disable(&lp->napi);
19221938

@@ -1927,6 +1943,7 @@ static int dwceqos_stop(struct net_device *ndev)
19271943

19281944
dwceqos_drain_dma(lp);
19291945
dwceqos_reset_hw(lp);
1946+
phy_stop(lp->phy_dev);
19301947

19311948
dwceqos_descriptor_free(lp);
19321949

0 commit comments

Comments
 (0)