diff options
| author | Yun Park <yunp@codeaurora.org> | 2017-03-30 15:38:33 -0700 |
|---|---|---|
| committer | Yun Park <yunp@codeaurora.org> | 2017-04-01 10:30:53 -0700 |
| commit | 90590ec040baff960c7b90758e1c92bd73217676 (patch) | |
| tree | 50ccfd49444b68c6fa4ae0239420aa0441e4be48 | |
| parent | 09371808dbe505b096948453fc0730d2ed820c75 (diff) | |
qcacld-3.0: HDD IPA event handler waits resource load/unload complete
There is a race condition bewteen CLIENT_DISCONNECT and AP_DISCONNECT,
which causes short HDD IPA interfaces, so AP_CONNECT failed afterward.
HDD IPA event handler waits IPA resource load/unload complete.
Once timed out, add the event in a pending queue for loading icase or
ignore it for unloading case.
Remove redundant CLIENT_DISCONNECT event from del_sta.
Change-Id: I671ecec6f236d52a1b51cb78b9c7466f2cde82aa
CRs-Fixed: 2027714
| -rw-r--r-- | core/hdd/src/wlan_hdd_cfg80211.c | 13 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_ipa.c | 109 |
2 files changed, 70 insertions, 52 deletions
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index b0ff7de8adae..7e442feb62d2 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -15233,14 +15233,6 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, pAdapter->aStaInfo[i]. macAddrSTA.bytes, QDF_MAC_ADDR_SIZE); - if (hdd_ipa_uc_is_enabled(pHddCtx)) { - hdd_ipa_wlan_evt(pAdapter, - pAdapter-> - aStaInfo[i]. - ucSTAId, - HDD_IPA_CLIENT_DISCONNECT, - mac); - } hdd_debug("Delete STA with MAC::" MAC_ADDRESS_STR, MAC_ADDR_ARRAY(mac)); @@ -15281,11 +15273,6 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, return -ENOENT; } - if (hdd_ipa_uc_is_enabled(pHddCtx)) { - hdd_ipa_wlan_evt(pAdapter, staId, - HDD_IPA_CLIENT_DISCONNECT, mac); - } - if (pAdapter->aStaInfo[staId].isDeauthInProgress == true) { hdd_debug("Skip DEL STA as deauth is in progress::" diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c index 370def6c968b..aed8f2f86c6d 100644 --- a/core/hdd/src/wlan_hdd_ipa.c +++ b/core/hdd/src/wlan_hdd_ipa.c @@ -503,6 +503,7 @@ struct hdd_ipa_priv { struct completion ipa_uc_sharing_stats_comp; struct completion ipa_uc_set_quota_comp; #endif + struct completion ipa_resource_comp; }; #define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) @@ -634,6 +635,8 @@ static struct hdd_ipa_tx_hdr ipa_tx_hdr = { #define IPA_UC_SET_QUOTA_WAIT_TIME 500 #endif +#define IPA_RESOURCE_COMP_WAIT_TIME 100 + static struct hdd_ipa_priv *ghdd_ipa; /* Local Function Prototypes */ @@ -1685,6 +1688,7 @@ static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) __func__, result); return result; } + INIT_COMPLETION(hdd_ipa->ipa_resource_comp); ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, false); hdd_ipa->ipa_pipes_down = false; return 0; @@ -1801,6 +1805,7 @@ static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) } hdd_ipa->resource_unloading = true; + INIT_COMPLETION(hdd_ipa->ipa_resource_comp); HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__); ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, false); HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__); @@ -2073,6 +2078,7 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) hdd_ipa->activated_fw_pipe++; if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) { hdd_ipa->resource_loading = false; + complete(&hdd_ipa->ipa_resource_comp); if (hdd_ipa->wdi_enabled == false) { hdd_ipa->wdi_enabled = true; if (hdd_ipa_uc_send_wdi_control_msg(true) == 0) @@ -2092,14 +2098,16 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) qdf_mutex_acquire(&hdd_ipa->ipa_lock); hdd_ipa->activated_fw_pipe--; if (!hdd_ipa->activated_fw_pipe) { + /* + * Async return success from FW + * Disable/suspend all the PIPEs + */ hdd_ipa_uc_disable_pipes(hdd_ipa); if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) ipa_rm_release_resource( IPA_RM_RESOURCE_WLAN_PROD); - /* Sync return success from IPA - * Enable/resume all the PIPEs - */ hdd_ipa->resource_unloading = false; + complete(&hdd_ipa->ipa_resource_comp); hdd_ipa_uc_proc_pending_event(hdd_ipa); hdd_ipa->pending_cons_req = false; } @@ -2514,7 +2522,6 @@ static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, } INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp); - INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp); hdd_ipa_uc_sharing_stats_request(adapter, wdi_sap_stats->reset_stats); ret = wait_for_completion_timeout( @@ -2570,6 +2577,7 @@ static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, return; } + INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp); hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota, ipa_set_quota->quota_bytes); @@ -5290,51 +5298,72 @@ static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, /* * During IPA UC resource loading/unloading new events can be issued. - * Store the events separately and handle them later. */ - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - if (hdd_ipa->resource_loading) { - unsigned int pending_event_count; - struct ipa_uc_pending_event *pending_event = NULL; + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) && + (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) { + unsigned int pending_event_count; + struct ipa_uc_pending_event *pending_event = NULL; + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s:IPA resource %s inprogress", + hdd_ipa_wlan_event_to_str(type), + hdd_ipa->resource_loading ? + "load" : "unload"); + + /* Wait until completion of the long/unloading */ + ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp, + msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME)); + if (!ret) { + /* + * If timed out, store the events separately and + * handle them later. + */ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA resource load inprogress"); + "IPA resource %s timed out", + hdd_ipa->resource_loading ? + "load" : "unload"); - qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if (hdd_ipa->resource_loading) { + qdf_mutex_acquire(&hdd_ipa->ipa_lock); - pending_event_count = + pending_event_count = qdf_list_size(&hdd_ipa->pending_event); - if (pending_event_count >= - HDD_IPA_MAX_PENDING_EVENT_COUNT) { - hdd_debug("Reached max pending event count"); - qdf_list_remove_front(&hdd_ipa->pending_event, - (qdf_list_node_t **)&pending_event); - } else { - pending_event = - qdf_mem_malloc(sizeof(*pending_event)); - } + if (pending_event_count >= + HDD_IPA_MAX_PENDING_EVENT_COUNT) { + hdd_debug( + "Reached max pending event count"); + qdf_list_remove_front( + &hdd_ipa->pending_event, + (qdf_list_node_t **)&pending_event); + } else { + pending_event = + qdf_mem_malloc( + sizeof(*pending_event)); + } - if (!pending_event) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "Pending event memory alloc fail"); - qdf_mutex_release(&hdd_ipa->ipa_lock); - return -ENOMEM; - } + if (!pending_event) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Pending event memory alloc fail"); + qdf_mutex_release(&hdd_ipa->ipa_lock); + return -ENOMEM; + } - pending_event->adapter = adapter; - pending_event->sta_id = sta_id; - pending_event->type = type; - qdf_mem_copy(pending_event->mac_addr, - mac_addr, - QDF_MAC_ADDR_SIZE); - qdf_list_insert_back(&hdd_ipa->pending_event, - &pending_event->node); + pending_event->adapter = adapter; + pending_event->sta_id = sta_id; + pending_event->type = type; + qdf_mem_copy(pending_event->mac_addr, + mac_addr, QDF_MAC_ADDR_SIZE); + qdf_list_insert_back(&hdd_ipa->pending_event, + &pending_event->node); - qdf_mutex_release(&hdd_ipa->ipa_lock); - return 0; - } else if (hdd_ipa->resource_unloading) { - hdd_err("IPA resource unload inprogress"); + qdf_mutex_release(&hdd_ipa->ipa_lock); + } return 0; + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA resource %s completed", + hdd_ipa->resource_loading ? + "load" : "unload"); } } @@ -5866,6 +5895,8 @@ static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) } } + init_completion(&hdd_ipa->ipa_resource_comp); + EXIT(); return QDF_STATUS_SUCCESS; |
