浏览代码

qcacmn: Populate pdev secondary_cur_chan_list for mobile device SAP

secondary_cur_chan_list channel list is for mobile device SAP, which
by default cannot enable on LPI channels, and cannot enable on SP
channel until AFC server response received.

Populate 6 GHz channels to secondary_cur_chan_list based on 6 GHz
regulatory rules of current country, LPI channel will not be added
in because it is not allowed for mobile SAP. And update 6 GHz SP
channel attributions if received AFC response.

Also add APIs to populate power attributions of secondary_cur_chan_list
and decide proper 6 GHz power attributions if 6 GHz channel frequency
and bandwidth being selected.

Change-Id: I6aa0228f18f7e31fc3cdd63a98483d02afb0579a
CRs-Fixed: 3204156
Will Huang 3 年之前
父节点
当前提交
ed050b6f1a

+ 241 - 56
umac/regulatory/core/src/reg_build_chan_list.c

@@ -42,6 +42,38 @@
 #define MAX_PWR_FCC_CHAN_13 2
 #define CHAN_144_CENT_FREQ 5720
 
+/**
+ * reg_init_chan() - Initialize the channel list from the channel_map global
+ *	list
+ * @dst_list: list to initialize
+ * @beg_enum: starting point in list(inclusive)
+ * @end_enum: ending point in list(inclusive)
+ * @dst_idx_adj: offset between channel_map and dst_list
+ * @soc_reg: soc private object for regulatory
+ *
+ * Return: none
+ */
+static void reg_init_chan(struct regulatory_channel *dst_list,
+			  enum channel_enum beg_enum,
+			  enum channel_enum end_enum, uint8_t dst_idx_adj,
+			  struct wlan_regulatory_psoc_priv_obj *soc_reg)
+{
+	enum channel_enum chan_enum;
+	uint8_t dst_idx;
+
+	for (chan_enum = beg_enum; chan_enum <= end_enum; chan_enum++) {
+		dst_idx = chan_enum - dst_idx_adj;
+
+		dst_list[dst_idx].chan_num = channel_map[chan_enum].chan_num;
+		dst_list[dst_idx].center_freq =
+					channel_map[chan_enum].center_freq;
+		dst_list[dst_idx].chan_flags = REGULATORY_CHAN_DISABLED;
+		dst_list[dst_idx].state = CHANNEL_STATE_DISABLE;
+		if (!soc_reg->retain_nol_across_regdmn_update)
+			dst_list[dst_idx].nol_chan = false;
+	}
+}
+
 static inline bool
 reg_nol_and_history_not_set(struct regulatory_channel *chan)
 {
@@ -63,12 +95,33 @@ static void reg_fill_psd_info(enum channel_enum chan_enum,
 
 	master_list[chan_enum].psd_eirp = reg_rule->psd_eirp;
 }
+
+/**
+ * reg_init_6ghz_master_chan() - Init 6 GHz channel list
+ * @dst_list: pointer to 6 GHz channel list
+ * @soc_reg: pointer to regulatory psoc private object.
+ *
+ * Return: None
+ */
+static void
+reg_init_6ghz_master_chan(struct regulatory_channel *dst_list,
+			  struct wlan_regulatory_psoc_priv_obj *soc_reg)
+{
+	reg_init_chan(dst_list, MIN_6GHZ_CHANNEL, MAX_6GHZ_CHANNEL,
+		      MIN_6GHZ_CHANNEL, soc_reg);
+}
 #else
 static inline void reg_fill_psd_info(enum channel_enum chan_enum,
 				     struct cur_reg_rule *reg_rule,
 				     struct regulatory_channel *master_list)
 {
 }
+
+static inline void
+reg_init_6ghz_master_chan(struct regulatory_channel *dst_list,
+			  struct wlan_regulatory_psoc_priv_obj *soc_reg)
+{
+}
 #endif
 
 /**
@@ -1527,12 +1580,120 @@ reg_append_mas_chan_list_for_6g(struct wlan_regulatory_pdev_priv_obj
 	}
 }
 
+/**
+ * reg_dump_valid_6ghz_channel_list() - Function to print valid 6 GHz channel
+ * list state and attribute.
+ * @chan: Pointer to array of 6 GHz channel list
+ *
+ * Return: None
+ */
+static void
+reg_dump_valid_6ghz_channel_list(struct regulatory_channel *chan)
+{
+#define MAX_CHAN_LOG_ONE_LINE 18
+	uint32_t buf_size = MAX_CHAN_LOG_ONE_LINE * 24 + 1;
+	uint8_t *buf;
+	uint32_t i, len = 0, count = 0;
+
+	buf = qdf_mem_malloc(buf_size);
+	if (!buf)
+		return;
+
+	for (i = MIN_6GHZ_CHANNEL; i <= MAX_6GHZ_CHANNEL; i++, chan++) {
+		if (chan->state == CHANNEL_STATE_DISABLE)
+			continue;
+		len += qdf_scnprintf(buf + len, buf_size - len,
+				    "%d:%d:%d:%d:%d:%x ",
+				    chan->center_freq, chan->state,
+				    chan->psd_flag, chan->tx_power,
+				    (int16_t)chan->psd_eirp,
+				    chan->chan_flags);
+		count++;
+		if (count >= MAX_CHAN_LOG_ONE_LINE) {
+			reg_nofl_debug("%s", buf);
+			count = 0;
+			len = 0;
+		}
+	}
+
+	if (len)
+		reg_nofl_debug("%s", buf);
+
+	qdf_mem_free(buf);
+}
+
+/**
+ * reg_dump_valid_6ghz_cur_chan_list() - API to dump pdev current/secondary
+ * channel list state
+ * @pdev_priv_obj: pointer to pdev private object
+ *
+ * Return: None
+ */
+static void
+reg_dump_valid_6ghz_cur_chan_list(struct wlan_regulatory_pdev_priv_obj
+				  *pdev_priv_obj)
+{
+	reg_debug("sta freq:state:ispsd:pwr:psd:flags(hex):");
+	reg_dump_valid_6ghz_channel_list(
+			&pdev_priv_obj->cur_chan_list[MIN_6GHZ_CHANNEL]);
+	reg_debug("sap freq:state:ispsd:pwr:psd:flags(hex):");
+	reg_dump_valid_6ghz_channel_list(
+		&pdev_priv_obj->secondary_cur_chan_list[MIN_6GHZ_CHANNEL]);
+}
+
+#ifdef CONFIG_AFC_SUPPORT
+/**
+ * reg_populate_afc_secondary_cur_chan_list() - Function to populate AFC
+ * channel list to secondary current channel list
+ * @pdev_priv_obj: Pointer to pdev regulatory private object
+ * @chan_list: Pointer to array of 6 GHz channel list
+ *
+ * Return: None
+ */
+static void reg_populate_afc_secondary_cur_chan_list(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+			struct regulatory_channel *chan_list)
+{
+	uint32_t i;
+	struct regulatory_channel *afc_chan_list;
+	struct regulatory_channel *sp_chan_list;
+
+	if (!pdev_priv_obj->is_6g_afc_power_event_received)
+		return;
+
+	afc_chan_list = pdev_priv_obj->afc_chan_list;
+	sp_chan_list = pdev_priv_obj->
+			mas_chan_list_6g_ap[REG_STANDARD_POWER_AP];
+	for (i = 0; i < NUM_6GHZ_CHANNELS; i++) {
+		if (afc_chan_list[i].state == CHANNEL_STATE_DISABLE &&
+		    sp_chan_list[i].state == CHANNEL_STATE_ENABLE) {
+			chan_list[i].state = CHANNEL_STATE_DISABLE;
+			chan_list[i].chan_flags |= REGULATORY_CHAN_DISABLED;
+		} else if (afc_chan_list[i].state == CHANNEL_STATE_ENABLE) {
+			qdf_mem_copy(&chan_list[i],
+				     &afc_chan_list[i],
+				     sizeof(chan_list[i]));
+			chan_list[i].chan_flags |= REGULATORY_CHAN_AFC;
+		}
+	}
+}
+#else
+static inline void reg_populate_afc_secondary_cur_chan_list(
+			struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+			struct regulatory_channel *chan_list)
+{
+}
+#endif
+
 static void
 reg_populate_secondary_cur_chan_list(struct wlan_regulatory_pdev_priv_obj
 				     *pdev_priv_obj)
 {
 	struct wlan_objmgr_psoc *psoc;
 	struct wlan_lmac_if_reg_tx_ops *reg_tx_ops;
+	struct wlan_regulatory_psoc_priv_obj *soc_reg;
+	struct regulatory_channel *chan_list;
+	uint32_t len_6ghz;
 
 	psoc = wlan_pdev_get_psoc(pdev_priv_obj->pdev_ptr);
 	if (!psoc) {
@@ -1540,29 +1701,59 @@ reg_populate_secondary_cur_chan_list(struct wlan_regulatory_pdev_priv_obj
 		return;
 	}
 
+	soc_reg = reg_get_psoc_obj(psoc);
+	if (!IS_VALID_PSOC_REG_OBJ(soc_reg)) {
+		reg_err("psoc reg component is NULL");
+		return;
+	}
+
 	reg_tx_ops = reg_get_psoc_tx_ops(psoc);
 	if (!reg_tx_ops) {
 		reg_err("reg_tx_ops null");
 		return;
 	}
-	if (reg_tx_ops->register_master_ext_handler &&
-	    wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_EXT_EVENT_SUPPORTED)) {
-		qdf_mem_copy(pdev_priv_obj->secondary_cur_chan_list,
-			     pdev_priv_obj->cur_chan_list,
-			     (NUM_CHANNELS - NUM_6GHZ_CHANNELS) *
-			     sizeof(struct regulatory_channel));
 
-		qdf_mem_copy(&pdev_priv_obj->
-		     secondary_cur_chan_list[MIN_6GHZ_CHANNEL],
-		     pdev_priv_obj->mas_chan_list_6g_ap
-		     [pdev_priv_obj->reg_cur_6g_ap_pwr_type],
-		     NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel));
-	} else {
+	if (!reg_tx_ops->register_master_ext_handler ||
+	    !wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_EXT_EVENT_SUPPORTED)) {
 		qdf_mem_copy(pdev_priv_obj->secondary_cur_chan_list,
 			     pdev_priv_obj->cur_chan_list,
 			     (NUM_CHANNELS) *
 			     sizeof(struct regulatory_channel));
+		return;
+	}
+
+	len_6ghz = NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel);
+	chan_list = qdf_mem_malloc(len_6ghz);
+	if (!chan_list)
+		return;
+
+	if (pdev_priv_obj->indoor_chan_enabled &&
+	    pdev_priv_obj->reg_rules.num_of_6g_ap_reg_rules[REG_INDOOR_AP]) {
+		qdf_mem_copy(chan_list,
+			     pdev_priv_obj->mas_chan_list_6g_ap[REG_INDOOR_AP],
+			     len_6ghz);
+		/* has flag REGULATORY_CHAN_INDOOR_ONLY */
+	} else if (pdev_priv_obj->reg_rules.num_of_6g_ap_reg_rules
+		   [REG_VERY_LOW_POWER_AP]) {
+		qdf_mem_copy(chan_list,
+			     pdev_priv_obj->mas_chan_list_6g_ap
+			     [REG_VERY_LOW_POWER_AP],
+			     len_6ghz);
+	} else {
+		reg_init_6ghz_master_chan(chan_list, soc_reg);
 	}
+
+	reg_populate_afc_secondary_cur_chan_list(pdev_priv_obj, chan_list);
+
+	qdf_mem_copy(pdev_priv_obj->secondary_cur_chan_list,
+		     pdev_priv_obj->cur_chan_list,
+		     (NUM_CHANNELS - NUM_6GHZ_CHANNELS) *
+		     sizeof(struct regulatory_channel));
+	qdf_mem_copy(&pdev_priv_obj->secondary_cur_chan_list[MIN_6GHZ_CHANNEL],
+		     chan_list,
+		     len_6ghz);
+	qdf_mem_free(chan_list);
+	reg_dump_valid_6ghz_cur_chan_list(pdev_priv_obj);
 }
 #else /* CONFIG_REG_CLIENT */
 
@@ -3267,38 +3458,6 @@ reg_soc_vars_reset_on_failure(enum cc_setting_code status_code,
 	return QDF_STATUS_SUCCESS;
 }
 
-/**
- * reg_init_chan() - Initialize the channel list from the channel_map global
- *	list
- * @dst_list: list to initialize
- * @beg_enum: starting point in list(inclusive)
- * @end_enum: ending point in list(inclusive)
- * @dst_idx_adj: offset between channel_map and dst_list
- * @soc_reg: soc private object for regulatory
- *
- * Return: none
- */
-static void reg_init_chan(struct regulatory_channel *dst_list,
-			  enum channel_enum beg_enum,
-			  enum channel_enum end_enum, uint8_t dst_idx_adj,
-			  struct wlan_regulatory_psoc_priv_obj *soc_reg)
-{
-	enum channel_enum chan_enum;
-	uint8_t dst_idx;
-
-	for (chan_enum = beg_enum; chan_enum <= end_enum; chan_enum++) {
-		dst_idx = chan_enum - dst_idx_adj;
-
-		dst_list[dst_idx].chan_num = channel_map[chan_enum].chan_num;
-		dst_list[dst_idx].center_freq =
-					channel_map[chan_enum].center_freq;
-		dst_list[dst_idx].chan_flags = REGULATORY_CHAN_DISABLED;
-		dst_list[dst_idx].state = CHANNEL_STATE_DISABLE;
-		if (!soc_reg->retain_nol_across_regdmn_update)
-			dst_list[dst_idx].nol_chan = false;
-	}
-}
-
 static void reg_init_legacy_master_chan(struct regulatory_channel *dst_list,
 				struct wlan_regulatory_psoc_priv_obj *soc_reg)
 {
@@ -3346,13 +3505,6 @@ static void reg_init_2g_5g_master_chan(struct regulatory_channel *dst_list,
 	reg_init_chan(dst_list, 0, MAX_5GHZ_CHANNEL, 0, soc_reg);
 }
 
-static void reg_init_6g_master_chan(struct regulatory_channel *dst_list,
-				struct wlan_regulatory_psoc_priv_obj *soc_reg)
-{
-	reg_init_chan(dst_list, MIN_6GHZ_CHANNEL, MAX_6GHZ_CHANNEL,
-		      MIN_6GHZ_CHANNEL, soc_reg);
-}
-
 /**
  * reg_store_regulatory_ext_info_to_socpriv() - Copy ext info from regulatory
  *	to regulatory PSOC private obj
@@ -3875,10 +4027,10 @@ QDF_STATUS reg_process_master_chan_list_ext(
 	reg_init_2g_5g_master_chan(mas_chan_list_2g_5g, soc_reg);
 
 	for (i = 0; i < REG_CURRENT_MAX_AP_TYPE; i++) {
-		reg_init_6g_master_chan(mas_chan_list_6g_ap[i], soc_reg);
+		reg_init_6ghz_master_chan(mas_chan_list_6g_ap[i], soc_reg);
 		for (j = 0; j < REG_MAX_CLIENT_TYPE; j++)
-			reg_init_6g_master_chan(mas_chan_list_6g_client[i][j],
-						soc_reg);
+			reg_init_6ghz_master_chan(mas_chan_list_6g_client[i][j],
+						  soc_reg);
 	}
 
 	reg_store_regulatory_ext_info_to_socpriv(soc_reg, regulat_info, phy_id);
@@ -4038,6 +4190,37 @@ reg_disable_sp_channels_in_super_chan_list(
 	}
 }
 
+#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_REG_CLIENT)
+/**
+ * reg_client_afc_populate_channels() - Function to populate channels and
+ * invoke callbacks to notify the channel list change.
+ * @psoc: Pointer to PSOC object
+ * @pdev: Pointer to PDEV object
+ *
+ * Return: None
+ */
+static void
+reg_client_afc_populate_channels(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_pdev *pdev)
+{
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_alert("pdev reg component is NULL");
+		return;
+	}
+	reg_compute_pdev_current_chan_list(pdev_priv_obj);
+	reg_send_scheduler_msg_nb(psoc, pdev);
+}
+#else
+static inline void
+reg_client_afc_populate_channels(struct wlan_objmgr_psoc *psoc,
+				 struct wlan_objmgr_pdev *pdev)
+{
+}
+#endif
+
 /**
  * reg_process_afc_expiry_event() - Process the afc expiry event and get the
  * afc request id
@@ -4108,6 +4291,7 @@ reg_process_afc_expiry_event(struct afc_regulatory_info *afc_info)
 		pdev_priv_obj->is_6g_afc_power_event_received = false;
 		reg_disable_afc_mas_chan_list_channels(pdev_priv_obj);
 		reg_disable_sp_channels_in_super_chan_list(pdev_priv_obj);
+		reg_client_afc_populate_channels(psoc, pdev);
 		if (tx_ops->trigger_acs_for_afc)
 			tx_ops->trigger_acs_for_afc(pdev);
 		break;
@@ -4564,7 +4748,7 @@ reg_process_afc_power_event(struct afc_regulatory_info *afc_info)
 	afc_mas_chan_list = this_mchan_params->mas_chan_list_6g_afc;
 	qdf_mem_zero(afc_mas_chan_list,
 		     NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel));
-	reg_init_6g_master_chan(afc_mas_chan_list, soc_reg);
+	reg_init_6ghz_master_chan(afc_mas_chan_list, soc_reg);
 	soc_reg->mas_chan_params[phy_id].is_6g_afc_power_event_received = true;
 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbg_id);
 
@@ -4582,7 +4766,7 @@ reg_process_afc_power_event(struct afc_regulatory_info *afc_info)
 	}
 
 	reg_init_pdev_super_chan_list(pdev_priv_obj);
-	reg_init_6g_master_chan(pdev_priv_obj->afc_chan_list, soc_reg);
+	reg_init_6ghz_master_chan(pdev_priv_obj->afc_chan_list, soc_reg);
 	/* Free the old power_info event if it was allocated */
 	if (pdev_priv_obj->power_info)
 		reg_free_afc_pwr_info(pdev_priv_obj);
@@ -4607,6 +4791,7 @@ reg_process_afc_power_event(struct afc_regulatory_info *afc_info)
 
 	reg_modify_6g_afc_chan_list(pdev_priv_obj);
 	reg_compute_super_chan_list(pdev_priv_obj);
+	reg_client_afc_populate_channels(psoc, pdev);
 
 	if (tx_ops->trigger_acs_for_afc &&
 	    !wlan_reg_is_noaction_on_afc_pwr_evt(pdev) &&

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

@@ -4347,6 +4347,167 @@ static uint32_t reg_get_channel_flags_from_secondary_list_for_freq(
 
 	return pdev_priv_obj->secondary_cur_chan_list[chan_enum].chan_flags;
 }
+
+#ifdef CONFIG_BAND_6GHZ
+/**
+ * reg_get_psd_power() - Function to get PSD power for 6 GHz channel
+ * @chan: Pointer to channel object
+ * @is_psd: Pointer to whether it is PSD power
+ *
+ * Return: Channel PSD power value if it is PSD type.
+ */
+static uint16_t reg_get_psd_power(struct regulatory_channel *chan, bool *is_psd)
+{
+	if (is_psd)
+		*is_psd = chan->psd_flag;
+	return chan->psd_eirp;
+}
+#else
+static uint16_t reg_get_psd_power(struct regulatory_channel *chan, bool *is_psd)
+{
+	if (is_psd)
+		*is_psd = false;
+	return 0;
+}
+#endif
+
+QDF_STATUS
+reg_get_channel_power_attr_from_secondary_list_for_freq(
+		struct wlan_objmgr_pdev *pdev,
+		qdf_freq_t freq, bool *is_psd,
+		uint16_t *tx_power, uint16_t *psd_eirp, uint32_t *flags)
+{
+	enum channel_enum chan_enum;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+	struct regulatory_channel *chan;
+
+	if (!is_psd && !tx_power && !psd_eirp && !flags) {
+		reg_err("all pointers null");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!pdev_priv_obj) {
+		reg_err("pdev priv obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	chan_enum = reg_get_chan_enum_for_freq(freq);
+	if (chan_enum == INVALID_CHANNEL) {
+		reg_err_rl("chan freq %u is not valid", freq);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	chan = &pdev_priv_obj->secondary_cur_chan_list[chan_enum];
+
+	if (chan->state == CHANNEL_STATE_DISABLE ||
+	    chan->state == CHANNEL_STATE_INVALID) {
+		reg_err_rl("invalid channel state %d", chan->state);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (tx_power)
+		*tx_power = chan->tx_power;
+	if (psd_eirp)
+		*psd_eirp = reg_get_psd_power(chan, is_psd);
+	if (flags)
+		*flags = chan->chan_flags;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef CONFIG_BAND_6GHZ
+QDF_STATUS
+reg_decide_6ghz_power_within_bw_for_freq(struct wlan_objmgr_pdev *pdev,
+					 qdf_freq_t freq, enum phy_ch_width bw,
+					 bool *is_psd, uint16_t *min_tx_power,
+					 int16_t *min_psd_eirp,
+					 enum reg_6g_ap_type *power_type)
+{
+	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
+	enum channel_state state;
+	qdf_freq_t start_freq;
+	uint16_t tx_power, psd_eirp;
+	uint32_t chan_flags, min_chan_flags = 0;
+	bool first_time = true;
+
+	if (!reg_is_6ghz_chan_freq(freq))
+		return QDF_STATUS_E_INVAL;
+
+	if (!is_psd) {
+		reg_err("is_psd pointer null");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (!min_tx_power) {
+		reg_err("min_tx_power pointer null");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (!min_psd_eirp) {
+		reg_err("min_psd_eirp pointer null");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (!power_type) {
+		reg_err("power_type pointer null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	state = reg_get_5g_bonded_channel_for_freq(pdev,
+						   freq,
+						   bw,
+						   &bonded_chan_ptr);
+	if (state != CHANNEL_STATE_ENABLE &&
+	    state != CHANNEL_STATE_DFS) {
+		reg_err("invalid channel state %d", state);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (bw <= CH_WIDTH_20MHZ) {
+		if (reg_get_channel_power_attr_from_secondary_list_for_freq(
+			pdev, freq, is_psd, &tx_power,
+			&psd_eirp, &chan_flags) != QDF_STATUS_SUCCESS)
+			return QDF_STATUS_E_INVAL;
+		*min_psd_eirp = (int16_t)psd_eirp;
+		*min_tx_power = tx_power;
+		min_chan_flags = chan_flags;
+		goto decide_power_type;
+	}
+
+	start_freq = bonded_chan_ptr->start_freq;
+	while (start_freq <= bonded_chan_ptr->end_freq) {
+		if (reg_get_channel_power_attr_from_secondary_list_for_freq(
+			pdev, start_freq, is_psd, &tx_power,
+			&psd_eirp, &chan_flags) != QDF_STATUS_SUCCESS)
+			return QDF_STATUS_E_INVAL;
+
+		if (first_time) {
+			*min_psd_eirp = (int16_t)psd_eirp;
+			*min_tx_power = tx_power;
+			min_chan_flags = chan_flags;
+			first_time = false;
+		}
+		if ((int16_t)psd_eirp < *min_psd_eirp)
+			*min_psd_eirp = (int16_t)psd_eirp;
+		if (tx_power < *min_tx_power)
+			*min_tx_power = tx_power;
+		min_chan_flags |= (chan_flags & REGULATORY_CHAN_AFC);
+		min_chan_flags |= (chan_flags & REGULATORY_CHAN_INDOOR_ONLY);
+		start_freq += 20;
+	}
+
+decide_power_type:
+	if ((min_chan_flags & REGULATORY_CHAN_AFC) &&
+	    (min_chan_flags & REGULATORY_CHAN_INDOOR_ONLY))
+		*power_type = REG_INDOOR_AP;
+	else if (min_chan_flags & REGULATORY_CHAN_AFC)
+		*power_type = REG_STANDARD_POWER_AP;
+	else if (min_chan_flags & REGULATORY_CHAN_INDOOR_ONLY)
+		*power_type = REG_INDOOR_AP;
+	else
+		*power_type = REG_VERY_LOW_POWER_AP;
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #endif
 
 /**

+ 51 - 0
umac/regulatory/core/src/reg_services_common.h

@@ -1293,6 +1293,57 @@ bool reg_is_dfs_for_freq(struct wlan_objmgr_pdev *pdev, qdf_freq_t freq);
  */
 bool reg_is_dfs_in_secondary_list_for_freq(struct wlan_objmgr_pdev *pdev,
 					   qdf_freq_t freq);
+
+/**
+ * reg_get_channel_power_attr_from_secondary_list_for_freq() - get channel
+ * power attributions from secondary channel list.
+ * @pdev: pdev pointer
+ * @freq: channel frequency
+ * @is_psd: pointer to retrieve value whether channel power is psd
+ * @tx_power: pointer to retrieve value of channel eirp tx power
+ * @psd_eirp: pointer to retrieve value of channel psd eirp power
+ * @flags: pointer to retrieve value of channel flags
+ *
+ * Return: QDF STATUS
+ */
+QDF_STATUS
+reg_get_channel_power_attr_from_secondary_list_for_freq(
+			struct wlan_objmgr_pdev *pdev,
+			qdf_freq_t freq, bool *is_psd,
+			uint16_t *tx_power, uint16_t *psd_eirp,
+			uint32_t *flags);
+
+#ifdef CONFIG_BAND_6GHZ
+/**
+ * reg_decide_6ghz_power_within_bw_for_freq() - decide tx power and 6 GHz power
+ * type given channel frequency and bandwidth.
+ * @pdev: pdev pointer
+ * @freq: channel frequency
+ * @bw: channel bandwidth
+ * @is_psd: pointer to retrieve value whether channel power is psd
+ * @min_tx_power: pointer to retrieve value of minimum eirp tx power in bw
+ * @min_psd_eirp: pointer to retrieve value of minimum psd eirp power in bw
+ * @power_type: pointer to retrieve value of 6 GHz power type
+ *
+ * Return: QDF STATUS
+ */
+QDF_STATUS
+reg_decide_6ghz_power_within_bw_for_freq(struct wlan_objmgr_pdev *pdev,
+					 qdf_freq_t freq, enum phy_ch_width bw,
+					 bool *is_psd, uint16_t *min_tx_power,
+					 int16_t *min_psd_eirp,
+					 enum reg_6g_ap_type *power_type);
+#else
+static inline QDF_STATUS
+reg_decide_6ghz_power_within_bw_for_freq(struct wlan_objmgr_pdev *pdev,
+					 qdf_freq_t freq, enum phy_ch_width bw,
+					 bool *is_psd, uint16_t *min_tx_power,
+					 int16_t *min_psd_eirp,
+					 enum reg_6g_ap_type *power_type)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
 #endif
 
 /**

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

@@ -1832,6 +1832,46 @@ bool wlan_reg_is_enable_in_secondary_list_for_freq(
  */
 bool wlan_reg_is_dfs_in_secondary_list_for_freq(struct wlan_objmgr_pdev *pdev,
 						qdf_freq_t freq);
+
+/**
+ * wlan_reg_get_chan_pwr_attr_from_secondary_list_for_freq() - get channel
+ * power attributions from secondary channel list
+ * @pdev: pdev ptr
+ * @freq: channel center frequency
+ * @is_psd: pointer to retrieve value whether channel power is psd
+ * @tx_power: pointer to retrieve value of channel eirp tx power
+ * @psd_eirp: pointer to retrieve value of channel psd eirp power
+ * @flags: pointer to retrieve value of channel flags
+ *
+ * Return: QDF STATUS
+ */
+QDF_STATUS
+wlan_reg_get_chan_pwr_attr_from_secondary_list_for_freq(
+				struct wlan_objmgr_pdev *pdev, qdf_freq_t freq,
+				bool *is_psd, uint16_t *tx_power,
+				uint16_t *psd_eirp, uint32_t *flags);
+
+/**
+ * wlan_reg_decide_6ghz_power_within_bw_for_freq() - decide minimum tx power in
+ * bandwidth and 6 GHz power type
+ * @pdev: pdev ptr
+ * @freq: channel center frequency
+ * @bw: channel bandwidth
+ * @is_psd: pointer to retrieve value whether channel power is psd
+ * @min_tx_power: pointer to retrieve minimum tx power in bandwidth
+ * @min_psd_eirp: pointer to retrieve minimum psd eirp in bandwidth
+ * @power_type: pointer to retrieve 6 GHz power type
+ *
+ * Return: QDF STATUS
+ */
+QDF_STATUS
+wlan_reg_decide_6ghz_power_within_bw_for_freq(struct wlan_objmgr_pdev *pdev,
+					      qdf_freq_t freq,
+					      enum phy_ch_width bw,
+					      bool *is_psd,
+					      uint16_t *min_tx_power,
+					      int16_t *min_psd_eirp,
+					      enum reg_6g_ap_type *power_type);
 #endif
 
 /**

+ 28 - 0
umac/regulatory/dispatcher/src/wlan_reg_services_api.c

@@ -1151,6 +1151,34 @@ bool wlan_reg_is_dfs_in_secondary_list_for_freq(struct wlan_objmgr_pdev *pdev,
 {
 	return reg_is_dfs_in_secondary_list_for_freq(pdev, freq);
 }
+
+QDF_STATUS
+wlan_reg_get_chan_pwr_attr_from_secondary_list_for_freq(
+				struct wlan_objmgr_pdev *pdev, qdf_freq_t freq,
+				bool *is_psd, uint16_t *tx_power,
+				uint16_t *psd_eirp, uint32_t *flags)
+{
+	return reg_get_channel_power_attr_from_secondary_list_for_freq(
+			pdev, freq, is_psd, tx_power, psd_eirp, flags);
+}
+
+QDF_STATUS
+wlan_reg_decide_6ghz_power_within_bw_for_freq(struct wlan_objmgr_pdev *pdev,
+					      qdf_freq_t freq,
+					      enum phy_ch_width bw,
+					      bool *is_psd,
+					      uint16_t *min_tx_power,
+					      int16_t *min_psd_eirp,
+					      enum reg_6g_ap_type *power_type)
+{
+	return reg_decide_6ghz_power_within_bw_for_freq(pdev,
+							freq,
+							bw,
+							is_psd,
+							min_tx_power,
+							min_psd_eirp,
+							power_type);
+}
 #endif
 
 bool wlan_reg_is_passive_for_freq(struct wlan_objmgr_pdev *pdev,