Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a1686b0 authored by sheenam monga's avatar sheenam monga Committed by Madan Koyyalamudi
Browse files

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
parent 81924701
Loading
Loading
Loading
Loading
+419 −0
Original line number Diff line number Diff line
@@ -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
@@ -3286,6 +3287,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
Original line number Diff line number Diff line
@@ -775,6 +775,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
Original line number Diff line number Diff line
@@ -1222,6 +1222,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