summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath10k/htt_tx.c
diff options
context:
space:
mode:
authorMohammed Shafi Shajakhan <mohammed@qti.qualcomm.com>2016-11-30 12:50:14 +0300
committerKalle Valo <kvalo@qca.qualcomm.com>2016-12-01 14:13:55 +0300
commit9ec34a86195a65953269d3ee97b90308f469e14c (patch)
tree0f5674c28ee889671f4c07b1a5e9f89f67a211d5 /drivers/net/wireless/ath/ath10k/htt_tx.c
parentc2cac2f74ab4bcf0db0dcf3a612f1e5b52d145c8 (diff)
downloadlinux-9ec34a86195a65953269d3ee97b90308f469e14c.tar.xz
ath10k: fix Tx DMA alloc failure during continuous wifi down/up
With maximum number of vap's configured in a two radio supported systems of ~256 Mb RAM, doing a continuous wifi down/up and intermittent traffic streaming from the connected stations results in failure to allocate contiguous memory for tx buffers. This results in the disappearance of all VAP's and a manual reboot is needed as this is not a crash (or) OOM(for OOM killer to be invoked). To address this allocate contiguous memory for tx buffers one time and re-use them until the modules are unloaded but this results in a slight increase in memory footprint of ath10k when the wifi is down, but the modules are still loaded. Also as of now we use a separate bool 'tx_mem_allocated' to keep track of the one time memory allocation, as we cannot come up with something like 'ath10k_tx_{register,unregister}' before 'ath10k_probe_fw' is called as 'ath10k_htt_tx_alloc_cont_frag_desc' memory allocation is dependent on the hw_param 'continuous_frag_desc' a) memory footprint of ath10k without the change lsmod | grep ath10k ath10k_core 414498 1 ath10k_pci ath10k_pci 38236 0 b) memory footprint of ath10k with the change ath10k_core 414980 1 ath10k_pci ath10k_pci 38236 0 Memory Failure Call trace: hostapd: page allocation failure: order:6, mode:0xd0 [<c021f150>] (__dma_alloc_buffer.isra.23) from [<c021f23c>] (__alloc_remap_buffer.isra.26+0x14/0xb8) [<c021f23c>] (__alloc_remap_buffer.isra.26) from [<c021f664>] (__dma_alloc+0x224/0x2b8) [<c021f664>] (__dma_alloc) from [<c021f810>] (arm_dma_alloc+0x84/0x90) [<c021f810>] (arm_dma_alloc) from [<bf954764>] (ath10k_htt_tx_alloc+0xe0/0x2e4 [ath10k_core]) [<bf954764>] (ath10k_htt_tx_alloc [ath10k_core]) from [<bf94e6ac>] (ath10k_core_start+0x538/0xcf8 [ath10k_core]) [<bf94e6ac>] (ath10k_core_start [ath10k_core]) from [<bf947eec>] (ath10k_start+0xbc/0x56c [ath10k_core]) [<bf947eec>] (ath10k_start [ath10k_core]) from [<bf8a7a04>] (drv_start+0x40/0x5c [mac80211]) [<bf8a7a04>] (drv_start [mac80211]) from [<bf8b7cf8>] (ieee80211_do_open+0x170/0x82c [mac80211]) [<bf8b7cf8>] (ieee80211_do_open [mac80211]) from [<c056afc8>] (__dev_open+0xa0/0xf4) [21053.491752] Normal: 641*4kB (UEMR) 505*8kB (UEMR) 330*16kB (UEMR) 126*32kB (UEMR) 762*64kB (UEMR) 237*128kB (UEMR) 1*256kB (M) 0*512kB 0*1024kB 0*2048kB 0*4096kB = 95276kB Signed-off-by: Mohammed Shafi Shajakhan <mohammed@qti.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/htt_tx.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index ccbc8c03abc1..27e49db4287a 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -350,21 +350,15 @@ static int ath10k_htt_tx_alloc_txdone_fifo(struct ath10k_htt *htt)
return ret;
}
-int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
+static int ath10k_htt_tx_alloc_buf(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
int ret;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
- htt->max_num_pending_tx);
-
- spin_lock_init(&htt->tx_lock);
- idr_init(&htt->pending_tx);
-
ret = ath10k_htt_tx_alloc_cont_txbuf(htt);
if (ret) {
ath10k_err(ar, "failed to alloc cont tx buffer: %d\n", ret);
- goto free_idr_pending_tx;
+ return ret;
}
ret = ath10k_htt_tx_alloc_cont_frag_desc(htt);
@@ -396,6 +390,31 @@ free_frag_desc:
free_txbuf:
ath10k_htt_tx_free_cont_txbuf(htt);
+ return ret;
+}
+
+int ath10k_htt_tx_start(struct ath10k_htt *htt)
+{
+ struct ath10k *ar = htt->ar;
+ int ret;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
+ htt->max_num_pending_tx);
+
+ spin_lock_init(&htt->tx_lock);
+ idr_init(&htt->pending_tx);
+
+ if (htt->tx_mem_allocated)
+ return 0;
+
+ ret = ath10k_htt_tx_alloc_buf(htt);
+ if (ret)
+ goto free_idr_pending_tx;
+
+ htt->tx_mem_allocated = true;
+
+ return 0;
+
free_idr_pending_tx:
idr_destroy(&htt->pending_tx);
@@ -418,15 +437,28 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
return 0;
}
-void ath10k_htt_tx_free(struct ath10k_htt *htt)
+void ath10k_htt_tx_destroy(struct ath10k_htt *htt)
{
- idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
- idr_destroy(&htt->pending_tx);
+ if (!htt->tx_mem_allocated)
+ return;
ath10k_htt_tx_free_cont_txbuf(htt);
ath10k_htt_tx_free_txq(htt);
ath10k_htt_tx_free_cont_frag_desc(htt);
ath10k_htt_tx_free_txdone_fifo(htt);
+ htt->tx_mem_allocated = false;
+}
+
+void ath10k_htt_tx_stop(struct ath10k_htt *htt)
+{
+ idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
+ idr_destroy(&htt->pending_tx);
+}
+
+void ath10k_htt_tx_free(struct ath10k_htt *htt)
+{
+ ath10k_htt_tx_stop(htt);
+ ath10k_htt_tx_destroy(htt);
}
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)