From patchwork Thu Nov 17 08:36:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sven Eckelmann X-Patchwork-Id: 9433619 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 820CE6047D for ; Thu, 17 Nov 2016 08:36:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7207029309 for ; Thu, 17 Nov 2016 08:36:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6518F2933D; Thu, 17 Nov 2016 08:36:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.4 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5C42129309 for ; Thu, 17 Nov 2016 08:36:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753223AbcKQIgZ (ORCPT ); Thu, 17 Nov 2016 03:36:25 -0500 Received: from mail-wm0-f48.google.com ([74.125.82.48]:35825 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752376AbcKQIgY (ORCPT ); Thu, 17 Nov 2016 03:36:24 -0500 Received: by mail-wm0-f48.google.com with SMTP id a197so294786938wmd.0 for ; Thu, 17 Nov 2016 00:36:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=open-mesh-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=tksI8cCTn6TcE1F2Ht08T2vgQChmvW17EPobuB7slGg=; b=XYs34r3t8KQ6MVxC9k/miLwzVMHH3iDTtA1fr1UjYuwqhVhPcbG7Uo9aNZLf2/Q5ga RAh2JfR/pvyyJJ01plOoPwuI/79vUaAHo3viUELte5GwveDO6GFcSZTE0bfY+fig/YJ2 07sandCjUyXpSzAjkRcPnPqN0Nko5bLT0zD3a3a/za/DKTL2VtBYQait8mC+T5ULPalC f087Yu44c73TX6iy2V1MaZCTVVQ0dPlyB5TrUS6dHOtoiCsEDXn5QB6qFcXxpbRKQei9 vMGPQhBnqYQ6QBldtX5Kk5kjSBRnaLu5EdsMXXg6kejsG8Iu4pEvl31d+sBXNq+kjLRZ E4fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=tksI8cCTn6TcE1F2Ht08T2vgQChmvW17EPobuB7slGg=; b=SrcZatUyO22N82Z6JEZGUuvudxs5qZb7cU6H7XUmeGN0lrT1Kul77f6+7PVFgYD7qg kobkBpwuVx0qXzYPS2U6r4pRI/MsK35seOkmPW6uqgpV9mINK+bj+bTRyD9xtBnxJAkp SGGnVqNIvSPGEwMQUQJYGet3cLbOc/hCTDGkSvNCFB9loC1Uznm/vM4trzVKbUphKicE DZJBAaYOsZdBcxjRH9aStygPahdrnqJjRNCg6mnW3kPsMMfJLv3mrkTc1U21H40GwMBh /xnz1rEngTOEZ7Ny/m6HViDfPJ7vw/dCOEFTB6FfXu0X9k+UrGb5vlmlOpx2/AIG3HCU Nn2A== X-Gm-Message-State: ABUngvfHnGY2Tt+PgWXka7u6hcrBaN9Nif0Nraa8Q+Pvs0yMirzbIIQO8I4XdqB5vHWHP6ZB X-Received: by 10.28.40.67 with SMTP id o64mr14140427wmo.40.1479371782799; Thu, 17 Nov 2016 00:36:22 -0800 (PST) Received: from sven-desktop.home.narfation.org (p2003007C6F610DFE714A10EABC54387E.dip0.t-ipconnect.de. [2003:7c:6f61:dfe:714a:10ea:bc54:387e]) by smtp.gmail.com with ESMTPSA id l187sm2487629wml.6.2016.11.17.00.36.21 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 17 Nov 2016 00:36:22 -0800 (PST) From: Sven Eckelmann To: ath9k-devel@lists.ath9k.org Cc: linux-wireless@vger.kernel.org, ath9k-devel@qca.qualcomm.com, Simon Wunderlich , Sven Eckelmann Subject: [RFC v2 1/2] ath9k: work around AR_CFG 0xdeadbeef chip hang Date: Thu, 17 Nov 2016 09:36:13 +0100 Message-Id: <20161117083614.19188-1-sven.eckelmann@open-mesh.com> X-Mailer: git-send-email 2.10.2 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Simon Wunderlich QCA 802.11n chips (especially AR9330/AR9340) sometimes end up in a state in which a read of AR_CFG always returns 0xdeadbeef. This should not happen when when the power_mode of the device is ATH9K_PM_AWAKE. This problem is not yet detected by any other workaround in ath9k. No way is known to reproduce the problem easily. Signed-off-by: Simon Wunderlich [sven.eckelmann@open-mesh.com: port to recent ath9k, add commit message] Signed-off-by: Sven Eckelmann --- v2: - reduce amount of possible goto-raptor attacks by one (thanks Kalle Valo) This was discussed 4 years ago on the OpenWrt mailing list. The most relevant post is https://lists.openwrt.org/pipermail/openwrt-devel/2012-September/016708.html --- drivers/net/wireless/ath/ath9k/ath9k.h | 3 +++ drivers/net/wireless/ath/ath9k/debug.c | 1 + drivers/net/wireless/ath/ath9k/debug.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 1 + drivers/net/wireless/ath/ath9k/link.c | 31 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 6 files changed, 41 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 26fc8ec..9c6fee7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -710,11 +710,13 @@ void ath9k_csa_update(struct ath_softc *sc); #define ATH_ANI_MAX_SKIP_COUNT 10 #define ATH_PAPRD_TIMEOUT 100 /* msecs */ #define ATH_PLL_WORK_INTERVAL 100 +#define ATH_HANG_WORK_INTERVAL 30000 void ath_tx_complete_poll_work(struct work_struct *work); void ath_reset_work(struct work_struct *work); bool ath_hw_check(struct ath_softc *sc); void ath_hw_pll_work(struct work_struct *work); +void ath_hw_hang_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); void ath_start_ani(struct ath_softc *sc); @@ -1014,6 +1016,7 @@ struct ath_softc { #endif struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; + struct delayed_work hw_hang_work; struct timer_list sleep_timer; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index c56e40f..608b370 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -767,6 +767,7 @@ static int read_file_reset(struct seq_file *file, void *data) [RESET_TYPE_CALIBRATION] = "Calibration error", [RESET_TX_DMA_ERROR] = "Tx DMA stop error", [RESET_RX_DMA_ERROR] = "Rx DMA stop error", + [RESET_TYPE_DEADBEEF] = "deadbeef hang", }; int i; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index cd68c5f..0d77abbf6 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -52,6 +52,7 @@ enum ath_reset_type { RESET_TYPE_CALIBRATION, RESET_TX_DMA_ERROR, RESET_RX_DMA_ERROR, + RESET_TYPE_DEADBEEF, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 368d9b3..9bc7d1c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -638,6 +638,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); + INIT_DELAYED_WORK(&sc->hw_hang_work, ath_hw_hang_work); ath9k_init_channel_context(sc); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 5ad0fee..04195d5 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -138,6 +138,37 @@ void ath_hw_pll_work(struct work_struct *work) msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); } +static bool ath_hw_hang_deadbeef(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + u32 reg; + + /* check for stucked MAC */ + ath9k_ps_wakeup(sc); + reg = REG_READ(sc->sc_ah, AR_CFG); + ath9k_ps_restore(sc); + + if (reg != 0xdeadbeef) + return false; + + ath_dbg(common, RESET, + "0xdeadbeef hang is detected. Schedule chip reset\n"); + ath9k_queue_reset(sc, RESET_TYPE_DEADBEEF); + + return true; +} + +void ath_hw_hang_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_hang_work.work); + + ath_hw_hang_deadbeef(sc); + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work, + msecs_to_jiffies(ATH_HANG_WORK_INTERVAL)); +} + /* * PA Pre-distortion. */ diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e9f32b5..4d3e216 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -183,6 +183,7 @@ static void __ath_cancel_work(struct ath_softc *sc) cancel_work_sync(&sc->paprd_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); + cancel_delayed_work_sync(&sc->hw_hang_work); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT if (ath9k_hw_mci_is_enabled(sc->sc_ah)) @@ -204,6 +205,9 @@ void ath_restart_work(struct ath_softc *sc) ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); + ieee80211_queue_delayed_work(sc->hw, &sc->hw_hang_work, + msecs_to_jiffies(ATH_HANG_WORK_INTERVAL)); + ath_start_ani(sc); }