On Fri, Jul 26, 2019 at 02:10:56PM +0200, Stanislaw Gruszka wrote:
> Since 41634aa8d6db ("mt76: only schedule txqs from the tx tasklet")
> I can observe firmware hangs on MT7630E on station mode: tx stop
> functioning after minor activity (rx keep working) and on module
> unload device fail to stop with messages:
> 
> [ 5446.141413] mt76x0e 0000:06:00.0: TX DMA did not stop
> [ 5449.176764] mt76x0e 0000:06:00.0: TX DMA did not stop
> 
> Loading module again results in failure to associate with AP.
> Only machine power off / power on cycle can make device work again.
> 
> I have no idea why the commit caused F/W hangs. Most likely some proper
> fix is needed of changing registers programming (or assuring proper order
> of actions), but so far I can not came up with any better fix than
> a partial revert of 41634aa8d6db.

The difference is that with 41634aa8d6db we can run mt76x02_poll_tx()
and mt76x02_tx_tasklet() in parallel on 2 different CPUs. Without
the commit, since tasklet is not scheduled from mt76_wake_tx_queue(),
it does not happen.

I'm not quite sure why, but MT7630E does not like when we poll tx status
on 2 cpus at once. Change like below:

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c 
b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index 467b28379870..622251faa415 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -170,7 +170,7 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int 
budget)
                                               mt76.tx_napi);
        int i;
 
-       mt76x02_mac_poll_tx_status(dev, false);
+       mt76x02_mac_poll_tx_status(dev, true);
 
        for (i = MT_TXQ_MCU; i >= 0; i--)
                mt76_queue_tx_cleanup(dev, i, false);

is sufficient to avoid the hangs.

> diff --git a/drivers/net/wireless/mediatek/mt76/tx.c 
> b/drivers/net/wireless/mediatek/mt76/tx.c
> index 5397827668b9..fefe0ee52584 100644
> --- a/drivers/net/wireless/mediatek/mt76/tx.c
> +++ b/drivers/net/wireless/mediatek/mt76/tx.c
> @@ -598,7 +598,7 @@ void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct 
> ieee80211_txq *txq)
>       if (!test_bit(MT76_STATE_RUNNING, &dev->state))
>               return;
>  
> -     tasklet_schedule(&dev->tx_tasklet);
> +     mt76_txq_schedule(dev, txq->ac);

However I'm not sure if change to tasklet_schedule() is indeed correct,
since on tasklet we schedule all queues, hence queues that could
possibly be still blocked? And on mt76_wake_tx_queue() we schedule only
one queue.

Stanislaw

Reply via email to