diff options
| author | Prashanth Bhatta <bhattap@qca.qualcomm.com> | 2014-09-03 22:54:52 -0700 |
|---|---|---|
| committer | Akash Patel <c_akashp@qca.qualcomm.com> | 2014-09-04 18:21:10 -0700 |
| commit | d8a66cae6ab82298eb069bbf27f9d64c8ca4a8c2 (patch) | |
| tree | 892c1b3edb022805b4946d2ad52d4389d2fe1411 | |
| parent | 5a105f04dc98e15129a502217be7b880e2d5eac8 (diff) | |
qcacld: ipa: Hold cleanup till all packets completed
If driver is unloaded while descriptors are pending in IPA
hardware then there is a chance that descriptors are completed
after driver is unloaded. Fix the issue by tearing down IPA pipe
before freeing the descriptors so that ipa_teardown_sys_pipe
takes care of completing the pending descriptors and unload is
handled gracefully.
Change-Id: Ic4d4ca681e649983c025593700b1ad5a4640efa2
CRs-fixed: 710380
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_ipa.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/CORE/HDD/src/wlan_hdd_ipa.c b/CORE/HDD/src/wlan_hdd_ipa.c index fdf904944ba5..fc53fbd23e27 100644 --- a/CORE/HDD/src/wlan_hdd_ipa.c +++ b/CORE/HDD/src/wlan_hdd_ipa.c @@ -1487,6 +1487,8 @@ static void hdd_ipa_destory_rm_resource(struct hdd_ipa_priv *hdd_ipa) static void hdd_ipa_send_skb_to_network(adf_nbuf_t skb, hdd_adapter_t *adapter) { + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, "Invalid adapter: 0x%p", adapter); @@ -1494,6 +1496,12 @@ static void hdd_ipa_send_skb_to_network(adf_nbuf_t skb, hdd_adapter_t *adapter) adf_nbuf_free(skb); return; } + + if (hdd_ipa->hdd_ctx->isUnloadInProgress) { + adf_nbuf_free(skb); + return; + } + skb->dev = adapter->dev; skb->protocol = eth_type_trans(skb, skb->dev); skb->ip_summed = CHECKSUM_NONE; @@ -1512,6 +1520,11 @@ static void hdd_ipa_send_pkt_to_ipa(struct hdd_ipa_priv *hdd_ipa) adf_nbuf_t buf; struct ipa_tx_data_desc *send_desc_head = NULL; + /* Unloading is in progress so do not proceed to send the packets to + * IPA + */ + if (hdd_ipa->hdd_ctx->isUnloadInProgress) + return; /* Make it priority queue request as send descriptor */ send_desc_head = hdd_ipa_alloc_data_desc(hdd_ipa, 1); @@ -1990,10 +2003,12 @@ static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, hdd_ipa = iface_context->hdd_ipa; /* - * When SSR is going on, just drop the packets. There is no use in - * queueing the packets as STA has to connect back any way + * When SSR is going on or driver is unloading, just drop the packets. + * During SSR, there is no use in queueing the packets as STA has to + * connect back any way */ - if (hdd_ipa->hdd_ctx->isLogpInProgress) { + if (hdd_ipa->hdd_ctx->isLogpInProgress || + hdd_ipa->hdd_ctx->isUnloadInProgress) { ipa_free_skb(ipa_tx_desc); iface_context->stats.num_tx_drop++; return; @@ -2750,7 +2765,8 @@ static void hdd_ipa_rx_pipe_desc_free(void) spin_unlock_bh(&hdd_ipa->q_lock); if (i != max_desc_cnt) - HDD_IPA_LOG(VOS_TRACE_LEVEL_FATAL, "free desc leak"); + HDD_IPA_LOG(VOS_TRACE_LEVEL_FATAL, "free desc leak: %u, %u", i, + max_desc_cnt); } @@ -3120,6 +3136,13 @@ VOS_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) if (!hdd_ipa_is_enabled(hdd_ctx)) return VOS_STATUS_SUCCESS; + if (!hdd_ipa_uc_is_enabled(hdd_ipa)) { + unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier); + hdd_ipa_teardown_sys_pipe(hdd_ipa); + } + + hdd_ipa_destory_rm_resource(hdd_ipa); + #ifdef WLAN_OPEN_SOURCE cancel_work_sync(&hdd_ipa->pm_work); #endif @@ -3147,10 +3170,23 @@ VOS_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) hdd_ipa_debugfs_remove(hdd_ipa); + /* This should never hit but still make sure that there are no pending + * descriptor in IPA hardware + */ if (hdd_ipa->pending_hw_desc_cnt != 0) { - HDD_IPA_LOG(VOS_TRACE_LEVEL_FATAL, "IPA Pending write done: %d", + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "IPA Pending write done: %d Waiting!", hdd_ipa->pending_hw_desc_cnt); - msleep(5); + + for (i = 0; hdd_ipa->pending_hw_desc_cnt != 0 && i < 10; i++) { + usleep(100); + } + + HDD_IPA_LOG(VOS_TRACE_LEVEL_ERROR, + "IPA Pending write done: desc: %d %s(%d)!", + hdd_ipa->pending_hw_desc_cnt, + hdd_ipa->pending_hw_desc_cnt == 0 ? "completed" + : "leak", i); } #ifdef IPA_UC_OFFLOAD @@ -3165,14 +3201,8 @@ VOS_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) #endif /* IPA_UC_OFFLOAD */ { hdd_ipa_rx_pipe_desc_free(); - hdd_ipa_teardown_sys_pipe(hdd_ipa); } - hdd_ipa_destory_rm_resource(hdd_ipa); - - if (!hdd_ipa_uc_is_enabled(hdd_ipa)) { - unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier); - } adf_os_mem_free(hdd_ipa); hdd_ctx->hdd_ipa = NULL; |
