qcacmn: Add support to disable channel list

Propagation from prima to qcacmn

Add support to disable channel list received with command
"SET_DISABLE_CHANNEL_LIST".
As part of this command, number of channels and list
of that many channels should be given. When SAP comes up, disable
the channels received in the command. If any of the interface
is up on any of the channel from the list, first disconnect
the interface and start the interface on the new channel.

Change-Id: I3c7810bfde78878a3e60570a13bf2741e1da599b
CRs-Fixed: 2225865
diff --git a/umac/regulatory/core/src/reg_priv.h b/umac/regulatory/core/src/reg_priv.h
index b8e5d37..a6de5ef 100644
--- a/umac/regulatory/core/src/reg_priv.h
+++ b/umac/regulatory/core/src/reg_priv.h
@@ -83,6 +83,11 @@
 struct wlan_regulatory_pdev_priv_obj {
 	struct regulatory_channel cur_chan_list[NUM_CHANNELS];
 	struct regulatory_channel mas_chan_list[NUM_CHANNELS];
+#ifdef DISABLE_CHANNEL_LIST
+	struct regulatory_channel cache_disable_chan_list[NUM_CHANNELS];
+	uint32_t num_cache_channels;
+	bool disable_cached_channels;
+#endif
 	char default_country[REG_ALPHA2_LEN + 1];
 	uint16_t def_region_domain;
 	uint16_t def_country_code;
diff --git a/umac/regulatory/core/src/reg_services.c b/umac/regulatory/core/src/reg_services.c
index de030ec..145338b 100644
--- a/umac/regulatory/core/src/reg_services.c
+++ b/umac/regulatory/core/src/reg_services.c
@@ -2181,6 +2181,37 @@
 	}
 }
 
+#ifdef DISABLE_CHANNEL_LIST
+static void reg_modify_chan_list_for_cached_channels(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+	uint32_t i, j, num_cache_channels = pdev_priv_obj->num_cache_channels;
+	struct regulatory_channel *chan_list = pdev_priv_obj->cur_chan_list;
+	struct regulatory_channel *cache_chan_list =
+					pdev_priv_obj->cache_disable_chan_list;
+
+	if (!num_cache_channels)
+		return;
+
+	if (pdev_priv_obj->disable_cached_channels) {
+		for (i = 0; i < num_cache_channels; i++)
+			for (j = 0; j < NUM_CHANNELS; j++)
+				if (cache_chan_list[i].chan_num ==
+							chan_list[j].chan_num) {
+					chan_list[j].state =
+							CHANNEL_STATE_DISABLE;
+					chan_list[j].chan_flags |=
+						REGULATORY_CHAN_DISABLED;
+				}
+	}
+}
+#else
+static void reg_modify_chan_list_for_cached_channels(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+}
+#endif
+
 static void reg_modify_chan_list_for_band(struct regulatory_channel *chan_list,
 					  enum band_info band_val)
 {
@@ -2522,6 +2553,8 @@
 
 	reg_modify_chan_list_for_chan_144(pdev_priv_obj->cur_chan_list,
 					  pdev_priv_obj->en_chan_144);
+
+	reg_modify_chan_list_for_cached_channels(pdev_priv_obj);
 }
 
 static void reg_call_chan_change_cbks(struct wlan_objmgr_psoc *psoc,
@@ -3287,6 +3320,105 @@
 	return status;
 }
 
+#ifdef DISABLE_CHANNEL_LIST
+QDF_STATUS reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+	struct wlan_objmgr_psoc *psoc;
+	QDF_STATUS status;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg component is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		reg_err("psoc is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
+		reg_err("psoc reg component is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev_priv_obj->disable_cached_channels = false;
+	reg_compute_pdev_current_chan_list(pdev_priv_obj);
+	status = reg_send_scheduler_msg_sb(psoc, pdev);
+	return status;
+}
+
+QDF_STATUS reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				   uint32_t *channel_list,
+				   uint32_t num_channels)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+	struct wlan_objmgr_psoc *psoc;
+	uint8_t i, j;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg component is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		reg_err("psoc is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
+		reg_err("psoc reg component is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (pdev_priv_obj->num_cache_channels > 0) {
+		pdev_priv_obj->num_cache_channels = 0;
+		qdf_mem_set(&pdev_priv_obj->cache_disable_chan_list,
+			    sizeof(pdev_priv_obj->cache_disable_chan_list), 0);
+	}
+
+	for (i = 0; i < num_channels; i++) {
+		for (j = 0; j < NUM_CHANNELS; j++) {
+			if (channel_list[i] == pdev_priv_obj->
+						cur_chan_list[j].chan_num) {
+				pdev_priv_obj->
+					cache_disable_chan_list[i].chan_num =
+							channel_list[i];
+				pdev_priv_obj->
+					cache_disable_chan_list[i].state =
+					pdev_priv_obj->cur_chan_list[j].state;
+				pdev_priv_obj->
+					cache_disable_chan_list[i].chan_flags =
+					pdev_priv_obj->
+						cur_chan_list[j].chan_flags;
+			}
+		}
+	}
+	pdev_priv_obj->num_cache_channels = num_channels;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void set_disable_channel_state(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+	pdev_priv_obj->disable_cached_channels = pdev_priv_obj->sap_state;
+}
+#else
+static void set_disable_channel_state(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+}
+#endif
+
 QDF_STATUS reg_notify_sap_event(struct wlan_objmgr_pdev *pdev,
 			bool sap_state)
 {
@@ -3320,6 +3452,7 @@
 		return QDF_STATUS_SUCCESS;
 
 	pdev_priv_obj->sap_state = sap_state;
+	set_disable_channel_state(pdev_priv_obj);
 
 	reg_compute_pdev_current_chan_list(pdev_priv_obj);
 	status = reg_send_scheduler_msg_sb(psoc, pdev);
diff --git a/umac/regulatory/core/src/reg_services.h b/umac/regulatory/core/src/reg_services.h
index f843eb6..c78c65c 100644
--- a/umac/regulatory/core/src/reg_services.h
+++ b/umac/regulatory/core/src/reg_services.h
@@ -131,6 +131,41 @@
 QDF_STATUS reg_set_band(struct wlan_objmgr_pdev *pdev, enum band_info band);
 
 /**
+ * reg_restore_cached_channels() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ */
+#ifdef DISABLE_CHANNEL_LIST
+QDF_STATUS reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev);
+#else
+static inline
+QDF_STATUS reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * reg_cache_channel_state() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ * @channel_list: List of the channels for which states needs to be cached
+ * @num_channels: Number of channels in the list
+ *
+ */
+#ifdef DISABLE_CHANNEL_LIST
+QDF_STATUS reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				   uint32_t *channel_list,
+				   uint32_t num_channels);
+#else
+static inline
+QDF_STATUS reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				   uint32_t *channel_list,
+				   uint32_t num_channels)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
  * reg_notify_sap_event() - Notify regulatory domain for sap event
  * @pdev: The physical dev to set the band for
  * @sap_state: true for sap start else false
diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h
index 0fb420b..286ee98 100644
--- a/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h
+++ b/umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h
@@ -54,6 +54,42 @@
 			bool sap_state);
 
 /**
+ * ucfg_reg_cache_channel_state() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ * @channel_list: List of the channels for which states needs to be cached
+ * @num_channels: Number of channels in the list
+ *
+ * Return: QDF_STATUS
+ */
+#ifdef DISABLE_CHANNEL_LIST
+void ucfg_reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				  uint32_t *channel_list,
+				  uint32_t num_channels);
+#else
+static inline
+void ucfg_reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				  uint32_t *channel_list,
+				  uint32_t num_channels)
+{
+}
+#endif
+
+/**
+ * ucfg_reg_restore_cached_channels() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ *
+ * Return: QDF_STATUS
+ */
+#ifdef DISABLE_CHANNEL_LIST
+void ucfg_reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev);
+#else
+static inline
+void ucfg_reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
+{
+}
+#endif
+
+/**
  * ucfg_reg_set_fcc_constraint() - apply fcc constraints on channels 12/13
  * @pdev: The physical pdev to reduce tx power for
  *
diff --git a/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c b/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c
index 4ae7b03..61252f6 100644
--- a/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c
+++ b/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c
@@ -131,6 +131,30 @@
 	return reg_notify_sap_event(pdev, sap_state);
 }
 
+#ifdef DISABLE_CHANNEL_LIST
+/**
+ * ucfg_reg_cache_channel_state() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ * @channel_list: List of the channels for which states needs to be cached
+ * @num_channels: Number of channels in the list
+ *
+ */
+void ucfg_reg_cache_channel_state(struct wlan_objmgr_pdev *pdev,
+				  uint32_t *channel_list, uint32_t num_channels)
+{
+	reg_cache_channel_state(pdev, channel_list, num_channels);
+}
+
+/**
+ * ucfg_reg_restore_cached_channels() - Cache the current state of the channles
+ * @pdev: The physical dev to cache the channels for
+ */
+void ucfg_reg_restore_cached_channels(struct wlan_objmgr_pdev *pdev)
+{
+	reg_restore_cached_channels(pdev);
+}
+#endif
+
 /**
  * ucfg_reg_set_fcc_constraint() - apply fcc constraints on channels 12/13
  * @pdev: The physical pdev to reduce tx power for