summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrashanth Bhatta <bhattap@qca.qualcomm.com>2014-09-03 22:54:52 -0700
committerAkash Patel <c_akashp@qca.qualcomm.com>2014-09-04 18:21:10 -0700
commitd8a66cae6ab82298eb069bbf27f9d64c8ca4a8c2 (patch)
tree892c1b3edb022805b4946d2ad52d4389d2fe1411
parent5a105f04dc98e15129a502217be7b880e2d5eac8 (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.c54
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;