Factor out airoha_qdma_start() and airoha_qdma_stop() from airoha_dev_open() and airoha_dev_stop(). These helpers will be reused by the QDMA hot-migration logic introduced in the next patch to dynamically switch GDM3/GDM4 ports between LAN and WAN QDMA blocks. Add a DMA engine busy poll in airoha_qdma_stop() to wait for in-flight DMA transfers to complete before cleaning up TX queues. Tested-by: Madhur Agrawal Reviewed-by: Alexander Lobakin Signed-off-by: Lorenzo Bianconi --- drivers/net/ethernet/airoha/airoha_eth.c | 53 ++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 9eb9b6a139b3..72ec6c888948 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -1774,6 +1774,40 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev) spin_unlock(&port->stats.lock); } +static void airoha_qdma_start(struct airoha_qdma *qdma) +{ + airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); + qdma->users++; +} + +static void airoha_qdma_stop(struct airoha_qdma *qdma) +{ + u32 status; + + if (--qdma->users) + return; + + airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, + GLOBAL_CFG_TX_DMA_EN_MASK | + GLOBAL_CFG_RX_DMA_EN_MASK); + + if (read_poll_timeout(airoha_qdma_rr, status, + !(status & (GLOBAL_CFG_TX_DMA_BUSY_MASK | + GLOBAL_CFG_RX_DMA_BUSY_MASK)), + USEC_PER_MSEC, 50 * USEC_PER_MSEC, true, + qdma, REG_QDMA_GLOBAL_CFG)) + dev_warn(qdma->eth->dev, "QDMA DMA engine busy timeout\n"); + + for (int i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) + continue; + + airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); + } +} + static int airoha_dev_open(struct net_device *netdev) { int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN; @@ -1809,10 +1843,7 @@ static int airoha_dev_open(struct net_device *netdev) } port->users++; - airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, - GLOBAL_CFG_TX_DMA_EN_MASK | - GLOBAL_CFG_RX_DMA_EN_MASK); - qdma->users++; + airoha_qdma_start(qdma); if (!airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(qdma->eth, 1)) @@ -1865,19 +1896,7 @@ static int airoha_dev_stop(struct net_device *netdev) airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), FE_PSE_PORT_DROP); - - if (!--qdma->users) { - airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, - GLOBAL_CFG_TX_DMA_EN_MASK | - GLOBAL_CFG_RX_DMA_EN_MASK); - - for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { - if (!qdma->q_tx[i].ndesc) - continue; - - airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); - } - } + airoha_qdma_stop(qdma); return 0; } -- 2.54.0