From: Tamizh chelvam <tamizhr@xxxxxxxxxxxxxx> [ Upstream commit bd1d395070cca4f42a93e520b0597274789274a4 ] When continuously running wifi up/down sequence, the napi poll can be scheduled after the CE buffers being freed by ath10k_pci_flush Steps: In a certain condition, during wifi down below scenario might occur. ath10k_stop->ath10k_hif_stop->napi_schedule->ath10k_pci_flush->napi_poll(napi_synchronize). In the above scenario, CE buffer entries will be freed up and become NULL in ath10k_pci_flush. And the napi_poll has been invoked after the flush process and it will try to get the skb from the CE buffer entry and perform some action on that. Since the CE buffer already cleaned by pci flush this action will create NULL pointer dereference and trigger below kernel panic. Unable to handle kernel NULL pointer dereference at virtual address 0000005c PC is at ath10k_pci_htt_rx_cb+0x64/0x3ec [ath10k_pci] ath10k_pci_htt_rx_cb [ath10k_pci] ath10k_ce_per_engine_service+0x74/0xc4 [ath10k_pci] ath10k_ce_per_engine_service [ath10k_pci] ath10k_ce_per_engine_service_any+0x74/0x80 [ath10k_pci] ath10k_ce_per_engine_service_any [ath10k_pci] ath10k_pci_napi_poll+0x48/0xec [ath10k_pci] ath10k_pci_napi_poll [ath10k_pci] net_rx_action+0xac/0x160 net_rx_action __do_softirq+0xdc/0x208 __do_softirq irq_exit+0x84/0xe0 irq_exit __handle_domain_irq+0x80/0xa0 __handle_domain_irq gic_handle_irq+0x38/0x5c gic_handle_irq __irq_usr+0x44/0x60 Tested on QCA4019 and firmware version 10.4.3.2.1.1-00010 Signed-off-by: Tamizh chelvam <tamizhr@xxxxxxxxxxxxxx> Signed-off-by: Kalle Valo <kvalo@xxxxxxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- drivers/net/wireless/ath/ath10k/ahb.c | 4 ++-- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index da770af830369..125b5c31b2b0a 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -658,10 +658,10 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar) ath10k_ahb_irq_disable(ar); synchronize_irq(ar_ahb->irq); - ath10k_pci_flush(ar); - napi_synchronize(&ar->napi); napi_disable(&ar->napi); + + ath10k_pci_flush(ar); } static int ath10k_ahb_hif_power_up(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 25b8d501d437e..b7bac14d1487b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1781,9 +1781,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_irq_disable(ar); ath10k_pci_irq_sync(ar); - ath10k_pci_flush(ar); napi_synchronize(&ar->napi); napi_disable(&ar->napi); + ath10k_pci_flush(ar); spin_lock_irqsave(&ar_pci->ps_lock, flags); WARN_ON(ar_pci->ps_wake_refcount > 0); -- 2.20.1