Browse Source

qcacmn: Implement 11d state machine

Regulatory component needs to listen to vdev messages in order to track
whether a master mode vdev is getting created or destroyed. It is also
used to kick-start the state machine. Also re-run the state machine when
user-space country code is set.

Change-Id: I5112396314a936f84dad2f0e07329f9cb237aa78
CRs-Fixed: 2048784
Amar Singhal 7 years ago
parent
commit
2e55c111a8

+ 67 - 10
target_if/regulatory/src/target_if_reg.c

@@ -35,11 +35,61 @@ static inline uint32_t get_chan_list_cc_event_id(void)
 {
 	return WMI_REG_CHAN_LIST_CC_EVENTID;
 }
+
+static bool tgt_if_regulatory_is_11d_offloaded(struct wlan_objmgr_psoc
+					       *psoc)
+{
+	return WMI_SERVICE_IS_ENABLED(psoc->service_param.service_bitmap,
+				      WMI_SERVICE_11D_OFFLOAD);
+}
+
+static bool tgt_if_regulatory_is_regdb_offloaded(struct wlan_objmgr_psoc
+						 *psoc)
+{
+	return WMI_SERVICE_IS_ENABLED(psoc->service_param.service_bitmap,
+				      WMI_SERVICE_REGULATORY_DB);
+}
+
+static bool tgt_if_regulatory_is_there_serv_ready_extn(struct wlan_objmgr_psoc
+						       *psoc)
+{
+	return WMI_SERVICE_IS_ENABLED(psoc->service_param.service_bitmap,
+				      WMI_SERVICE_EXT_MSG);
+}
+
 #else
 static inline uint32_t get_chan_list_cc_event_id(void)
 {
 	return wmi_reg_chan_list_cc_event_id;
 }
+
+static bool tgt_if_regulatory_is_11d_offloaded(struct wlan_objmgr_psoc
+					       *psoc)
+{
+	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	return wmi_service_enabled(wmi_handle,
+				   wmi_service_11d_offload);
+}
+
+static bool tgt_if_regulatory_is_regdb_offloaded(struct wlan_objmgr_psoc
+						 *psoc)
+{
+	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	return wmi_service_enabled(wmi_handle,
+				   wmi_service_regulatory_db);
+}
+
+static bool tgt_if_regulatory_is_there_serv_ready_extn(struct wlan_objmgr_psoc
+						       *psoc)
+{
+	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
+
+	return wmi_service_enabled(wmi_handle,
+				   wmi_service_ext_msg);
+}
+
 #endif
 
 static inline struct wlan_lmac_if_reg_rx_ops *
@@ -185,10 +235,9 @@ static QDF_STATUS tgt_if_regulatory_register_11d_new_cc_handler(
 {
 	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
 
-	return wmi_unified_register_event_handler(wmi_handle,
-						  WMI_11D_NEW_COUNTRY_EVENTID,
-						  tgt_reg_11d_new_cc_handler,
-						  WMI_RX_UMAC_CTX);
+	return wmi_unified_register_event(wmi_handle,
+					  wmi_11d_new_country_event_id,
+					  tgt_reg_11d_new_cc_handler);
 }
 
 static QDF_STATUS tgt_if_regulatory_unregister_11d_new_cc_handler(
@@ -196,8 +245,8 @@ static QDF_STATUS tgt_if_regulatory_unregister_11d_new_cc_handler(
 {
 	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
 
-	return wmi_unified_unregister_event_handler(wmi_handle,
-			WMI_11D_NEW_COUNTRY_EVENTID);
+	return wmi_unified_unregister_event(wmi_handle,
+					    wmi_11d_new_country_event_id);
 }
 
 static QDF_STATUS tgt_if_regulatory_start_11d_scan(
@@ -207,19 +256,20 @@ static QDF_STATUS tgt_if_regulatory_start_11d_scan(
 	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
 
 	return wmi_unified_send_start_11d_scan_cmd(wmi_handle,
-			reg_start_11d_scan_req);
+						   reg_start_11d_scan_req);
 }
 
 static QDF_STATUS tgt_if_regulatory_stop_11d_scan(
-		struct wlan_objmgr_psoc *psoc,
-		struct reg_stop_11d_scan_req *reg_stop_11d_scan_req)
+		   struct wlan_objmgr_psoc *psoc,
+		   struct reg_stop_11d_scan_req *reg_stop_11d_scan_req)
 {
 	wmi_unified_t wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc);
 
 	return wmi_unified_send_stop_11d_scan_cmd(wmi_handle,
-			reg_stop_11d_scan_req);
+						  reg_stop_11d_scan_req);
 }
 
+
 QDF_STATUS target_if_register_regulatory_tx_ops(struct wlan_lmac_if_tx_ops
 						*tx_ops)
 {
@@ -245,6 +295,13 @@ QDF_STATUS target_if_register_regulatory_tx_ops(struct wlan_lmac_if_tx_ops
 
 	reg_ops->stop_11d_scan = tgt_if_regulatory_stop_11d_scan;
 
+	reg_ops->is_11d_offloaded = tgt_if_regulatory_is_11d_offloaded;
+
+	reg_ops->is_regdb_offloaded = tgt_if_regulatory_is_regdb_offloaded;
+
+	reg_ops->is_there_serv_ready_extn =
+		tgt_if_regulatory_is_there_serv_ready_extn;
+
 	return QDF_STATUS_SUCCESS;
 }
 

+ 4 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -562,6 +562,10 @@ struct wlan_lmac_if_reg_tx_ops {
 			struct reg_start_11d_scan_req *reg_start_11d_scan_req);
 	QDF_STATUS (*stop_11d_scan)(struct wlan_objmgr_psoc *psoc,
 			struct reg_stop_11d_scan_req *reg_stop_11d_scan_req);
+
+	bool (*is_11d_offloaded)(struct wlan_objmgr_psoc *psoc);
+	bool (*is_regdb_offloaded)(struct wlan_objmgr_psoc *psoc);
+	bool (*is_there_serv_ready_extn)(struct wlan_objmgr_psoc *psoc);
 };
 
 /**

+ 8 - 2
umac/regulatory/core/src/reg_priv.h

@@ -66,8 +66,14 @@ struct wlan_regulatory_psoc_priv_obj {
 	enum band_info band_capability;
 	bool indoor_chan_enabled;
 	bool enable_11d_supp_original;
-	bool enable_11d_supp_current;
-	bool userspace_country_priority;
+	bool enable_11d_supp;
+	bool is_11d_offloaded;
+	uint8_t vdev_id_for_11d_scan;
+	uint8_t master_vdev_cnt;
+	uint8_t vdev_cnt_11d;
+	uint8_t vdev_ids_11d[MAX_STA_VDEV_CNT];
+	bool user_ctry_priority;
+	bool user_ctry_set;
 	struct chan_change_cbk_entry cbk_list[REG_MAX_CHAN_CHANGE_CBKS];
 	uint8_t num_chan_change_cbks;
 	qdf_spinlock_t cbk_list_lock;

+ 303 - 21
umac/regulatory/core/src/reg_services.c

@@ -37,6 +37,7 @@
 
 #define MAX_PWR_FCC_CHAN_12 8
 #define MAX_PWR_FCC_CHAN_13 2
+#define SCAN_11D_PERIOD_MS 360000
 
 #define IS_VALID_PSOC_REG_OBJ(psoc_priv_obj) (NULL != psoc_priv_obj)
 #define IS_VALID_PDEV_REG_OBJ(pdev_priv_obj) (NULL != pdev_priv_obj)
@@ -1648,6 +1649,7 @@ static QDF_STATUS send_scheduler_msg_sb(struct wlan_objmgr_psoc *psoc,
 		wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
 		return QDF_STATUS_E_NOMEM;
 	}
+
 	msg.bodyptr = payload;
 	msg.callback = sched_chan_change_cbks_sb;
 	msg.flush_callback = chan_change_flush_cbk_sb;
@@ -1705,6 +1707,74 @@ static QDF_STATUS send_scheduler_msg_nb(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+static QDF_STATUS send_11d_flush_cbk(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_psoc *psoc = msg->bodyptr;
+
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS send_11d_msg_cbk(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_psoc *psoc = msg->bodyptr;
+	struct wlan_lmac_if_reg_tx_ops *tx_ops;
+	struct reg_start_11d_scan_req start_req;
+	struct reg_stop_11d_scan_req stop_req;
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	tx_ops = reg_get_psoc_tx_ops(psoc);
+
+	psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
+		wlan_objmgr_psoc_get_comp_private_obj(psoc,
+					 WLAN_UMAC_COMP_REGULATORY);
+
+	if (NULL == psoc_priv_obj) {
+		reg_err("psoc priv obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (psoc_priv_obj->enable_11d_supp) {
+		start_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
+		start_req.scan_period_msec = SCAN_11D_PERIOD_MS;
+		start_req.start_interval_msec = 0;
+		reg_debug("sending start msg");
+		tx_ops->start_11d_scan(psoc, &start_req);
+	} else {
+		stop_req.vdev_id = psoc_priv_obj->vdev_id_for_11d_scan;
+		reg_debug("sending stop msg");
+		tx_ops->stop_11d_scan(psoc, &stop_req);
+	}
+
+	wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS sched_11d_msg(struct wlan_objmgr_psoc *psoc)
+{
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+	status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_REGULATORY_SB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		reg_err("error taking psoc ref cnt");
+		return status;
+	}
+
+	msg.bodyptr = psoc;
+	msg.callback = send_11d_msg_cbk;
+	msg.flush_callback = send_11d_flush_cbk;
+
+	status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wlan_objmgr_psoc_release_ref(psoc, WLAN_REGULATORY_SB_ID);
+		reg_err("scheduler msg posting failed");
+	}
+
+	return status;
+}
+
+
 static void reg_propagate_mas_chan_list_to_pdev(struct wlan_objmgr_psoc *psoc,
 						void *object, void *arg)
 {
@@ -1748,6 +1818,34 @@ static void reg_propagate_mas_chan_list_to_pdev(struct wlan_objmgr_psoc *psoc,
 		send_scheduler_msg_sb(psoc, pdev);
 }
 
+static void reg_run_11d_state_machine(struct wlan_objmgr_psoc *psoc)
+{
+	bool temp_11d_support;
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+
+	psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						 WLAN_UMAC_COMP_REGULATORY);
+	if (NULL == psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return;
+	}
+
+	temp_11d_support = psoc_priv_obj->enable_11d_supp;
+	if (((psoc_priv_obj->user_ctry_set) &&
+	     (psoc_priv_obj->user_ctry_priority)) ||
+	    (psoc_priv_obj->master_vdev_cnt))
+		psoc_priv_obj->enable_11d_supp = false;
+	else
+		psoc_priv_obj->enable_11d_supp =
+			psoc_priv_obj->enable_11d_supp_original;
+
+	reg_debug("inside 11d state machine");
+	if ((temp_11d_support != psoc_priv_obj->enable_11d_supp) &&
+	    (psoc_priv_obj->is_11d_offloaded)) {
+		sched_11d_msg(psoc);
+	}
+}
+
 QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info
 					*regulat_info)
 {
@@ -1756,6 +1854,7 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info
 	struct cur_reg_rule *reg_rule_2g, *reg_rule_5g;
 	uint16_t min_bw_2g, max_bw_2g, min_bw_5g, max_bw_5g;
 	struct regulatory_channel *mas_chan_list;
+	struct wlan_lmac_if_reg_tx_ops *tx_ops;
 	struct wlan_objmgr_psoc *psoc;
 	enum channel_enum chan_enum;
 	QDF_STATUS status;
@@ -1793,7 +1892,19 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info
 		mas_chan_list[chan_enum].nol_chan = false;
 	}
 
-	soc_reg->offload_enabled = regulat_info->offload_enabled;
+	tx_ops = reg_get_psoc_tx_ops(psoc);
+	if (tx_ops->is_regdb_offloaded)
+		soc_reg->offload_enabled =
+			tx_ops->is_regdb_offloaded(psoc);
+	else
+		soc_reg->offload_enabled = false;
+
+	if (tx_ops->is_11d_offloaded)
+		soc_reg->is_11d_offloaded =
+			tx_ops->is_11d_offloaded(psoc);
+	else
+		soc_reg->is_11d_offloaded = false;
+
 	soc_reg->phybitmap = regulat_info->phybitmap;
 	soc_reg->dfs_region = regulat_info->dfs_region;
 	soc_reg->num_phy = regulat_info->num_phy;
@@ -1835,12 +1946,17 @@ QDF_STATUS reg_process_master_chan_list(struct cur_regulatory_info
 
 	soc_reg->cc_src = SOURCE_DRIVER;
 	if (soc_reg->new_user_ctry_pending == true) {
+
 		soc_reg->new_user_ctry_pending = false;
 		soc_reg->cc_src = SOURCE_USERSPACE;
-
+		soc_reg->user_ctry_set = true;
+		reg_debug("new country code is set");
+		reg_run_11d_state_machine(psoc);
 	} else if (soc_reg->new_11d_ctry_pending == true) {
+
 		soc_reg->new_11d_ctry_pending = false;
 		soc_reg->cc_src = SOURCE_11D;
+		soc_reg->user_ctry_set = false;
 	}
 
 	if (soc_reg->offload_enabled) {
@@ -1881,6 +1997,7 @@ QDF_STATUS wlan_regulatory_psoc_obj_created_notification(
 	struct regulatory_channel *mas_chan_list;
 	enum channel_enum chan_enum;
 	QDF_STATUS status;
+	uint8_t i;
 
 	soc_reg_obj = qdf_mem_malloc(sizeof(*soc_reg_obj));
 	if (NULL == soc_reg_obj) {
@@ -1894,6 +2011,12 @@ QDF_STATUS wlan_regulatory_psoc_obj_created_notification(
 	soc_reg_obj->set_fcc_channel = false;
 	soc_reg_obj->band_capability = BAND_ALL;
 	soc_reg_obj->indoor_chan_enabled = true;
+	soc_reg_obj->master_vdev_cnt = 0;
+	soc_reg_obj->vdev_cnt_11d = 0;
+
+	for (i = 0; i < MAX_STA_VDEV_CNT; i++)
+		soc_reg_obj->vdev_ids_11d[i] = INVALID_VDEV_ID;
+
 	qdf_spinlock_create(&soc_reg_obj->cbk_list_lock);
 
 	mas_chan_list = soc_reg_obj->mas_chan_list;
@@ -1938,7 +2061,7 @@ QDF_STATUS wlan_regulatory_psoc_obj_destroyed_notification(
 
 	wlan_psoc_obj_lock(psoc);
 	soc_reg = wlan_objmgr_psoc_get_comp_private_obj(psoc,
-					    WLAN_UMAC_COMP_REGULATORY);
+				     WLAN_UMAC_COMP_REGULATORY);
 	wlan_psoc_obj_unlock(psoc);
 
 	if (NULL == soc_reg) {
@@ -1950,8 +2073,9 @@ QDF_STATUS wlan_regulatory_psoc_obj_destroyed_notification(
 	qdf_spinlock_destroy(&soc_reg->cbk_list_lock);
 
 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
-			WLAN_UMAC_COMP_REGULATORY,
-			soc_reg);
+					  WLAN_UMAC_COMP_REGULATORY,
+					  soc_reg);
+
 	if (status != QDF_STATUS_SUCCESS)
 		reg_err("soc_reg private obj detach failed");
 
@@ -2115,8 +2239,8 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 	struct wlan_objmgr_psoc *parent_psoc;
 	uint32_t pdev_id;
 	uint32_t cnt;
-	uint32_t range_2g_low, range_2g_high,
-		range_5g_low, range_5g_high;
+	uint32_t range_2g_low, range_2g_high;
+	uint32_t range_5g_low, range_5g_high;
 	QDF_STATUS status;
 
 	pdev_priv_obj = qdf_mem_malloc(sizeof(*pdev_priv_obj));
@@ -2136,6 +2260,7 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 
 	if (NULL == psoc_priv_obj) {
 		reg_err("reg psoc private obj is NULL");
+		qdf_mem_free(pdev_priv_obj);
 		return QDF_STATUS_E_FAULT;
 	}
 
@@ -2150,6 +2275,7 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 
 	for (cnt = 0; cnt < PSOC_MAX_PHY_REG_CAP; cnt++) {
 		if (reg_cap_ptr == NULL) {
+			qdf_mem_free(pdev_priv_obj);
 			reg_err(" reg cap ptr is NULL");
 			return QDF_STATUS_E_FAULT;
 		}
@@ -2160,6 +2286,7 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 	}
 
 	if (cnt == PSOC_MAX_PHY_REG_CAP) {
+		qdf_mem_free(pdev_priv_obj);
 		reg_err("extended capabilities not found for pdev");
 		return QDF_STATUS_E_FAULT;
 	}
@@ -2182,8 +2309,11 @@ QDF_STATUS wlan_regulatory_pdev_obj_created_notification(
 
 	status = send_scheduler_msg_sb(parent_psoc, pdev);
 
-	if (QDF_IS_STATUS_ERROR(status))
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(pdev_priv_obj);
+		reg_err("scheduler send msg failed");
 		return status;
+	}
 
 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
 						     WLAN_UMAC_COMP_REGULATORY,
@@ -2224,6 +2354,144 @@ QDF_STATUS wlan_regulatory_pdev_obj_destroyed_notification(
 	return status;
 }
 
+/**
+ * reg_11d_vdev_created_update() - vdev obj create callback
+ * @vdev: vdev pointer
+ *
+ * updates 11d state when a vdev is created.
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	struct wlan_objmgr_pdev *parent_pdev;
+	struct wlan_objmgr_psoc *parent_psoc;
+	uint32_t vdev_id;
+	enum tQDF_ADAPTER_MODE op_mode;
+	uint8_t i;
+
+	wlan_vdev_obj_lock(vdev);
+	op_mode = wlan_vdev_mlme_get_opmode(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	parent_pdev = wlan_vdev_get_pdev(vdev);
+	parent_psoc = wlan_pdev_get_psoc(parent_pdev);
+
+	psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
+		wlan_objmgr_psoc_get_comp_private_obj(parent_psoc,
+					     WLAN_UMAC_COMP_REGULATORY);
+
+	if (!psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	if ((op_mode == QDF_STA_MODE) ||
+	    (op_mode == QDF_P2P_DEVICE_MODE) ||
+	    (op_mode == QDF_P2P_CLIENT_MODE)) {
+		vdev_id = wlan_vdev_get_id(vdev);
+		if (!psoc_priv_obj->vdev_cnt_11d) {
+			psoc_priv_obj->vdev_id_for_11d_scan = vdev_id;
+			reg_debug("running 11d state machine, opmode %d",
+					op_mode);
+			reg_run_11d_state_machine(parent_psoc);
+		}
+
+		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
+			if (psoc_priv_obj->vdev_ids_11d[i] ==
+					INVALID_VDEV_ID) {
+				psoc_priv_obj->vdev_ids_11d[i] = vdev_id;
+				break;
+			}
+		}
+		psoc_priv_obj->vdev_cnt_11d++;
+	}
+
+	if ((op_mode == QDF_P2P_GO_MODE) ||
+	    (op_mode == QDF_SAP_MODE)) {
+		reg_debug("running 11d state machine, opmode %d", op_mode);
+		psoc_priv_obj->master_vdev_cnt++;
+		reg_run_11d_state_machine(parent_psoc);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * reg_11d_vdev_delete_update() - update 11d state upon vdev delete
+ * @vdev: vdev pointer
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	struct wlan_objmgr_pdev *parent_pdev;
+	struct wlan_objmgr_psoc *parent_psoc;
+	enum tQDF_ADAPTER_MODE op_mode;
+	uint32_t vdev_id;
+	uint8_t i;
+
+	wlan_vdev_obj_lock(vdev);
+	op_mode = wlan_vdev_mlme_get_opmode(vdev);
+	wlan_vdev_obj_unlock(vdev);
+
+	parent_pdev = wlan_vdev_get_pdev(vdev);
+	parent_psoc = wlan_pdev_get_psoc(parent_pdev);
+
+	psoc_priv_obj = (struct wlan_regulatory_psoc_priv_obj *)
+		wlan_objmgr_psoc_get_comp_private_obj(parent_psoc,
+					     WLAN_UMAC_COMP_REGULATORY);
+
+	if (!psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return QDF_STATUS_E_FAULT;
+	}
+
+	if ((op_mode == QDF_P2P_GO_MODE) ||
+	    (op_mode == QDF_SAP_MODE)) {
+		psoc_priv_obj->master_vdev_cnt--;
+		reg_debug("run 11d state machine, deleted opmode %d",
+				op_mode);
+		reg_run_11d_state_machine(parent_psoc);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if ((op_mode == QDF_STA_MODE) ||
+	    (op_mode == QDF_P2P_DEVICE_MODE) ||
+	    (op_mode == QDF_P2P_CLIENT_MODE)) {
+		vdev_id = wlan_vdev_get_id(vdev);
+		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
+			if (psoc_priv_obj->vdev_ids_11d[i] == vdev_id) {
+				psoc_priv_obj->vdev_ids_11d[i] =
+					INVALID_VDEV_ID;
+				psoc_priv_obj->vdev_cnt_11d--;
+				break;
+			}
+		}
+
+		if ((psoc_priv_obj->vdev_id_for_11d_scan != vdev_id) ||
+				!psoc_priv_obj->vdev_cnt_11d)
+			return QDF_STATUS_SUCCESS;
+
+		for (i = 0; i < MAX_STA_VDEV_CNT; i++) {
+			if (psoc_priv_obj->vdev_ids_11d[i] ==
+			    INVALID_VDEV_ID)
+				continue;
+			psoc_priv_obj->vdev_id_for_11d_scan =
+				psoc_priv_obj->vdev_ids_11d[i];
+			psoc_priv_obj->enable_11d_supp = false;
+			reg_debug("running 11d state machine, vdev %d",
+				  psoc_priv_obj->vdev_id_for_11d_scan);
+			reg_run_11d_state_machine(parent_psoc);
+			break;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS reg_get_current_chan_list(struct wlan_objmgr_pdev *pdev,
 			  struct regulatory_channel *chan_list)
 {
@@ -2363,9 +2631,7 @@ QDF_STATUS reg_set_config_vars(struct wlan_objmgr_psoc *psoc,
 
 	psoc_priv_obj->enable_11d_supp_original =
 		config_vars.enable_11d_support;
-	psoc_priv_obj->enable_11d_supp_current =
-		config_vars.enable_11d_support;
-	psoc_priv_obj->userspace_country_priority =
+	psoc_priv_obj->user_ctry_priority =
 		config_vars.userspace_ctry_priority;
 	psoc_priv_obj->dfs_enabled =
 		config_vars.dfs_enabled;
@@ -2546,7 +2812,7 @@ enum country_src reg_get_cc_and_src(struct wlan_objmgr_psoc *psoc,
 }
 
 QDF_STATUS reg_program_default_cc(struct wlan_objmgr_psoc *psoc,
-		uint16_t regdmn)
+				  uint16_t regdmn)
 {
 	struct wlan_regulatory_psoc_priv_obj *soc_reg;
 	struct cur_regulatory_info *reg_info;
@@ -2584,8 +2850,8 @@ QDF_STATUS reg_program_default_cc(struct wlan_objmgr_psoc *psoc,
 		cc = regdmn & ~COUNTRY_ERD_FLAG;
 
 		reg_get_rdpair_from_country_code(cc,
-				&country_index,
-				&regdmn_pair);
+						 &country_index,
+						 &regdmn_pair);
 
 		err = reg_get_cur_reginfo(reg_info, country_index, regdmn_pair);
 		if (err == QDF_STATUS_E_FAILURE) {
@@ -2634,7 +2900,7 @@ QDF_STATUS reg_program_chan_list(struct wlan_objmgr_psoc *psoc,
 
 	soc_reg = (struct wlan_regulatory_psoc_priv_obj *)
 		wlan_objmgr_psoc_get_comp_private_obj(psoc,
-				WLAN_UMAC_COMP_REGULATORY);
+				      WLAN_UMAC_COMP_REGULATORY);
 
 	if (NULL == soc_reg) {
 		reg_err("soc_reg is NULL");
@@ -2652,15 +2918,15 @@ QDF_STATUS reg_program_chan_list(struct wlan_objmgr_psoc *psoc,
 
 	if (rd->flags == CC_IS_SET) {
 		reg_get_rdpair_from_country_code(rd->cc.country_code,
-				&country_index,
-				&regdmn_pair);
+						 &country_index,
+						 &regdmn_pair);
 	} else if (rd->flags == ALPHA_IS_SET) {
 		reg_get_rdpair_from_country_iso(rd->cc.alpha,
-				&country_index,
-				&regdmn_pair);
+						&country_index,
+						&regdmn_pair);
 	} else if (rd->flags == REGDMN_IS_SET) {
 		reg_get_rdpair_from_regdmn_id(rd->cc.regdmn_id,
-				&regdmn_pair);
+					      &regdmn_pair);
 	}
 
 	err = reg_get_cur_reginfo(reg_info, country_index, regdmn_pair);
@@ -2721,8 +2987,24 @@ QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_FAILURE;
 	}
 
-	qdf_mem_copy(psoc_priv_obj->current_country, country, REG_ALPHA2_LEN);
 	psoc_priv_obj->new_11d_ctry_pending = true;
 
 	return QDF_STATUS_SUCCESS;
 }
+
+
+bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+
+	psoc_priv_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+					WLAN_UMAC_COMP_REGULATORY);
+
+	if (NULL == psoc_priv_obj) {
+		reg_err("reg psoc private obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return (psoc_priv_obj->enable_11d_supp &&
+		!psoc_priv_obj->is_11d_offloaded);
+}

+ 24 - 0
umac/regulatory/core/src/reg_services.h

@@ -32,6 +32,7 @@
 #include <wlan_objmgr_global_obj.h>
 #include <wlan_objmgr_psoc_obj.h>
 #include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
 #include "reg_db.h"
 #include <reg_services_public_struct.h>
 
@@ -330,4 +331,27 @@ enum country_src reg_get_cc_and_src(struct wlan_objmgr_psoc *psoc,
 QDF_STATUS reg_save_new_11d_country(struct wlan_objmgr_psoc *psoc,
 		uint8_t *country);
 
+/**
+ * reg_11d_enabled_on_host() - know whether 11d enabled on host
+ * @psoc: psoc ptr
+ *
+ * Return: bool
+ */
+bool reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * reg_11d_vdev_delete_update() - update 11d state upon vdev delete
+ * @vdev: vdev pointer
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * reg_11d_vdev_created_update() - update 11d state upon vdev create
+ * @vdev: vdev pointer
+ *
+ * Return: Success or Failure
+ */
+QDF_STATUS reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev);
 #endif

+ 2 - 1
umac/regulatory/dispatcher/inc/reg_services_public_struct.h

@@ -30,7 +30,8 @@
 #define REG_MAX_CHANNELS_PER_OPERATING_CLASS  25
 #define REG_MAX_SUPP_OPER_CLASSES 32
 #define REG_MAX_CHAN_CHANGE_CBKS 30
-
+#define MAX_STA_VDEV_CNT 4
+#define INVALID_VDEV_ID 0xFF
 /**
  * enum channel_enum - channel enumeration
  * @CHAN_ENUM_1:  channel number 1

+ 7 - 0
umac/regulatory/dispatcher/inc/wlan_reg_services_api.h

@@ -368,6 +368,13 @@ void wlan_reg_register_chan_change_callback(struct wlan_objmgr_psoc *psoc,
  */
 void wlan_reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
 					      reg_chan_change_callback cbk);
+/**
+ * wlan_reg_11d_enabled_on_host() - 11d enabled don host
+ * @psoc: psoc ptr
+ *
+ * Return: bool
+ */
+bool wlan_reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc);
 
 /**
  * wlan_reg_get_chip_mode() - get supported chip mode

+ 15 - 0
umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h

@@ -198,4 +198,19 @@ void ucfg_reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
  */
 enum country_src ucfg_reg_get_cc_and_src(struct wlan_objmgr_psoc *psoc,
 					 uint8_t *alpha2);
+/**
+ * ucfg_reg_11d_vdev_delete_update() - update vdev delete to regulatory
+ * @vdev: vdev ptr
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_reg_11d_vdev_created_update() - update vdev create to regulatory
+ * @vdev: vdev ptr
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev);
 #endif

+ 60 - 45
umac/regulatory/dispatcher/src/wlan_reg_services_api.c

@@ -250,69 +250,72 @@ QDF_STATUS wlan_regulatory_init(void)
 	QDF_STATUS status;
 
 	status = wlan_objmgr_register_psoc_create_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_psoc_obj_created_notification, NULL);
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_psoc_obj_created_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
 		reg_err("failed to register reg psoc obj create handler");
 		return status;
 	}
 
 	status = wlan_objmgr_register_psoc_destroy_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_psoc_obj_destroyed_notification, NULL);
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_psoc_obj_destroyed_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
-		reg_err("failed to register reg psoc obj detroy handler");
-		wlan_objmgr_unregister_psoc_create_handler(
-				WLAN_UMAC_COMP_REGULATORY,
-				wlan_regulatory_psoc_obj_created_notification,
-				NULL);
-		return status;
+		reg_err("failed to register reg psoc obj create handler");
+		goto unreg_psoc_create;
 	}
 
 	status = wlan_objmgr_register_pdev_create_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_pdev_obj_created_notification, NULL);
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_pdev_obj_created_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
-		reg_err("failed to register reg pdev obj create handler");
-		return status;
+		reg_err("failed to register reg psoc obj create handler");
+		goto unreg_psoc_destroy;
 	}
 
 	status = wlan_objmgr_register_pdev_destroy_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_pdev_obj_destroyed_notification, NULL);
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_pdev_obj_destroyed_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
-		reg_err("failed to register reg pdev obj destroy handler");
-		wlan_objmgr_unregister_pdev_create_handler(
-				WLAN_UMAC_COMP_REGULATORY,
-				wlan_regulatory_pdev_obj_created_notification,
-				NULL);
-		return status;
+		reg_err("failed to register reg psoc obj create handler");
+		goto unreg_pdev_create;
 	}
 
 	reg_debug("regulatory handlers registered with obj mgr");
 
-	return QDF_STATUS_SUCCESS;
+	return status;
+
+unreg_pdev_create:
+	status = wlan_objmgr_unregister_pdev_create_handler(
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_pdev_obj_created_notification,
+		NULL);
+
+unreg_psoc_destroy:
+	status = wlan_objmgr_unregister_psoc_destroy_handler(
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_psoc_obj_destroyed_notification,
+		NULL);
+
+unreg_psoc_create:
+	status = wlan_objmgr_unregister_psoc_create_handler(
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_psoc_obj_created_notification,
+		NULL);
+
+	return QDF_STATUS_E_FAILURE;
 }
 
 QDF_STATUS wlan_regulatory_deinit(void)
 {
-	QDF_STATUS status;
+	QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS;
 
-	status = wlan_objmgr_unregister_psoc_create_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_psoc_obj_created_notification,
-			NULL);
-	if (status != QDF_STATUS_SUCCESS)
-		reg_err("deregister fail for psoc create notif:%d",
-				status);
-	status = wlan_objmgr_unregister_psoc_destroy_handler(
-			WLAN_UMAC_COMP_REGULATORY,
-			wlan_regulatory_psoc_obj_destroyed_notification,
-			NULL);
+	status = wlan_objmgr_unregister_pdev_destroy_handler(
+		WLAN_UMAC_COMP_REGULATORY,
+		wlan_regulatory_pdev_obj_destroyed_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
-		reg_err("deregister fail for psoc delete notif:%d",
-				status);
-		return status;
+		reg_err("failed to unregister reg pdev obj destroy handler");
+		ret_status = status;
 	}
 
 	status = wlan_objmgr_unregister_pdev_create_handler(
@@ -320,20 +323,28 @@ QDF_STATUS wlan_regulatory_deinit(void)
 		wlan_regulatory_pdev_obj_created_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
 		reg_err("failed to unregister reg pdev obj create handler");
-		return status;
+		ret_status = status;
 	}
 
-	status = wlan_objmgr_unregister_pdev_destroy_handler(
+	status = wlan_objmgr_unregister_psoc_destroy_handler(
 		WLAN_UMAC_COMP_REGULATORY,
-		wlan_regulatory_pdev_obj_destroyed_notification, NULL);
+		wlan_regulatory_psoc_obj_destroyed_notification, NULL);
 	if (status != QDF_STATUS_SUCCESS) {
-		reg_err("failed to unregister reg pdev obj destroy handler");
-		return status;
+		reg_err("failed to unregister reg psoc obj destroy handler");
+		ret_status = status;
 	}
 
-	reg_debug("deregistered callbacks with obj mgr successfully");
+	status = wlan_objmgr_unregister_psoc_create_handler(
+			WLAN_UMAC_COMP_REGULATORY,
+			wlan_regulatory_psoc_obj_created_notification, NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		reg_err("failed to unregister reg psoc obj create handler");
+		ret_status = status;
+	}
 
-	return QDF_STATUS_SUCCESS;
+	reg_debug("deregistered callbacks with obj mgr");
+
+	return ret_status;
 }
 
 QDF_STATUS regulatory_psoc_open(struct wlan_objmgr_psoc *psoc)
@@ -416,7 +427,11 @@ void wlan_reg_unregister_chan_change_callback(struct wlan_objmgr_psoc *psoc,
 					      reg_chan_change_callback cbk)
 {
 	reg_unregister_chan_change_callback(psoc, cbk);
+}
 
+bool wlan_reg_11d_enabled_on_host(struct wlan_objmgr_psoc *psoc)
+{
+	return reg_11d_enabled_on_host(psoc);
 }
 
 QDF_STATUS wlan_reg_get_chip_mode(struct wlan_objmgr_pdev *pdev,

+ 10 - 0
umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c

@@ -204,3 +204,13 @@ enum country_src ucfg_reg_get_cc_and_src(struct wlan_objmgr_psoc *psoc,
 {
 	return reg_get_cc_and_src(psoc, alpha2);
 }
+
+QDF_STATUS ucfg_reg_11d_vdev_delete_update(struct wlan_objmgr_vdev *vdev)
+{
+	return reg_11d_vdev_delete_update(vdev);
+}
+
+QDF_STATUS ucfg_reg_11d_vdev_created_update(struct wlan_objmgr_vdev *vdev)
+{
+	return reg_11d_vdev_created_update(vdev);
+}

+ 1 - 0
wmi/inc/wmi_unified_param.h

@@ -4956,6 +4956,7 @@ typedef enum {
 	wmi_dfs_cac_complete_id,
 	wmi_dfs_radar_detection_event_id,
 	wmi_ext_tbttoffset_update_event_id,
+	wmi_11d_new_country_event_id,
 
 	wmi_events_max,
 } wmi_conv_event_id;

+ 1 - 0
wmi/src/wmi_unified_tlv.c

@@ -18435,6 +18435,7 @@ static void populate_tlv_events_id(uint32_t *event_ids)
 	event_ids[wmi_dfs_radar_detection_event_id] =
 		WMI_PDEV_DFS_RADAR_DETECTION_EVENTID;
 	event_ids[wmi_tt_stats_event_id] = WMI_THERM_THROT_STATS_EVENTID;
+	event_ids[wmi_11d_new_country_event_id] = WMI_11D_NEW_COUNTRY_EVENTID;
 }
 
 #ifndef CONFIG_MCL