Эх сурвалжийг харах

qcacmn: Fetch usable channels for particular band and dev mode

Add support to get usable channels for particular band and
dev mode.

Change-Id: I891e041d777ba37686fbc35b3c14cc964e5db159
CRs-Fixed: 2947182
sheenam monga 4 жил өмнө
parent
commit
09bb1c3ad0

+ 419 - 0
umac/regulatory/core/src/reg_services_common.c

@@ -35,6 +35,7 @@
 #include "reg_build_chan_list.h"
 #include <wlan_objmgr_pdev_obj.h>
 #include <target_if.h>
+#include "wlan_mlme_ucfg_api.h"
 
 const struct chan_map *channel_map;
 #ifdef CONFIG_CHAN_NUM_API
@@ -3292,6 +3293,424 @@ reg_is_freq_present_in_cur_chan_list(struct wlan_objmgr_pdev *pdev,
 	return false;
 }
 
+#ifdef WLAN_FEATURE_GET_USABLE_CHAN_LIST
+/**
+ * is_freq_present_in_resp_list() - is freq present in resp list
+ *
+ * @pcl_ch: pcl ch
+ * @res_msg: Response msg
+ * @count: no of usable channels
+ *
+ * Return: void
+ */
+static bool
+is_freq_present_in_resp_list(uint32_t pcl_ch,
+			     struct get_usable_chan_res_params *res_msg,
+			     int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (res_msg[i].freq == pcl_ch)
+			return true;
+	}
+	return false;
+}
+
+/**
+ * reg_update_usable_chan_resp() - Update response msg
+ * @pdev: Pointer to pdev
+ * @res_msg: Response msg
+ * @pcl_ch: pcl channel
+ * @len: calculated pcl len
+ * @iface_mode_mask: interface type
+ * @count: no of usable channels
+ *
+ * Return: void
+ */
+static void
+reg_update_usable_chan_resp(struct wlan_objmgr_pdev *pdev,
+			    struct get_usable_chan_res_params *res_msg,
+			    uint32_t *pcl_ch, uint32_t len,
+			    uint32_t iface_mode_mask, int *count)
+{
+	int i;
+	struct ch_params ch_params = {0};
+	int index = *count;
+
+	for (i = 0; i < len; i++) {
+/*
+ * In case usable channels are required for multiple filter mask,
+ * Some frequencies may present in res_msg . To avoid frequency
+ * duplication, only mode mask is updated for existing freqency.
+ */
+		if (is_freq_present_in_resp_list(pcl_ch[i], res_msg, *count)) {
+			res_msg[i].iface_mode_mask |= 1 << iface_mode_mask;
+			continue;
+		}
+		ch_params.ch_width = CH_WIDTH_MAX;
+		reg_set_channel_params_for_freq(
+				pdev,
+				pcl_ch[i],
+				0, &ch_params);
+		res_msg[index].freq = pcl_ch[i];
+		res_msg[index].iface_mode_mask |= 1 << iface_mode_mask;
+		res_msg[index].bw = ch_params.ch_width;
+		if (ch_params.center_freq_seg0)
+			res_msg[index].seg0_freq =
+					ch_params.center_freq_seg0;
+		if (ch_params.center_freq_seg1)
+			res_msg[index].seg1_freq =
+					ch_params.center_freq_seg1;
+		index++;
+	}
+
+	*count = index;
+}
+
+/**
+ * reg_update_conn_chan_list() - Get usable channels with conn filter
+ *				 and policy mgr mask
+ * @pdev: Pointer to pdev
+ * @res_msg: Response msg
+ * @policy_mgr_con_mode: policy mgr mode
+ * @iftype: interface type
+ * @count: no of usable channels
+ *
+ * Return: qdf status
+ */
+static QDF_STATUS
+reg_update_conn_chan_list(struct wlan_objmgr_pdev *pdev,
+			  struct get_usable_chan_res_params *res_msg,
+			  enum policy_mgr_con_mode mode,
+			  uint32_t iftype,
+			  uint32_t *count)
+{
+	uint32_t pcl_ch[NUM_CHANNELS] = {0};
+	uint8_t weight_list[NUM_CHANNELS] = {0};
+	uint32_t len;
+	uint32_t weight_len;
+	struct wlan_objmgr_psoc *psoc;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		reg_err("invalid psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	len = QDF_ARRAY_SIZE(pcl_ch);
+	weight_len = QDF_ARRAY_SIZE(weight_list);
+
+	status = policy_mgr_get_pcl(psoc, mode, pcl_ch, &len,
+				    weight_list, weight_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		reg_err("get pcl failed for mode: %d", mode);
+		return status;
+	}
+	reg_update_usable_chan_resp(pdev, res_msg, pcl_ch, len, iftype, count);
+	return status;
+}
+
+/**
+ * reg_get_usable_channel_con_filter() - Get usable channel with con filter mask
+ * @pdev: Pointer to pdev
+ * @req_msg: Request msg
+ * @res_msg: Response msg
+ * @chan_list: reg channel list
+ * @count: no of usable channels
+ *
+ * Return: qdf status
+ */
+static QDF_STATUS
+reg_get_usable_channel_con_filter(struct wlan_objmgr_pdev *pdev,
+				  struct get_usable_chan_req_params req_msg,
+				  struct get_usable_chan_res_params *res_msg,
+				  struct regulatory_channel *chan_list,
+				  int *count)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (req_msg.iface_mode_mask & 1 << IFTYPE_AP) {
+		status =
+		reg_update_conn_chan_list(pdev, res_msg, PM_SAP_MODE,
+					  IFTYPE_AP, count);
+	}
+	if (req_msg.iface_mode_mask & 1 << IFTYPE_STATION) {
+		status =
+		reg_update_conn_chan_list(pdev, res_msg, PM_STA_MODE,
+					  IFTYPE_STATION, count);
+	}
+	if (req_msg.iface_mode_mask & 1 << IFTYPE_P2P_GO) {
+		status =
+		reg_update_conn_chan_list(pdev, res_msg, PM_P2P_GO_MODE,
+					  IFTYPE_P2P_GO, count);
+	}
+	if (req_msg.iface_mode_mask & 1 << IFTYPE_P2P_CLIENT) {
+		status =
+		reg_update_conn_chan_list(pdev, res_msg, PM_P2P_CLIENT_MODE,
+					  IFTYPE_P2P_CLIENT, count);
+	}
+	return status;
+}
+
+/**
+ * reg_remove_freq() - Remove invalid freq
+ * @res_msg: Response msg
+ * @index: index of freq that needs to be removed
+ *
+ * Return: void
+ */
+static void
+reg_remove_freq(struct get_usable_chan_res_params *res_msg,
+		int index)
+{
+	reg_debug("removing freq %d", res_msg[index].freq);
+	qdf_mem_zero(&res_msg[index],
+		     sizeof(struct get_usable_chan_res_params));
+}
+
+/**
+ * reg_skip_invalid_chan_for_sap_p2p_go() - Remove invalid freq for SAP & P2PGO
+ * @pdev: Pointer to pdev
+ * @res_msg: Response msg
+ * @count: no of usable channels
+ * @iface_mode_mask: interface mode mask
+ *
+ * Return: qdf status
+ */
+static QDF_STATUS
+reg_skip_invalid_chan_for_sap_p2p_go(struct wlan_objmgr_pdev *pdev,
+				     struct get_usable_chan_res_params *res_msg,
+				     uint32_t *no_usable_channels,
+				     uint32_t iface_mode_mask)
+{
+	uint32_t chan_enum, iface_mode = 0;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	bool include_indoor_channel;
+	uint8_t enable_srd_chan, srd_mask = 0;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		reg_err("invalid psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = ucfg_mlme_get_indoor_channel_support(psoc,
+						      &include_indoor_channel);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		reg_err("failed to get indoor channel skip info");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ucfg_mlme_get_etsi_srd_chan_in_master_mode(psoc,
+						   &enable_srd_chan);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		reg_err("failed to get srd chan info");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	while (iface_mode_mask) {
+		if (iface_mode_mask & (1 << IFTYPE_AP)) {
+			srd_mask = 1;
+			iface_mode = 1 << IFTYPE_AP;
+		} else if (iface_mode_mask & (1 << IFTYPE_P2P_GO)) {
+			srd_mask = 2;
+			iface_mode = 1 << IFTYPE_P2P_GO;
+		} else {
+			break;
+		}
+		for (chan_enum = 0; chan_enum < *no_usable_channels;
+		     chan_enum++) {
+			if (wlan_reg_is_freq_indoor(
+					pdev, res_msg[chan_enum].freq) &&
+					!include_indoor_channel) {
+				res_msg[chan_enum].iface_mode_mask &=
+						~(iface_mode);
+				if (!res_msg[chan_enum].iface_mode_mask)
+					reg_remove_freq(res_msg, chan_enum);
+			}
+
+			if (!(enable_srd_chan & srd_mask) &&
+			    reg_is_etsi13_srd_chan(
+					pdev, res_msg[chan_enum].freq)) {
+				res_msg[chan_enum].iface_mode_mask &=
+					~(iface_mode);
+				if (!res_msg[chan_enum].iface_mode_mask)
+					reg_remove_freq(res_msg, chan_enum);
+			}
+		}
+
+		iface_mode_mask &= ~iface_mode;
+	}
+
+	return status;
+}
+
+/**
+ * reg_get_usable_channel_no_filter() - Get usable channel with no filter mask
+ * @pdev: Pointer to pdev
+ * @req_msg: Request msg
+ * @res_msg: Response msg
+ * @chan_list: reg channel list
+ * @count: no of usable channels
+ *
+ * Return: qdf status
+ */
+static QDF_STATUS
+reg_get_usable_channel_no_filter(struct wlan_objmgr_pdev *pdev,
+				 struct get_usable_chan_req_params req_msg,
+				 struct get_usable_chan_res_params *res_msg,
+				 struct regulatory_channel *chan_list,
+				 int *count)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	status =
+	reg_skip_invalid_chan_for_sap_p2p_go(pdev, res_msg,
+					     count, req_msg.iface_mode_mask);
+	return status;
+}
+
+/**
+ * reg_get_usable_channel_coex_filter() - Get usable channel with coex filter
+ * @pdev: Pointer to pdev
+ * @req_msg: Request msg
+ * @res_msg: Response msg
+ * @chan_list: reg channel list
+ * @count: no of usable channels
+ *
+ * Return: qdf status
+ */
+static QDF_STATUS
+reg_get_usable_channel_coex_filter(struct wlan_objmgr_pdev *pdev,
+				   struct get_usable_chan_req_params req_msg,
+				   struct get_usable_chan_res_params *res_msg,
+				   struct regulatory_channel *chan_list,
+				   int *count)
+{
+	struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj;
+	enum channel_enum chan_enum;
+	uint32_t index = 0, i = 0;
+	struct ch_avoid_freq_type freq_range;
+	struct wlan_objmgr_psoc *psoc;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	if (!psoc) {
+		reg_err("invalid psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	psoc_priv_obj = reg_get_psoc_obj(psoc);
+	if (!IS_VALID_PSOC_REG_OBJ(psoc_priv_obj)) {
+		reg_alert("psoc reg component is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	for (chan_enum = 0; chan_enum < *count; chan_enum++) {
+		for (i = 0; i <
+		    psoc_priv_obj->avoid_freq_list.ch_avoid_range_cnt; i++) {
+			freq_range =
+			psoc_priv_obj->avoid_freq_list.avoid_freq_range[i];
+
+			if (freq_range.start_freq <=
+			    chan_list[chan_enum].center_freq &&
+			    freq_range.end_freq >=
+			    chan_list[chan_enum].center_freq) {
+				reg_remove_freq(res_msg, chan_enum);
+			}
+		}
+		index++;
+	}
+	if (req_msg.iface_mode_mask & 1 << IFTYPE_AP ||
+	    req_msg.iface_mode_mask & 1 << IFTYPE_P2P_GO)
+		status =
+		reg_skip_invalid_chan_for_sap_p2p_go(pdev, res_msg, count,
+						     req_msg.iface_mode_mask);
+	return status;
+}
+
+/**
+ * reg_add_usable_channel_to_resp() - Add usable channels to resp structure
+ * @pdev: Pointer to pdev
+ * @res_msg: Response msg
+ * @iface_mode_mask: interface mode mask
+ * @chan_list: reg channel list
+ * @count: no of usable channels
+ *
+ * Return: void
+ */
+static void
+reg_add_usable_channel_to_resp(struct wlan_objmgr_pdev *pdev,
+			       struct get_usable_chan_res_params *res_msg,
+			       uint32_t iface_mode_mask,
+			       struct regulatory_channel *chan_list,
+			       int *count)
+{
+	enum channel_enum chan_enum;
+	struct ch_params ch_params = {0};
+
+	for (chan_enum = 0; chan_enum < *count; chan_enum++) {
+		ch_params.ch_width = CH_WIDTH_MAX;
+		reg_set_channel_params_for_freq(
+				pdev,
+				chan_list[chan_enum].center_freq,
+				chan_list[chan_enum].max_bw, &ch_params);
+
+		res_msg[chan_enum].freq = chan_list[chan_enum].center_freq;
+		res_msg[chan_enum].iface_mode_mask = iface_mode_mask;
+		res_msg[chan_enum].bw = chan_list[chan_enum].max_bw;
+		if (ch_params.center_freq_seg0)
+			res_msg[chan_enum].seg0_freq =
+					ch_params.center_freq_seg0;
+		if (ch_params.center_freq_seg1)
+			res_msg[chan_enum].seg1_freq =
+					ch_params.center_freq_seg1;
+	}
+}
+
+QDF_STATUS
+wlan_reg_get_usable_channel(struct wlan_objmgr_pdev *pdev,
+			    struct get_usable_chan_req_params req_msg,
+			    struct get_usable_chan_res_params *res_msg,
+			    uint32_t *usable_channels)
+{
+	struct regulatory_channel chan_list[NUM_CHANNELS];
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if ((req_msg.filter_mask & 1 << FILTER_CELLULAR_COEX) ||
+	    (!(req_msg.filter_mask & 1 << FILTER_CELLULAR_COEX) &&
+	     !(req_msg.filter_mask & 1 << FILTER_WLAN_CONCURRENCY))) {
+		*usable_channels = reg_get_band_channel_list(pdev,
+							     req_msg.band_mask,
+							     chan_list);
+
+		reg_add_usable_channel_to_resp(pdev, res_msg,
+					       req_msg.iface_mode_mask,
+					       chan_list, usable_channels);
+	}
+
+	if (req_msg.filter_mask & 1 << FILTER_CELLULAR_COEX)
+		status =
+		reg_get_usable_channel_coex_filter(pdev, req_msg, res_msg,
+						   chan_list, usable_channels);
+
+	if (req_msg.filter_mask & 1 << FILTER_WLAN_CONCURRENCY)
+		status =
+		reg_get_usable_channel_con_filter(pdev, req_msg, res_msg,
+						  chan_list, usable_channels);
+
+	if (!(req_msg.filter_mask & 1 << FILTER_CELLULAR_COEX) &&
+	    !(req_msg.filter_mask & 1 << FILTER_WLAN_CONCURRENCY))
+		status =
+		reg_get_usable_channel_no_filter(pdev, req_msg, res_msg,
+						 chan_list, usable_channels);
+
+	return status;
+}
+#endif
+
 enum channel_state reg_get_channel_state_for_freq(struct wlan_objmgr_pdev *pdev,
 						  qdf_freq_t freq)
 {

+ 87 - 0
umac/regulatory/dispatcher/inc/reg_services_public_struct.h

@@ -802,6 +802,93 @@ enum country_src {
 	SOURCE_11D
 };
 
+#ifdef WLAN_FEATURE_GET_USABLE_CHAN_LIST
+/**
+ * enum iftype - (virtual) interface types
+ *
+ * @IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @IFTYPE_ADHOC: independent BSS member
+ * @IFTYPE_STATION: managed BSS member
+ * @IFTYPE_AP: access point
+ * @IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ *      are a bit special in that they must always be tied to a pre-existing
+ *      AP type interface.
+ * @IFTYPE_WDS: wireless distribution interface
+ * @IFTYPE_MONITOR: monitor interface receiving all frames
+ * @IFTYPE_MESH_POINT: mesh point
+ * @IFTYPE_P2P_CLIENT: P2P client
+ * @IFTYPE_P2P_GO: P2P group owner
+ * @IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
+ *      and therefore can't be created in the normal ways, use the
+ *      %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
+ *      commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ *      This mode corresponds to the MIB variable dot11OCBActivated=true
+ * @IFTYPE_MAX: highest interface type number currently defined
+ * @NUM_IFTYPES: number of defined interface types
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum iftype {
+	IFTYPE_UNSPECIFIED,
+	IFTYPE_ADHOC,
+	IFTYPE_STATION,
+	IFTYPE_AP,
+	IFTYPE_AP_VLAN,
+	IFTYPE_WDS,
+	IFTYPE_MONITOR,
+	IFTYPE_MESH_POINT,
+	IFTYPE_P2P_CLIENT,
+	IFTYPE_P2P_GO,
+	IFTYPE_P2P_DEVICE,
+	IFTYPE_OCB,
+
+	/* keep last */
+	NUM_IFTYPES,
+	IFTYPE_MAX = NUM_IFTYPES - 1
+};
+
+/**
+ * usable_channels_filter - Filters to get usable channels
+ * FILTER_CELLULAR_COEX: Avoid lte coex channels
+ * FILTER_WLAN_CONCURRENCY: Avoid con channels
+ **/
+enum usable_channels_filter {
+	FILTER_CELLULAR_COEX = 0,
+	FILTER_WLAN_CONCURRENCY = 1,
+};
+
+/**
+ * get_usable_chan_res_params - Usable channels resp params
+ * freq : center freq
+ * seg0_freq : seg0 freq
+ * seg1_freq: seg1 freq
+ * bw : bandwidth
+ * iface_mode_mask: interface mode mask
+ **/
+struct get_usable_chan_res_params {
+	uint32_t freq;
+	uint32_t seg0_freq;
+	uint32_t seg1_freq;
+	uint32_t bw;
+	uint32_t iface_mode_mask;
+};
+
+/**
+ * get_usable_chan_req_params - Usable channels req params
+ * band_mask : band mask
+ * iface_mode_mask: interface mode mask
+ * filter_mask: filter mask
+ **/
+struct get_usable_chan_req_params {
+	uint32_t band_mask;
+	uint32_t iface_mode_mask;
+	uint32_t filter_mask;
+};
+#endif
+
 /**
  * struct regulatory_channel
  * @center_freq: center frequency

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

@@ -1084,6 +1084,23 @@ wlan_reg_disable_chan_coex(struct wlan_objmgr_pdev *pdev,
 }
 #endif
 
+#ifdef WLAN_FEATURE_GET_USABLE_CHAN_LIST
+/**
+ * wlan_reg_get_usable_channel() - Get usable channels
+ * @pdev: Pointer to pdev
+ * @req_msg: Request msg
+ * @res_msg: Response msg
+ * @count: no of usable channels
+ *
+ * Return: qdf status
+ */
+QDF_STATUS
+wlan_reg_get_usable_channel(struct wlan_objmgr_pdev *pdev,
+			    struct get_usable_chan_req_params req_msg,
+			    struct get_usable_chan_res_params *res_msg,
+			    uint32_t *count);
+#endif
+
 #ifdef CONFIG_CHAN_FREQ_API
 /**
  * wlan_reg_is_same_band_freqs() - Check if two channel frequencies