qcacld-3.0: Propagate error from the hdd to wma in case of failure

When the ready event is received from the firmware, hdd callback
is called to create the pdev and update the capabilties. If
there is any error the error is not propogated back to hdd
which can result in the accessing the invalid memory.

Propagate the status correctly from hdd to wma to resolve this issue.
This will result in the probe failure until the resources are available
or reference leaks are fixed.

Change-Id: I97ec062893216e25e285d95d6bfb5cf3e91a4005
CRs-Fixed: 2426612
diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c
index 6daf019..176ac48 100644
--- a/core/cds/src/cds_api.c
+++ b/core/cds/src/cds_api.c
@@ -827,7 +827,6 @@
 	status = wma_wait_for_ready_event(gp_cds_context->wma_context);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		cds_err("Failed to wait for ready event; status: %u", status);
-		cds_trigger_recovery(QDF_REASON_UNSPECIFIED);
 		goto stop_wmi;
 	}
 
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index 000e3c6..6166496 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -299,7 +299,7 @@
 void hdd_get_pmkid_modes(struct hdd_context *hdd_ctx,
 			 struct pmkid_mode_bits *pmkid_modes);
 
-void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg);
+int hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg);
 
 /**
  * hdd_string_to_u8_array() - used to convert decimal string into u8 array
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index c2a17b5..dba1f1c 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -1793,7 +1793,7 @@
 	}
 }
 
-void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
+int hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
 {
 	int ret;
 	struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle);
@@ -1810,12 +1810,12 @@
 
 	if (!hdd_ctx) {
 		hdd_err("HDD context is NULL");
-		return;
+		return -EINVAL;
 	}
 	ret = hdd_objmgr_create_and_store_pdev(hdd_ctx);
 	if (ret) {
 		QDF_DEBUG_PANIC("Failed to create pdev; errno:%d", ret);
-		return;
+		return -EINVAL;
 	}
 
 	hdd_debug("New pdev has been created with pdev_id = %u",
@@ -1825,15 +1825,18 @@
 	if (QDF_IS_STATUS_ERROR(status)) {
 		QDF_DEBUG_PANIC("dispatcher pdev open failed; status:%d",
 				status);
-		return;
+		ret = qdf_status_to_os_return(status);
+		goto exit;
 	}
 
 	status = hdd_component_pdev_open(hdd_ctx->pdev);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		QDF_DEBUG_PANIC("hdd component pdev open failed; status:%d",
 				status);
-		return;
+		ret = qdf_status_to_os_return(status);
+		goto dispatcher_close;
 	}
+
 	cdp_pdev_set_ctrl_pdev(cds_get_context(QDF_MODULE_ID_SOC),
 			cds_get_context(QDF_MODULE_ID_TXRX),
 			(struct cdp_ctrl_objmgr_pdev *)hdd_ctx->pdev);
@@ -1856,7 +1859,8 @@
 						 &sub_20_chan_width);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to get sub_20_chan_width config");
-		return;
+		ret = qdf_status_to_os_return(status);
+		goto pdev_close;
 	}
 
 	if (cds_cfg) {
@@ -1873,7 +1877,8 @@
 	status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to get MLME band capability");
-		return;
+		ret = qdf_status_to_os_return(status);
+		goto pdev_close;
 	}
 
 	/* first store the INI band capability */
@@ -1902,7 +1907,8 @@
 	status = ucfg_mlme_set_band_capability(hdd_ctx->psoc, band_capability);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to set MLME Band Capability");
-		return;
+		ret = qdf_status_to_os_return(status);
+		goto pdev_close;
 	}
 
 	hdd_ctx->curr_band = band_capability;
@@ -1910,7 +1916,7 @@
 	status = wlan_hdd_update_wiphy_supported_band(hdd_ctx);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to update wiphy band info");
-		return;
+		goto pdev_close;
 	}
 
 	if (!cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
@@ -2069,6 +2075,16 @@
 	else
 		hdd_debug("bcast twt is disable in ini, fw cap %d",
 			  cfg->bcast_twt_support);
+	return 0;
+
+dispatcher_close:
+	dispatcher_pdev_close(hdd_ctx->pdev);
+pdev_close:
+	hdd_component_pdev_close(hdd_ctx->pdev);
+exit:
+	hdd_objmgr_release_and_destroy_pdev(hdd_ctx);
+
+	return ret;
 }
 
 bool hdd_dfs_indicate_radar(struct hdd_context *hdd_ctx)
diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h
index 077a2d4..d02b5a3 100644
--- a/core/wma/inc/wma_types.h
+++ b/core/wma/inc/wma_types.h
@@ -599,7 +599,7 @@
 				      uint32_t status, void *params);
 
 /* generic callback for updating parameters from target to HDD */
-typedef void (*wma_tgt_cfg_cb)(hdd_handle_t handle, struct wma_tgt_cfg *cfg);
+typedef int (*wma_tgt_cfg_cb)(hdd_handle_t handle, struct wma_tgt_cfg *cfg);
 
 /**
  * struct wma_cli_set_cmd_t - set command parameters
diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c
index 458f84e..43503a2 100644
--- a/core/wma/src/wma_main.c
+++ b/core/wma/src/wma_main.c
@@ -5605,9 +5605,9 @@
  * wma_update_hdd_cfg() - update HDD config
  * @wma_handle: wma handle
  *
- * Return: none
+ * Return: Zero on success err number on failure
  */
-static void wma_update_hdd_cfg(tp_wma_handle wma_handle)
+static int wma_update_hdd_cfg(tp_wma_handle wma_handle)
 {
 	struct wma_tgt_cfg tgt_cfg;
 	void *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
@@ -5616,26 +5616,28 @@
 	struct target_psoc_info *tgt_hdl;
 	struct wmi_unified *wmi_handle;
 	uint8_t i;
+	int ret;
 
 	WMA_LOGD("%s: Enter", __func__);
 
 	tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc);
 	if (!tgt_hdl) {
 		WMA_LOGE("%s: target psoc info is NULL", __func__);
-		return;
+		return -EINVAL;
 	}
 
 	wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl);
 	if (!wlan_res_cfg) {
 		WMA_LOGE("%s: wlan_res_cfg is null", __func__);
-		return;
+		return -EINVAL;
 	}
+
 	service_ext_param =
 			target_psoc_get_service_ext_param(tgt_hdl);
 	wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc);
 	if (!wmi_handle) {
 		WMA_LOGE("%s: wmi handle is NULL", __func__);
-		return;
+		return -EINVAL;
 	}
 
 	qdf_mem_zero(&tgt_cfg, sizeof(struct wma_tgt_cfg));
@@ -5711,11 +5713,15 @@
 	for (i = 0; i < tgt_hdl->info.total_mac_phy_cnt; i++)
 		wma_fill_chain_cfg(tgt_hdl, i);
 
-	wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg);
+	ret = wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg);
+	if (ret)
+		return -EINVAL;
 	target_if_store_pdev_target_if_ctx(wma_get_pdev_from_scn_handle);
 	target_pdev_set_wmi_handle(wma_handle->pdev->tgt_if_handle,
 				   wma_handle->wmi_handle);
 	wma_green_ap_register_handlers(wma_handle);
+
+	return ret;
 }
 
 /**
@@ -6820,6 +6826,7 @@
 	tp_wma_handle wma_handle = (tp_wma_handle) handle;
 	WMI_READY_EVENTID_param_tlvs *param_buf = NULL;
 	wmi_ready_event_fixed_param *ev = NULL;
+	int ret;
 
 	WMA_LOGD("%s: Enter", __func__);
 
@@ -6848,7 +6855,10 @@
 	/* copy the mac addr */
 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->myaddr);
 	WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->hwaddr);
-	wma_update_hdd_cfg(wma_handle);
+	ret = wma_update_hdd_cfg(wma_handle);
+	if (ret)
+		return ret;
+
 	WMA_LOGD("Exit");
 
 	return 0;
@@ -6920,6 +6930,11 @@
 
 	status = qdf_wait_for_event_completion(&tgt_hdl->info.event,
 					       WMA_READY_EVENTID_TIMEOUT);
+	if (!tgt_hdl->info.wmi_ready) {
+		wma_err("Error in pdev creation");
+		return QDF_STATUS_E_INVAL;
+	}
+
 	if (status == QDF_STATUS_E_TIMEOUT)
 		wma_err("Timeout waiting for FW ready event");
 	else if (QDF_IS_STATUS_ERROR(status))