Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E6A7C433F5 for ; Wed, 24 Nov 2021 12:37:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245632AbhKXMkU (ORCPT ); Wed, 24 Nov 2021 07:40:20 -0500 Received: from mail.kernel.org ([198.145.29.99]:38572 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242918AbhKXMgV (ORCPT ); Wed, 24 Nov 2021 07:36:21 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2225E611ED; Wed, 24 Nov 2021 12:21:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1637756509; bh=tvcChKVG1+IHaCtTMsRbTj1RlqUopMUzPg5TRZMYkrw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KlMyc5LLnp0x/B1MWlEpWWpsYy0nW8RxOHj9uVjftuCYA8sCOdGv2Qk/hkg1/QTEU hp01ffwmIwDPTjDV66LyhOPd9TdnpZVrjYmlCFJcM9e3Llr1DJbbMGStjz8x+G4GtO siMlq7tLci9/9YEe3EdYAttcURG37NE56y8LL3eA= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Sven Eckelmann , Simon Wunderlich , =?UTF-8?q?Linus=20L=C3=BCssing?= , =?UTF-8?q?Linus=20L=C3=BCssing?= , Kalle Valo , Sasha Levin Subject: [PATCH 4.14 112/251] ath9k: Fix potential interrupt storm on queue reset Date: Wed, 24 Nov 2021 12:55:54 +0100 Message-Id: <20211124115714.124887641@linuxfoundation.org> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211124115710.214900256@linuxfoundation.org> References: <20211124115710.214900256@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Linus Lüssing [ Upstream commit 4925642d541278575ad1948c5924d71ffd57ef14 ] In tests with two Lima boards from 8devices (QCA4531 based) on OpenWrt 19.07 we could force a silent restart of a device with no serial output when we were sending a high amount of UDP traffic (iperf3 at 80 MBit/s in both directions from external hosts, saturating the wifi and causing a load of about 4.5 to 6) and were then triggering an ath9k_queue_reset(). Further debugging showed that the restart was caused by the ath79 watchdog. With disabled watchdog we could observe that the device was constantly going into ath_isr() interrupt handler and was returning early after the ATH_OP_HW_RESET flag test, without clearing any interrupts. Even though ath9k_queue_reset() calls ath9k_hw_kill_interrupts(). With JTAG we could observe the following race condition: 1) ath9k_queue_reset() ... -> ath9k_hw_kill_interrupts() -> set_bit(ATH_OP_HW_RESET, &common->op_flags); ... <- returns 2) ath9k_tasklet() ... -> ath9k_hw_resume_interrupts() ... <- returns 3) loops around: ... handle_int() -> ath_isr() ... -> if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return IRQ_HANDLED; x) ath_reset_internal(): => never reached <= And in ath_isr() we would typically see the following interrupts / interrupt causes: * status: 0x00111030 or 0x00110030 * async_cause: 2 (AR_INTR_MAC_IPQ) * sync_cause: 0 So the ath9k_tasklet() reenables the ath9k interrupts through ath9k_hw_resume_interrupts() which ath9k_queue_reset() had just disabled. And ath_isr() then keeps firing because it returns IRQ_HANDLED without actually clearing the interrupt. To fix this IRQ storm also clear/disable the interrupts again when we are in reset state. Cc: Sven Eckelmann Cc: Simon Wunderlich Cc: Linus Lüssing Fixes: 872b5d814f99 ("ath9k: do not access hardware on IRQs during reset") Signed-off-by: Linus Lüssing Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20210914192515.9273-3-linus.luessing@c0d3.blue Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath9k/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 173960682ea06..507d8c5149686 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -529,8 +529,10 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_debug_sync_cause(sc, sync_cause); status &= ah->imask; /* discard unasked-for bits */ - if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) + if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) { + ath9k_hw_kill_interrupts(sc->sc_ah); return IRQ_HANDLED; + } /* * If there are no status bits set, then this interrupt was not -- 2.33.0