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>
This commit is contained in:
parent
c2cac2f74a
commit
9ec34a8619
|
@ -1858,7 +1858,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
|
|||
goto err_wmi_detach;
|
||||
}
|
||||
|
||||
status = ath10k_htt_tx_alloc(&ar->htt);
|
||||
status = ath10k_htt_tx_start(&ar->htt);
|
||||
if (status) {
|
||||
ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
|
||||
goto err_wmi_detach;
|
||||
|
@ -2053,7 +2053,7 @@ void ath10k_core_stop(struct ath10k *ar)
|
|||
ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
|
||||
|
||||
ath10k_hif_stop(ar);
|
||||
ath10k_htt_tx_free(&ar->htt);
|
||||
ath10k_htt_tx_stop(&ar->htt);
|
||||
ath10k_htt_rx_free(&ar->htt);
|
||||
ath10k_wmi_detach(ar);
|
||||
}
|
||||
|
@ -2386,6 +2386,7 @@ void ath10k_core_destroy(struct ath10k *ar)
|
|||
destroy_workqueue(ar->workqueue_aux);
|
||||
|
||||
ath10k_debug_destroy(ar);
|
||||
ath10k_htt_tx_destroy(&ar->htt);
|
||||
ath10k_wmi_free_host_mem(ar);
|
||||
ath10k_mac_destroy(ar);
|
||||
}
|
||||
|
|
|
@ -1717,6 +1717,8 @@ struct ath10k_htt {
|
|||
enum htt_tx_mode_switch_mode mode;
|
||||
enum htt_q_depth_type type;
|
||||
} tx_q_state;
|
||||
|
||||
bool tx_mem_allocated;
|
||||
};
|
||||
|
||||
#define RX_HTT_HDR_STATUS_LEN 64
|
||||
|
@ -1779,7 +1781,9 @@ int ath10k_htt_connect(struct ath10k_htt *htt);
|
|||
int ath10k_htt_init(struct ath10k *ar);
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
|
||||
int ath10k_htt_tx_start(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_stop(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_destroy(struct ath10k_htt *htt);
|
||||
void ath10k_htt_tx_free(struct ath10k_htt *htt);
|
||||
|
||||
int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue