From 6a4f6e1d295f4aa2e26056a859b76ccc769e75a5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:03 +0300 Subject: [PATCH 1/7] ath10k: differentiate between target init failures This just makes it easier to tell apart different kinds of bringup failure. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bf1083d52e61..cd3b00cbc920 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2464,7 +2464,13 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) mdelay(10); } while (time_before(jiffies, timeout)); - if (val == 0xffffffff || !(val & FW_IND_INITIALIZED)) { + if (val == 0xffffffff) { + ath10k_err("failed to read device register, device is gone\n"); + ret = -EIO; + goto out; + } + + if (!(val & FW_IND_INITIALIZED)) { ath10k_err("failed to receive initialized event from target: %08x\n", val); ret = -ETIMEDOUT; From 7710cd2e240f507ec70897258b945c30e2ccb83a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:04 +0300 Subject: [PATCH 2/7] ath10k: don't wait for device init if it crashed When warm resetting it's possible for device to crash during initialization. Instead of waiting 3 seconds just return failure as soon as FW_IND_EVENT_PENDING is set. This speeds up device bootup and recovery in some cases. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index cd3b00cbc920..66b1f3017f2b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2452,6 +2452,10 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val == 0xffffffff) continue; + /* the device has crashed so don't bother trying anymore */ + if (val & FW_IND_EVENT_PENDING) + break; + if (val & FW_IND_INITIALIZED) break; @@ -2470,6 +2474,12 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) goto out; } + if (val & FW_IND_EVENT_PENDING) { + ath10k_warn("device has crashed during init\n"); + ret = -ECOMM; + goto out; + } + if (!(val & FW_IND_INITIALIZED)) { ath10k_err("failed to receive initialized event from target: %08x\n", val); From 216a18367a4b287a9fa2bfeae9f22cbc344772b8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:04 +0300 Subject: [PATCH 3/7] ath10k: skip suspending when recovering It doesn't make much sense to even try suspending the device when recovering. Recovering means the device is unresponsive and waiting for suspend procedure means taking a 3 second timeout waiting for tx credits. This speeds up firmware recovery significantly. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 6abde37fb339..75b3dfbd6509 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -680,8 +680,8 @@ static void ath10k_core_restart(struct work_struct *work) switch (ar->state) { case ATH10K_STATE_ON: - ath10k_halt(ar); ar->state = ATH10K_STATE_RESTARTING; + ath10k_halt(ar); ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: @@ -908,7 +908,9 @@ void ath10k_core_stop(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); /* try to suspend target */ - ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); + if (ar->state != ATH10K_STATE_RESTARTING) + ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR); + ath10k_debug_stop(ar); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); From ec6bc5523b40008448bad5eadcdcf4cdbf9c7054 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:05 +0300 Subject: [PATCH 4/7] ath10k: make sure to not leak beacon dma mapping If for some reason mac80211 wouldn't stop beaconing gracefully and just removed interface of a running AP/IBSS interface it was possible to leak pending beacon DMA mapping. It's very unlikely but better safe than sorry. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8385a7ad02ac..22e82398c45b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2771,6 +2771,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, spin_lock_bh(&ar->data_lock); if (arvif->beacon) { + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); dev_kfree_skb_any(arvif->beacon); arvif->beacon = NULL; } From 2ab03a6b962eb9ff34846156b324eb411837b331 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:05 +0300 Subject: [PATCH 5/7] ath10k: make sure to not use invalid beacon pointer If DMA mapping of next beacon failed it was possible for next SWBA to access a pointer that was already unmapped and freed. This could cause memory corruption. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index fe4d5f1c672f..11176cc6a2ad 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1431,6 +1431,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ATH10K_SKB_CB(arvif->beacon)->paddr, arvif->beacon->len, DMA_TO_DEVICE); dev_kfree_skb_any(arvif->beacon); + arvif->beacon = NULL; } ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev, From ad3d2153bd5e2f616108d087ca2eb43dcb6b0741 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:06 +0300 Subject: [PATCH 6/7] ath10k: prevent beacon memory leak If DMA mapping of next beacon failed ath10k leaked the beacon. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 11176cc6a2ad..72cc4f20d102 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1441,6 +1441,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ATH10K_SKB_CB(bcn)->paddr); if (ret) { ath10k_warn("failed to map beacon: %d\n", ret); + dev_kfree_skb_any(bcn); goto skip; } From d9bc4b9b693d52dc14dc1de5dfec760634067d8c Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 23 Apr 2014 19:30:06 +0300 Subject: [PATCH 7/7] ath10k: fix firmware recovery with ap interface Beacon data wasn't properly cleared during early phase of recovery. This in turn caused firmware to crash because the beacon data was submitted before vdevs were fully re-configured. Ultimately the device was considered wedged and nothing worked until driver was reloaded. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 22e82398c45b..e2c01dc5900c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2291,6 +2291,8 @@ static void ath10k_tx(struct ieee80211_hw *hw, */ void ath10k_halt(struct ath10k *ar) { + struct ath10k_vif *arvif; + lockdep_assert_held(&ar->conf_mutex); if (ath10k_monitor_is_enabled(ar)) { @@ -2313,6 +2315,17 @@ void ath10k_halt(struct ath10k *ar) ar->scan.in_progress = false; ieee80211_scan_completed(ar->hw, true); } + + list_for_each_entry(arvif, &ar->arvifs, list) { + if (!arvif->beacon) + continue; + + dma_unmap_single(arvif->ar->dev, + ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); + dev_kfree_skb_any(arvif->beacon); + arvif->beacon = NULL; + } spin_unlock_bh(&ar->data_lock); }