Selaa lähdekoodia

qcacmn: Add support for NLA type CH_INFO_RESP in LOWI

Host driver processes cld80211 vendor sub command
CLD80211_VENDOR_SUB_CMD_GET_CH_INFO and respond with
NLA type CH_INFO response

CRs-Fixed: 2595374
Change-Id: Ibe6f2431ac1cae6e4560ec11424434b4f1cf8b76
Vinay Gannevaram 5 vuotta sitten
vanhempi
sitoutus
8fd2d1abbf

+ 38 - 0
os_if/linux/wifi_pos/inc/os_if_wifi_pos.h

@@ -173,5 +173,43 @@ enum cld80211_sub_attr_cap_rsp {
 	CLD80211_SUB_ATTR_CAPS_MAX =
 		CLD80211_SUB_ATTR_CAPS_AFTER_LAST - 1
 };
+
+/**
+ * enum cld80211_sub_attr_channel_rsp - Chan info response sub attribute
+ * @CLD80211_SUB_ATTR_CH_RESP_INVALID: Invalid channel resp
+ * @CLD80211_SUB_ATTR_CH_MORE_DATA: More date sub attr for frag response
+ * @CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN: Number of channels in response
+ * @CLD80211_SUB_ATTR_CHANNEL_LIST: Channel list nesting
+ * @CLD80211_SUB_ATTR_CH_CHAN_ID: Channel number
+ * @CLD80211_SUB_ATTR_CH_MHZ: Channel frequency
+ * @CLD80211_SUB_ATTR_CH_BAND_CF_1: Center frequency 1
+ * @CLD80211_SUB_ATTR_CH_BAND_CF_2: Center frequency 2
+ * @CLD80211_SUB_ATTR_CH_INFO: channel info
+ * @CLD80211_SUB_ATTR_CH_REG_INFO_1: regulatory info field 1
+ * @CLD80211_SUB_ATTR_CH_REG_INFO_2: regulatory info field 2
+ * @CLD80211_SUB_ATTR_CAPS_MAX: Max number for CHAN Info sub attribute
+ *
+ */
+enum cld80211_sub_attr_channel_rsp {
+	CLD80211_SUB_ATTR_CH_RESP_INVALID = 0,
+	CLD80211_SUB_ATTR_CH_MORE_DATA = 1,
+	CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN = 2,
+	CLD80211_SUB_ATTR_CH_LIST = 3,
+	/* CH_* belongs to CH_LIST */
+	CLD80211_SUB_ATTR_CH_CHAN_ID = 4,
+	CLD80211_SUB_ATTR_CH_MHZ = 5,
+	CLD80211_SUB_ATTR_CH_BAND_CF_1 = 6,
+	CLD80211_SUB_ATTR_CH_BAND_CF_2 = 7,
+	CLD80211_SUB_ATTR_CH_INFO = 8,
+	CLD80211_SUB_ATTR_CH_REG_INFO_1 = 9,
+	CLD80211_SUB_ATTR_CH_REG_INFO_2 = 10,
+
+	/* keep last */
+	CLD80211_SUB_ATTR_CH_AFTER_LAST,
+	CLD80211_SUB_ATTR_CH_MAX =
+		CLD80211_SUB_ATTR_CH_AFTER_LAST - 1
+
+};
+
 #endif
 #endif /* _OS_IF_WIFI_POS_H_ */

+ 161 - 0
os_if/linux/wifi_pos/src/os_if_wifi_pos.c

@@ -62,6 +62,19 @@ cap_resp_sub_attr_len[CLD80211_SUB_ATTR_CAPS_MAX + 1] = {
 	[CLD80211_SUB_ATTR_CAPS_USER_DEFINED_CAPS] =
 				sizeof(struct wifi_pos_user_defined_caps),
 };
+
+static const uint32_t
+ch_resp_sub_attr_len[CLD80211_SUB_ATTR_CH_MAX + 1] = {
+	[CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_LIST] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_CHAN_ID] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_MHZ] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_BAND_CF_1] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_BAND_CF_2] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_INFO] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_REG_INFO_1] = sizeof(uint32_t),
+	[CLD80211_SUB_ATTR_CH_REG_INFO_2] = sizeof(uint32_t),
+};
 #endif
 
 static int map_wifi_pos_cmd_to_ani_msg_rsp(
@@ -216,6 +229,151 @@ static void os_if_send_cap_nl_resp(uint32_t pid, uint8_t *buf)
 	cld80211_oem_send_reply(msg, hdr, nest1, flags);
 }
 
+static void
+os_if_get_chan_nl_resp_len(uint32_t *chan_info, uint32_t *attr_headers)
+{
+	uint32_t i;
+	struct nlattr more_data;
+	struct nlattr attr_tag_data;
+	struct nlattr cld80211_subattr_ch_list;
+	struct nlattr chan_iter;
+
+	*attr_headers = NLA_ALIGN(sizeof(attr_tag_data));
+	*attr_headers += NLA_ALIGN(sizeof(more_data));
+	*attr_headers += nla_total_size(
+		ch_resp_sub_attr_len[CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN]);
+	*attr_headers += sizeof(cld80211_subattr_ch_list);
+
+	*chan_info = NLA_ALIGN(sizeof(chan_iter));
+	i = CLD80211_SUB_ATTR_CH_LIST;
+	for (; i <= CLD80211_SUB_ATTR_CH_MAX; i++)
+		*chan_info += nla_total_size(ch_resp_sub_attr_len[i]);
+}
+
+static uint8_t os_if_get_max_chan_nl_resp(uint8_t chan_num)
+{
+	struct nlattr vendor_data;
+	struct nlattr attr_cmd;
+	uint32_t chan_info = 0, attr_headers = 0;
+	uint32_t chan_info_msg_len, chan_allow = 0;
+
+	os_if_get_chan_nl_resp_len(&chan_info, &attr_headers);
+	attr_headers += NLA_ALIGN(sizeof(vendor_data));
+	attr_headers += NLA_ALIGN(sizeof(attr_cmd));
+
+	chan_info_msg_len = WLAN_CLD80211_MAX_SIZE;
+	chan_info_msg_len -= WIFIPOS_RESERVE_BYTES;
+	chan_info_msg_len -= attr_headers;
+
+	chan_allow = chan_info_msg_len / chan_info;
+
+	if (chan_num > chan_allow)
+		return chan_allow;
+	else
+		return chan_num;
+}
+
+static int
+os_if_create_ch_nl_resp(uint32_t pid, uint8_t *buf, uint16_t num_chan,
+			bool is_frag)
+{
+	void *hdr;
+	int i;
+	int flags = GFP_KERNEL;
+	struct sk_buff *msg = NULL;
+	struct nlattr *nest1, *nest2;
+	struct nlattr *nest3, *nest4;
+	struct wifi_pos_ch_info_rsp *channel_rsp;
+
+	channel_rsp = (struct wifi_pos_ch_info_rsp *)buf;
+
+	msg = cld80211_oem_rsp_alloc_skb(pid, &hdr, &nest1, &flags);
+	if (!msg) {
+		osif_err("alloc_skb failed");
+		return -EPERM;
+	}
+
+	nla_put_u32(msg, CLD80211_ATTR_CMD,
+		    CLD80211_VENDOR_SUB_CMD_GET_CH_INFO);
+
+	nest2 = nla_nest_start(msg, CLD80211_ATTR_CMD_TAG_DATA);
+	if (!nest2)
+		goto fail;
+
+	if (is_frag)
+		nla_put_flag(msg, CLD80211_SUB_ATTR_CH_MORE_DATA);
+
+	nla_put_u32(msg, CLD80211_SUB_ATTR_CHANNEL_NUM_CHAN, num_chan);
+
+	nest3 = nla_nest_start(msg, CLD80211_SUB_ATTR_CH_LIST);
+	if (!nest3)
+		goto fail;
+	for (i = 0; i < num_chan; i++) {
+		nest4 = nla_nest_start(msg, i);
+		if (!nest4)
+			goto fail;
+
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_CHAN_ID,
+			    channel_rsp->chan_id);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_MHZ, channel_rsp->mhz);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_1,
+			    channel_rsp->band_center_freq1);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_BAND_CF_2,
+			    channel_rsp->band_center_freq2);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_INFO, channel_rsp->info);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_1,
+			    channel_rsp->reg_info_1);
+		nla_put_u32(msg, CLD80211_SUB_ATTR_CH_REG_INFO_2,
+			    channel_rsp->reg_info_2);
+		nla_nest_end(msg, nest4);
+		channel_rsp++;
+	}
+
+	nla_nest_end(msg, nest3);
+	nla_nest_end(msg, nest2);
+
+	osif_debug("sending oem rsp: type: %d to pid (%d)",
+		   CLD80211_VENDOR_SUB_CMD_GET_CH_INFO, pid);
+
+	cld80211_oem_send_reply(msg, hdr, nest1, flags);
+	return 0;
+
+fail:
+	osif_err("failed to fill CHAN_RESP attributes");
+	dev_kfree_skb(msg);
+	return -EPERM;
+}
+
+static void os_if_send_chan_nl_resp(uint32_t pid, uint8_t *buf)
+{
+	int err;
+	uint8_t check_chans = 0;
+	uint8_t  *chnk_ptr, chan_allow = 0;
+	bool resp_frag = false;
+
+	check_chans = buf[0];
+	chnk_ptr = &buf[1];
+
+	do {
+		chan_allow = os_if_get_max_chan_nl_resp(check_chans);
+
+		if (check_chans > chan_allow)
+			resp_frag = true;
+		else
+			resp_frag = false;
+		check_chans -= chan_allow;
+
+		err = os_if_create_ch_nl_resp(pid, chnk_ptr,
+					      chan_allow, resp_frag);
+		if (err) {
+			osif_err("failed to alloc memory for ch_nl_resp");
+			return;
+		}
+		chnk_ptr += (sizeof(struct wifi_pos_ch_info_rsp) *
+				      chan_allow);
+	} while (resp_frag);
+}
+
 
 static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
 			       enum wifi_pos_cmd_ids cmd)
@@ -224,6 +382,9 @@ static void os_if_send_nl_resp(uint32_t pid, uint8_t *buf,
 	case WIFI_POS_CMD_GET_CAPS:
 		os_if_send_cap_nl_resp(pid, buf);
 		break;
+	case WIFI_POS_CMD_GET_CH_INFO:
+		os_if_send_chan_nl_resp(pid, buf);
+		break;
 	default:
 		osif_err("response message is invalid :%d", cmd);
 	}

+ 23 - 0
umac/wifi_pos/inc/wifi_pos_utils_pub.h

@@ -30,6 +30,7 @@
 #define OEM_TARGET_SIGNATURE_LEN   8
 #define OEM_TARGET_SIGNATURE       "QUALCOMM"
 
+#define MAX_CHANNELS               255
 #define OEM_CAP_MAX_NUM_CHANNELS   128
 
 #define WIFI_POS_RSP_V1_FLAT_MEMORY  0x00000001
@@ -74,6 +75,28 @@ struct qdf_packed wifi_pos_driver_version {
 	uint8_t build;
 };
 
+/**
+ * struct wifi_pos_channel_power
+ * @center_freq: Channel Center Frequency
+ * @chan_num: channel number
+ * @tx_power: TX power
+ */
+struct wifi_pos_channel_power {
+	uint32_t center_freq;
+	uint32_t chan_num;
+	uint32_t tx_power;
+};
+
+/**
+ * struct wifi_pos_channel_list
+ * @valid_channels: no of valid channels
+ * @chan_info: channel info
+ */
+struct qdf_packed wifi_pos_channel_list {
+	uint16_t num_channels;
+	struct wifi_pos_channel_power chan_info[MAX_CHANNELS];
+};
+
 /**
  * struct wifi_pos_driver_caps - OEM Data Capabilities
  * @oem_target_signature: Signature of chipset vendor

+ 109 - 80
umac/wifi_pos/src/wifi_pos_main.c

@@ -286,7 +286,7 @@ QDF_STATUS wifi_pos_send_report_resp(struct wlan_objmgr_psoc *psoc,
 
 static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc,
 					struct wlan_objmgr_pdev *pdev,
-					uint16_t chan,
+					uint16_t freq,
 					struct wifi_pos_ch_info_rsp *chan_info)
 {
 	struct ch_params ch_params = {0};
@@ -302,25 +302,21 @@ static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc,
 
 	/* Passing CH_WIDTH_MAX will give the max bandwidth supported */
 	ch_params.ch_width = CH_WIDTH_MAX;
-
-	wlan_reg_set_channel_params(pdev, chan, sec_ch_2g, &ch_params);
-	if (ch_params.center_freq_seg0)
-		chan_info->band_center_freq1 =
-			wlan_reg_legacy_chan_to_freq(
-						pdev,
-						ch_params.center_freq_seg0);
-
-	wifi_pos_psoc->wifi_pos_get_phy_mode(chan, ch_params.ch_width,
-					     &phy_mode);
-
+	wlan_reg_set_channel_params_for_freq(pdev, freq,
+					     sec_ch_2g, &ch_params);
+	chan_info->band_center_freq1 = ch_params.mhz_freq_seg0;
+	wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq(freq,
+						ch_params.ch_width,
+						&phy_mode);
 	REG_SET_CHANNEL_MODE(chan_info, phy_mode);
 }
 
 static void wifi_pos_get_reg_info(struct wlan_objmgr_pdev *pdev,
-				  uint32_t chan_num, uint32_t *reg_info_1,
+				  uint16_t freq, uint32_t *reg_info_1,
 				  uint32_t *reg_info_2)
 {
-	uint32_t reg_power = wlan_reg_get_channel_reg_power(pdev, chan_num);
+	uint32_t reg_power = wlan_reg_get_channel_reg_power_for_freq(pdev,
+								     freq);
 
 	*reg_info_1 = 0;
 	*reg_info_2 = 0;
@@ -351,20 +347,55 @@ static uint32_t wifi_pos_get_valid_channels(uint8_t *channels, uint32_t num_ch,
 	return num_valid_channels;
 }
 
+static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
+				   void *obj, void *arg)
+{
+	QDF_STATUS status;
+	uint8_t num_channels;
+	struct wlan_objmgr_pdev *pdev = obj;
+	struct wifi_pos_channel_list *chan_list = arg;
+	struct channel_power *ch_info = NULL;
+
+	if (!chan_list) {
+		wifi_pos_err("wifi_pos priv arg is null");
+		return;
+	}
+	ch_info = (struct channel_power *)chan_list->chan_info;
+	status = wlan_reg_get_channel_list_with_power(pdev, ch_info,
+						      &num_channels);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wifi_pos_err("Failed to get valid channel list");
+		return;
+	}
+	chan_list->num_channels = num_channels;
+}
+
+static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
+				 struct wifi_pos_channel_list *chan_list)
+{
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
+				     wifi_pos_pdev_iterator,
+				     chan_list, true, WLAN_WIFI_POS_CORE_ID);
+	wifi_pos_notice("num channels: %d", chan_list->num_channels);
+}
+
 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
 					struct wifi_pos_req_msg *req)
 {
-	uint8_t idx;
+	uint8_t idx, band_mask;
 	uint8_t *buf;
-	uint32_t len;
+	uint32_t len, i, freq;
 	uint32_t reg_info_1;
 	uint32_t reg_info_2;
+	bool oem_6g_support_disable;
 	uint8_t *channels = req->buf;
 	struct wlan_objmgr_pdev *pdev;
 	uint32_t num_ch = req->buf_len;
 	uint8_t valid_channel_list[NUM_CHANNELS];
-	uint32_t num_valid_channels;
+	uint32_t num_valid_channels = 0;
 	struct wifi_pos_ch_info_rsp *ch_info;
+	struct wifi_pos_channel_list *ch_list;
 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
 					wifi_pos_get_psoc_priv_obj(psoc);
 
@@ -386,38 +417,68 @@ static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
 		wifi_pos_err("Invalid number of channels");
 		return QDF_STATUS_E_INVAL;
 	}
-	num_valid_channels = wifi_pos_get_valid_channels(channels, num_ch,
+
+	ch_list = qdf_mem_malloc(sizeof(*ch_list));
+	if (!ch_list)
+		return QDF_STATUS_E_NOMEM;
+
+	if (num_ch == 0 && req->rsp_version == WIFI_POS_RSP_V2_NL) {
+		wifi_pos_get_ch_info(psoc, ch_list);
+		qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
+		oem_6g_support_disable = wifi_pos_obj->oem_6g_support_disable;
+		qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
+
+		/* ch_list has the frequencies in order of 2.4g, 5g & 6g */
+		for (i = 0; i < ch_list->num_channels; i++) {
+			freq = ch_list->chan_info[i].center_freq;
+			if (oem_6g_support_disable &&
+			    WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
+				continue;
+			num_valid_channels++;
+		}
+	} else {
+		/* v1 has ch_list with frequencies in order of 2.4g, 5g only */
+		num_valid_channels = wifi_pos_get_valid_channels(
+							channels, num_ch,
 							 valid_channel_list);
+		band_mask = BIT(REG_BAND_5G) | BIT(REG_BAND_2G);
+		for (i = 0; i < num_valid_channels; i++) {
+			ch_list->chan_info[i].chan_num = valid_channel_list[i];
+			ch_list->chan_info[i].center_freq =
+				wlan_reg_chan_band_to_freq(
+						pdev,
+						ch_list->chan_info[i].chan_num,
+						band_mask);
+		}
+	}
 
 	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) *
 			num_valid_channels;
 	buf = qdf_mem_malloc(len);
 	if (!buf) {
 		wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
+		qdf_mem_free(ch_list);
 		return QDF_STATUS_E_NOMEM;
 	}
 
-	qdf_mem_zero(buf, len);
-
 	/* First byte of message body will have num of channels */
 	buf[0] = num_valid_channels;
 	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
 	for (idx = 0; idx < num_valid_channels; idx++) {
-		ch_info[idx].chan_id = valid_channel_list[idx];
-		wifi_pos_get_reg_info(pdev, ch_info[idx].chan_id,
-				      &reg_info_1, &reg_info_2);
 		ch_info[idx].reserved0 = 0;
-		ch_info[idx].mhz = wlan_reg_get_channel_freq(
-						pdev,
-						valid_channel_list[idx]);
+		ch_info[idx].chan_id = ch_list->chan_info[idx].chan_num;
+		ch_info[idx].mhz = ch_list->chan_info[idx].center_freq;
 		ch_info[idx].band_center_freq1 = ch_info[idx].mhz;
 		ch_info[idx].band_center_freq2 = 0;
 		ch_info[idx].info = 0;
+		wifi_pos_get_reg_info(pdev, ch_info[idx].mhz,
+				      &reg_info_1, &reg_info_2);
+
 		if (wlan_reg_is_dfs_for_freq(pdev, ch_info[idx].mhz))
 			WIFI_POS_SET_DFS(ch_info[idx].info);
 
 		wifi_update_channel_bw_info(psoc, pdev,
-					    ch_info[idx].chan_id,
+					    ch_info[idx].mhz,
 					    &ch_info[idx]);
 
 		ch_info[idx].reg_info_1 = reg_info_1;
@@ -425,9 +486,11 @@ static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
 	}
 
 	wifi_pos_obj->wifi_pos_send_rsp(wifi_pos_obj->app_pid,
-					ANI_MSG_CHANNEL_INFO_RSP,
+					WIFI_POS_CMD_GET_CH_INFO,
 					len, buf);
+
 	qdf_mem_free(buf);
+	qdf_mem_free(ch_list);
 	wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
 
 	return QDF_STATUS_SUCCESS;
@@ -759,62 +822,14 @@ void wifi_pos_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
 	wifi_pos_rx_ops->oem_rsp_event_rx = wifi_pos_oem_rsp_handler;
 }
 
-static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
-				   void *obj, void *arg)
-{
-	QDF_STATUS status;
-	uint8_t i, num_channels, size, valid_ch = 0;
-	struct wlan_objmgr_pdev *pdev = obj;
-	struct wifi_pos_driver_caps *caps = arg;
-	struct channel_power *ch_list;
-	bool oem_6g_support_disable;
-	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
-					wifi_pos_get_psoc_priv_obj(psoc);
-
-	size = QDF_MAX(OEM_CAP_MAX_NUM_CHANNELS, NUM_CHANNELS);
-	ch_list = qdf_mem_malloc(size * sizeof(*ch_list));
-	if (!ch_list)
-		return;
-
-	status = wlan_reg_get_channel_list_with_power(pdev, ch_list,
-						      &num_channels);
-
-	if (QDF_IS_STATUS_ERROR(status)) {
-		wifi_pos_err("Failed to get valid channel list");
-		qdf_mem_free(ch_list);
-		return;
-	}
-	if (num_channels > OEM_CAP_MAX_NUM_CHANNELS)
-		num_channels = OEM_CAP_MAX_NUM_CHANNELS;
-
-	qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
-	oem_6g_support_disable = wifi_pos_obj->oem_6g_support_disable;
-	qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
-
-	for (i = 0; i < num_channels; i++) {
-		if (oem_6g_support_disable &&
-		    WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_list[i].center_freq))
-			continue;
-		caps->channel_list[valid_ch++] = ch_list[i].chan_num;
-	}
-	caps->num_channels = valid_ch;
-	qdf_mem_free(ch_list);
-}
-
-static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
-				 struct wifi_pos_driver_caps *caps)
-{
-	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
-				     wifi_pos_pdev_iterator,
-				      caps, true, WLAN_WIFI_POS_CORE_ID);
-	wifi_pos_err("num channels: %d", caps->num_channels);
-}
-
 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
 			   struct wifi_pos_driver_caps *caps)
 {
+	uint16_t i, count = 0;
+	uint32_t freq;
 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
 					wifi_pos_get_psoc_priv_obj(psoc);
+	struct wifi_pos_channel_list *ch_list = NULL;
 
 	wifi_pos_debug("Enter");
 	if (!wifi_pos_obj) {
@@ -822,6 +837,10 @@ QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
 		return QDF_STATUS_E_NULL_VALUE;
 	}
 
+	ch_list = qdf_mem_malloc(sizeof(*ch_list));
+	if (!ch_list)
+		return QDF_STATUS_E_NOMEM;
+
 	strlcpy(caps->oem_target_signature,
 		OEM_TARGET_SIGNATURE,
 		OEM_TARGET_SIGNATURE_LEN);
@@ -836,6 +855,16 @@ QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
 	caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min;
 	caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max;
 	caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc);
-	wifi_pos_get_ch_info(psoc, caps);
+	wifi_pos_get_ch_info(psoc, ch_list);
+
+	/* copy valid channels list to caps */
+	for (i = 0; i < ch_list->num_channels; i++) {
+		freq = ch_list->chan_info[i].center_freq;
+		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
+			continue;
+		caps->channel_list[count++] = ch_list->chan_info[i].chan_num;
+	}
+	caps->num_channels = count;
+	qdf_mem_free(ch_list);
 	return QDF_STATUS_SUCCESS;
 }