diff options
author | Robert Hancock <hancock@sedsystems.ca> | 2019-06-06 16:28:11 -0600 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-06 16:24:29 -0700 |
commit | 7789e9ed0591bab4d8a419bf3b9b18327d75128f (patch) | |
tree | 097f925ed05d6dd6b3c30b5a9a3141ecead25b50 /drivers/net/ethernet/xilinx/xilinx_axienet_main.c | |
parent | net: axienet: fix teardown order of MDIO bus (diff) | |
download | linux-dev-7789e9ed0591bab4d8a419bf3b9b18327d75128f.tar.xz linux-dev-7789e9ed0591bab4d8a419bf3b9b18327d75128f.zip |
net: axienet: Re-initialize MDIO registers properly after reset
The MDIO clock divisor register setting was only applied on the initial
startup when the driver was loaded. However, this setting is cleared
when the device is reset, such as would occur when the interface was
taken down and brought up again, and so the MDIO bus would be
non-functional afterwards.
Split up the MDIO bus setup and enable into separate functions and
re-enable the bus after a device reset, to ensure that the MDIO
registers are set properly. This also allows us to remove direct access
to MDIO registers in xilinx_axienet_main.c and centralize them all in
xilinx_axienet_mdio.c.
Also, lock the MDIO bus lock around the device reset process, to avoid
MDIO accesses from occurring while the MDIO is disabled during the reset.
Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/xilinx/xilinx_axienet_main.c')
-rw-r--r-- | drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 38 |
1 files changed, 15 insertions, 23 deletions
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 5cb39deca8d2..e735ca7b5df0 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -914,27 +914,23 @@ static void axienet_dma_err_handler(unsigned long data); */ static int axienet_open(struct net_device *ndev) { - int ret, mdio_mcreg; + int ret; struct axienet_local *lp = netdev_priv(ndev); struct phy_device *phydev = NULL; dev_dbg(&ndev->dev, "axienet_open()\n"); - mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); - ret = axienet_mdio_wait_until_ready(lp); - if (ret < 0) - return ret; /* Disable the MDIO interface till Axi Ethernet Reset is completed. * When we do an Axi Ethernet reset, it resets the complete core - * including the MDIO. If MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. + * including the MDIO. MDIO must be disabled before resetting + * and re-enabled afterwards. + * Hold MDIO bus lock to avoid MDIO accesses during the reset. */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, - (mdio_mcreg & (~XAE_MDIO_MC_MDIOEN_MASK))); + mutex_lock(&lp->mii_bus->mdio_lock); + axienet_mdio_disable(lp); axienet_device_reset(ndev); - /* Enable the MDIO */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg); - ret = axienet_mdio_wait_until_ready(lp); + ret = axienet_mdio_enable(lp); + mutex_unlock(&lp->mii_bus->mdio_lock); if (ret < 0) return ret; @@ -1316,28 +1312,24 @@ static void axienet_dma_err_handler(unsigned long data) { u32 axienet_status; u32 cr, i; - int mdio_mcreg; struct axienet_local *lp = (struct axienet_local *) data; struct net_device *ndev = lp->ndev; struct axidma_bd *cur_p; axienet_setoptions(ndev, lp->options & ~(XAE_OPTION_TXEN | XAE_OPTION_RXEN)); - mdio_mcreg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); - axienet_mdio_wait_until_ready(lp); /* Disable the MDIO interface till Axi Ethernet Reset is completed. * When we do an Axi Ethernet reset, it resets the complete core - * including the MDIO. So if MDIO is not disabled when the reset - * process is started, MDIO will be broken afterwards. + * including the MDIO. MDIO must be disabled before resetting + * and re-enabled afterwards. + * Hold MDIO bus lock to avoid MDIO accesses during the reset. */ - axienet_iow(lp, XAE_MDIO_MC_OFFSET, (mdio_mcreg & - ~XAE_MDIO_MC_MDIOEN_MASK)); - + mutex_lock(&lp->mii_bus->mdio_lock); + axienet_mdio_disable(lp); __axienet_device_reset(lp, XAXIDMA_TX_CR_OFFSET); __axienet_device_reset(lp, XAXIDMA_RX_CR_OFFSET); - - axienet_iow(lp, XAE_MDIO_MC_OFFSET, mdio_mcreg); - axienet_mdio_wait_until_ready(lp); + axienet_mdio_enable(lp); + mutex_unlock(&lp->mii_bus->mdio_lock); for (i = 0; i < TX_BD_NUM; i++) { cur_p = &lp->tx_bd_v[i]; |