Changing ring sizes or channel counts calls the complete ndo_stop/open pair while the interface remains administratively up. If reopening fails, the PHY attachment and runtime-PM reference have already been dropped, but the next ordinary close drops them again. The device also remains present, allowing an MTU change to quiesce NAPI which is already disabled. Detach the device and release only the datapath during these live changes. Use a common reopen helper which retains the PHY attachment and runtime-PM reference and reattaches only on success. Restore the previous ring sizes or channel topology after failure so a subsequent down/up retries the old configuration. Leave the failed device detached and reject further live ethtool reconfiguration until administrative recovery. No additional outer-lifetime flag is needed: PHY and PM ownership continue to follow the successful ndo_open/ndo_stop pair instead of being changed by live datapath reconfiguration. Fixes: aa042f60e496 ("net: stmmac: Add support to Ethtool get/set ring parameters") Fixes: 0366f7e06a6b ("net: stmmac: add ethtool support for get/set channels") Signed-off-by: James Hilliard --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 76 ++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d56b7f911db0..d17c68f55caf 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4361,6 +4361,8 @@ static void __stmmac_release(struct net_device *dev) /* Stop TX/RX DMA after draining IRQ handlers which can restart it. */ stmmac_stop_all_dma(priv); + /* Link resolution need not have reached mac_link_up() yet. */ + stmmac_mac_set(priv, priv->ioaddr, false); /* Release and free the Rx/Tx resources */ free_dma_desc_resources(priv, priv->dma_conf); @@ -7658,13 +7660,37 @@ static void stmmac_napi_del(struct net_device *dev) } } -int stmmac_reinit_queues(struct net_device *dev, u8 rx_cnt, u8 tx_cnt) +/* Rebuild only the datapath. The administratively-up device still owns its + * PHY attachment and runtime-PM reference, even if this reopen fails. + */ +static int stmmac_reopen(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); - int ret = 0, i; + struct stmmac_dma_conf *old_conf = priv->dma_conf; + struct stmmac_dma_conf *dma_conf; + int ret; - if (netif_running(dev)) - stmmac_release(dev); + dma_conf = stmmac_setup_dma_desc(priv, dev->mtu); + if (IS_ERR(dma_conf)) + return PTR_ERR(dma_conf); + + ret = __stmmac_open(dev, dma_conf); + if (ret) { + priv->dma_conf = old_conf; + free_dma_desc_resources(priv, dma_conf); + kfree(dma_conf); + return ret; + } + + kfree(old_conf); + netif_device_attach(dev); + return 0; +} + +static void stmmac_set_queues(struct net_device *dev, u8 rx_cnt, u8 tx_cnt) +{ + struct stmmac_priv *priv = netdev_priv(dev); + int i; stmmac_napi_del(dev); @@ -7676,9 +7702,31 @@ int stmmac_reinit_queues(struct net_device *dev, u8 rx_cnt, u8 tx_cnt) rx_cnt); stmmac_napi_add(dev); +} + +int stmmac_reinit_queues(struct net_device *dev, u8 rx_cnt, u8 tx_cnt) +{ + struct stmmac_priv *priv = netdev_priv(dev); + u8 old_rx = priv->plat->rx_queues_to_use; + u8 old_tx = priv->plat->tx_queues_to_use; + int ret = 0; + + if (netif_running(dev)) { + if (!netif_device_present(dev)) + return -ENETDOWN; + netif_device_detach(dev); + __stmmac_release(dev); + } + + stmmac_set_queues(dev, rx_cnt, tx_cnt); if (netif_running(dev)) - ret = stmmac_open(dev); + ret = stmmac_reopen(dev); + if (ret) { + stmmac_set_queues(dev, old_rx, old_tx); + netdev_err(dev, "failed reopening after channel change: %pe; interface remains detached\n", + ERR_PTR(ret)); + } return ret; } @@ -7686,16 +7734,28 @@ int stmmac_reinit_queues(struct net_device *dev, u8 rx_cnt, u8 tx_cnt) int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size) { struct stmmac_priv *priv = netdev_priv(dev); + u32 old_rx = priv->dma_conf->dma_rx_size; + u32 old_tx = priv->dma_conf->dma_tx_size; int ret = 0; - if (netif_running(dev)) - stmmac_release(dev); + if (netif_running(dev)) { + if (!netif_device_present(dev)) + return -ENETDOWN; + netif_device_detach(dev); + __stmmac_release(dev); + } priv->dma_conf->dma_rx_size = rx_size; priv->dma_conf->dma_tx_size = tx_size; if (netif_running(dev)) - ret = stmmac_open(dev); + ret = stmmac_reopen(dev); + if (ret) { + priv->dma_conf->dma_rx_size = old_rx; + priv->dma_conf->dma_tx_size = old_tx; + netdev_err(dev, "failed reopening after ring change: %pe; interface remains detached\n", + ERR_PTR(ret)); + } return ret; } -- 2.53.0