From 76533a62824bddfc829ec6ec7cc2a26e9db3d3a2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 9 Dec 2016 11:29:53 -0800 Subject: [PATCH] ath10k: Work around hang on FW crash, tid config, etc. This updates to latest 4.7 CT kernel ath10k-ct driver. Signed-off-by: Ben Greear --- ath10k/core.c | 4 ++++ ath10k/hw.h | 4 ++-- ath10k/mac.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ ath10k/wmi.c | 20 ++++++++++++++++---- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/ath10k/core.c b/ath10k/core.c index 1da3a9a..cf7c4f4 100644 --- a/ath10k/core.c +++ b/ath10k/core.c @@ -2006,10 +2006,12 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; + ar->num_tids = TARGET_NUM_TIDS; break; case ATH10K_FW_WMI_OP_VERSION_10_1: ar->bmiss_offload_max_vdev = TARGET_10X_BMISS_OFFLOAD_MAX_VDEV; ar->skid_limit = TARGET_10X_AST_SKID_LIMIT; + ar->num_tids = TARGET_10X_NUM_TIDS; if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, fw_file->fw_features)) { ar->skid_limit = TARGET_10X_AST_SKID_LIMIT_CT; @@ -2031,9 +2033,11 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) if (ath10k_peer_stats_enabled(ar)) { ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS; + ar->num_tids = TARGET_10X_TX_STATS_NUM_TIDS; } else { ar->max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; + ar->num_tids = TARGET_10X_NUM_TIDS; } ar->bmiss_offload_max_vdev = TARGET_10X_BMISS_OFFLOAD_MAX_VDEV; ar->skid_limit = TARGET_10X_AST_SKID_LIMIT; diff --git a/ath10k/hw.h b/ath10k/hw.h index 16c3e16..bc7f186 100644 --- a/ath10k/hw.h +++ b/ath10k/hw.h @@ -407,9 +407,9 @@ enum ath10k_hw_4addr_pad { #define DEF_TARGET_10X_NUM_VDEVS_CT 16 /* Can support up to 64 with proper config of other settings. * override w/module parm or fwcfg file */ /* NOTE: AST can really hold 4 keys, and there can be some temporarily in use as well. So this - * needs to be pretty large. 256 works in my testing with 64 station vdevs. --Ben + * needs to be pretty large. 256 works in my testing with 64 station vdevs (360 works better). --Ben */ -#define TARGET_10X_AST_SKID_LIMIT_CT (ath10k_modparam_target_num_peers_ct * TARGET_10X_NUM_PEER_AST) +#define TARGET_10X_AST_SKID_LIMIT_CT 360 /*((ath10k_modparam_target_num_peers_ct * TARGET_10X_NUM_PEER_AST)*/ #define TARGET_10X_NUM_PEER_KEYS_CT (WMI_MAX_KEY_INDEX + 1) /* 4 */ /* Related to HTC buffers */ diff --git a/ath10k/mac.c b/ath10k/mac.c index 784cf2b..2f50915 100644 --- a/ath10k/mac.c +++ b/ath10k/mac.c @@ -4190,13 +4190,37 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) } } -static void ath10k_mac_txq_init(struct ieee80211_txq *txq) +static void ath10k_mac_txq_init(struct ath10k *ar, struct ieee80211_txq *txq) { struct ath10k_txq *artxq = (void *)txq->drv_priv; + struct ath10k_txq *tmp, *walker; + struct ieee80211_txq *txq_tmp; + int i = 0; if (!txq) return; + spin_lock_bh(&ar->txqs_lock); + + /* Remove from ar->txqs in case it still exists there. */ + list_for_each_entry_safe(walker, tmp, &ar->txqs, list) { + txq_tmp = container_of((void *)walker, struct ieee80211_txq, + drv_priv); + if ((++i % 10000) == 0) { + ath10k_err(ar, "txq-init: Checking txq_tmp: %p i: %d\n", txq_tmp, i); + ath10k_err(ar, "txq-init: txqs: %p walker->list: %p w->next: %p w->prev: %p ar->txqs: %p\n", + &ar->txqs, &(walker->list), walker->list.next, walker->list.prev, &ar->txqs); + } + + if (txq_tmp == txq) { + WARN_ON_ONCE(1); + ath10k_err(ar, "txq-init: Found txq when it should be deleted, txq_tmp: %p txq: %p\n", + txq_tmp, txq); + list_del(&walker->list); + } + } + spin_unlock_bh(&ar->txqs_lock); + INIT_LIST_HEAD(&artxq->list); } @@ -4208,6 +4232,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) struct sk_buff *msdu; struct ieee80211_txq *txq_tmp; int msdu_id; + int i = 0; if (!txq) return; @@ -4220,8 +4245,18 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) list_for_each_entry_safe(walker, tmp, &ar->txqs, list) { txq_tmp = container_of((void *)walker, struct ieee80211_txq, drv_priv); - if (txq_tmp == txq) + if ((++i % 10000) == 0) { + ath10k_err(ar, "Checking txq_tmp: %p i: %d\n", txq_tmp, i); + ath10k_err(ar, "txqs: %p walker->list: %p w->next: %p w->prev: %p ar->txqs: %p\n", + &ar->txqs, &(walker->list), walker->list.next, walker->list.prev, &ar->txqs); + } + + if (txq_tmp == txq) { + WARN_ON_ONCE(1); + ath10k_err(ar, "Found txq when it should be deleted, txq_tmp: %p txq: %p\n", + txq_tmp, txq); list_del(&walker->list); + } } spin_unlock_bh(&ar->txqs_lock); @@ -5255,7 +5290,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); memset(arvif, 0, sizeof(*arvif)); - ath10k_mac_txq_init(vif->txq); + ath10k_mac_txq_init(ar, vif->txq); memset(&arvif->bcast_rate, WMI_FIXED_RATE_NONE, sizeof(arvif->bcast_rate)); memset(&arvif->mcast_rate, WMI_FIXED_RATE_NONE, sizeof(arvif->mcast_rate)); @@ -5620,8 +5655,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, kfree(arvif->u.ap.noa_data); } - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", - arvif->vdev_id); + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac vdev %i delete (remove interface), vif: %p arvif: %p\n", + arvif->vdev_id, vif, arvif); ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); if (ret) @@ -6437,7 +6473,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - ath10k_mac_txq_init(sta->txq[i]); + ath10k_mac_txq_init(ar, sta->txq[i]); } /* cancel must be done outside the mutex to avoid deadlock */ diff --git a/ath10k/wmi.c b/ath10k/wmi.c index fd685c4..107147a 100644 --- a/ath10k/wmi.c +++ b/ath10k/wmi.c @@ -1771,6 +1771,15 @@ static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif) bool deliver_cab; int ret; + /* I saw a kasan warning here, looks like arvif and/or ar might have been + * NULL, add something to catch this if it happens again. + */ + if ((((unsigned long)(arvif)) < 8000) || (((unsigned long)(ar)) < 8000)) { + pr_err("tx-beacon-nowait: arvif: %p ar: %p\n", arvif, ar); + BUG_ON(((unsigned long)(arvif)) < 8000); + BUG_ON(((unsigned long)(ar)) < 8000); + } + spin_lock_bh(&ar->data_lock); bcn = arvif->beacon; @@ -5686,6 +5695,10 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); config.num_peers = __cpu_to_le32(ar->max_num_peers); + + ath10k_warn(ar, "10.1 wmi init: vdevs: %d peers: %d tid: %d\n", + ar->max_num_vdevs, ar->max_num_peers, ar->num_tids); + config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); config.roam_offload_max_vdev = @@ -5736,7 +5749,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) ar->htt.max_num_pending_tx); } - config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); + config.num_tids = __cpu_to_le32(ar->num_tids); config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK); config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); @@ -5801,11 +5814,10 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) if (ath10k_peer_stats_enabled(ar)) { config.num_peers = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_PEERS); - config.num_tids = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_TIDS); } else { config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); - config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS); } + config.num_tids = __cpu_to_le32(ar->num_tids); config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK); @@ -8460,7 +8472,7 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar) dma_unmap_single(ar->dev, ar->wmi.mem_chunks[i].paddr, ar->wmi.mem_chunks[i].len, - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); kfree(ar->wmi.mem_chunks[i].vaddr); }