Jelajahi Sumber

qcacmn: Add an API wlan_reg_get_opclass_details

Add an API wlan_reg_get_opclass_details, to get the operating class
table details from the regulatory component. Also, add a new structure
regdmn_ap_cap_opclass_t in the regulatory component, to fill members
of the mapapcap_t structure.

Change-Id: I8b6a3867a766038663c10ce2f01a8b7d310c7375
CRs-Fixed: 2580505
Hariharan Basuthkar 5 tahun lalu
induk
melakukan
8e28cdda42

+ 120 - 2
umac/regulatory/core/src/reg_opclass.c

@@ -590,8 +590,8 @@ uint16_t reg_chan_opclass_to_freq(uint8_t chan,
 				     op_class_tbl->channels[i]); i++) {
 				if (op_class_tbl->channels[i] == chan) {
 					chan = op_class_tbl->channels[i];
-					return (op_class_tbl->start_freq +
-						(chan * FREQ_TO_CHAN_SCALE));
+					return op_class_tbl->start_freq +
+						(chan * FREQ_TO_CHAN_SCALE);
 				}
 			}
 			reg_err_rl("Channel not found");
@@ -602,4 +602,122 @@ uint16_t reg_chan_opclass_to_freq(uint8_t chan,
 	reg_err_rl("Invalid opclass given as input");
 	return 0;
 }
+
+static void
+reg_get_op_class_tbl_by_chan_map(const struct
+				 reg_dmn_op_class_map_t **op_class_tbl)
+{
+	if (channel_map == channel_map_us)
+		*op_class_tbl = us_op_class;
+	else if (channel_map == channel_map_eu)
+		*op_class_tbl = euro_op_class;
+	else if (channel_map == channel_map_china)
+		*op_class_tbl = us_op_class;
+	else if (channel_map == channel_map_jp)
+		*op_class_tbl = japan_op_class;
+	else
+		*op_class_tbl = global_op_class;
+}
+
+/**
+ * reg_get_channels_from_opclassmap()- Get channels from the opclass map
+ * @pdev: Pointer to pdev
+ * @reg_ap_cap: Pointer to reg_ap_cap
+ * @index: Pointer to index of reg_ap_cap
+ * @op_class_tbl: Pointer to op_class_tbl
+ * @is_opclass_operable: Set true if opclass is operable, else set false
+ *
+ * Populate channels from opclass map to reg_ap_cap as supported and
+ * non-supported channels.
+ *
+ * Return: void.
+ */
+static void
+reg_get_channels_from_opclassmap(
+		struct wlan_objmgr_pdev *pdev,
+		struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+		uint8_t index,
+		const struct reg_dmn_op_class_map_t *op_class_tbl,
+		bool *is_opclass_operable)
+{
+	uint8_t op_cls_chan;
+	qdf_freq_t search_freq;
+	bool is_freq_present;
+	uint8_t chan_idx = 0, n_sup_chans = 0, n_unsup_chans = 0;
+
+	while (op_class_tbl->channels[chan_idx]) {
+		op_cls_chan = op_class_tbl->channels[chan_idx];
+		search_freq = op_class_tbl->start_freq +
+					(FREQ_TO_CHAN_SCALE * op_cls_chan);
+		is_freq_present =
+			reg_is_freq_present_in_cur_chan_list(pdev, search_freq);
+
+		if (!is_freq_present) {
+			reg_ap_cap[index].
+					non_sup_chan_list[n_unsup_chans++] =
+					op_class_tbl->channels[chan_idx];
+			reg_ap_cap[index].num_non_supported_chan++;
+		} else {
+			reg_ap_cap[index].sup_chan_list[n_sup_chans++] =
+					op_class_tbl->channels[chan_idx];
+			reg_ap_cap[index].num_supported_chan++;
+		}
+
+		chan_idx++;
+	}
+
+	if (reg_ap_cap[index].num_supported_chan >= 1)
+		*is_opclass_operable = true;
+}
+
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+				   uint8_t *n_opclasses,
+				   uint8_t max_supp_op_class,
+				   bool global_tbl_lookup)
+{
+	uint8_t max_reg_power = 0;
+	const struct reg_dmn_op_class_map_t *op_class_tbl;
+	uint8_t index = 0;
+
+	if (global_tbl_lookup)
+		op_class_tbl = global_op_class;
+	else
+		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
+
+	max_reg_power = reg_get_max_tx_power(pdev);
+
+	while (op_class_tbl->op_class && (index < max_supp_op_class)) {
+		bool is_opclass_operable = false;
+
+		qdf_mem_zero(reg_ap_cap[index].sup_chan_list,
+			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
+		reg_ap_cap[index].num_supported_chan = 0;
+		qdf_mem_zero(reg_ap_cap[index].non_sup_chan_list,
+			     REG_MAX_CHANNELS_PER_OPERATING_CLASS);
+		reg_ap_cap[index].num_non_supported_chan = 0;
+		reg_get_channels_from_opclassmap(pdev,
+						 reg_ap_cap,
+						 index,
+						 op_class_tbl,
+						 &is_opclass_operable);
+		if (is_opclass_operable) {
+			reg_ap_cap[index].op_class = op_class_tbl->op_class;
+			reg_ap_cap[index].ch_width =
+						op_class_tbl->chan_spacing;
+			reg_ap_cap[index].start_freq =
+						op_class_tbl->start_freq;
+			reg_ap_cap[index].max_tx_pwr_dbm = max_reg_power;
+			reg_ap_cap[index].behav_limit =
+						op_class_tbl->behav_limit;
+			index++;
+		}
+
+		op_class_tbl++;
+	}
+
+	*n_opclasses = index;
+
+	return QDF_STATUS_SUCCESS;
+}
 #endif

+ 25 - 0
umac/regulatory/core/src/reg_opclass.h

@@ -89,6 +89,21 @@ uint16_t reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class);
  */
 uint16_t reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class);
 
+/**
+ * reg_get_opclass_details() - Get details about the current opclass table.
+ * @pdev: Pointer to pdev.
+ * @reg_ap_cap: Pointer to reg_ap_cap.
+ * @n_opclasses: Pointer to number of opclasses.
+ * @max_supp_op_class: Maximum number of operating classes supported.
+ * @global_tbl_lookup: Whether to lookup global op class table.
+ *
+ * Return: QDF_STATUS_SUCCESS if success, else return QDF_STATUS_FAILURE.
+ */
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+				   uint8_t *n_opclasses,
+				   uint8_t max_supp_op_class,
+				   bool global_tbl_lookup);
 #ifdef CONFIG_CHAN_FREQ_API
 
 /**
@@ -195,6 +210,16 @@ static inline void reg_dmn_print_channels_in_opclass(uint8_t *country,
 {
 }
 
+static inline
+QDF_STATUS reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+				   struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+				   uint8_t *n_opclasses,
+				   uint8_t max_supp_op_class,
+				   bool global_tbl_lookup)
+{
+	return QDF_STATUS_E_FAILURE;
+}
+
 #ifdef CONFIG_CHAN_FREQ_API
 
 static inline void

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

@@ -2853,6 +2853,36 @@ enum channel_enum reg_get_chan_enum_for_freq(qdf_freq_t freq)
 	return INVALID_CHANNEL;
 }
 
+bool
+reg_is_freq_present_in_cur_chan_list(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t freq)
+{
+	enum channel_enum chan_enum;
+	struct regulatory_channel *cur_chan_list;
+	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_err_rl("pdev reg obj is NULL");
+		return false;
+	}
+
+	cur_chan_list = pdev_priv_obj->cur_chan_list;
+
+	for (chan_enum = 0; chan_enum < NUM_CHANNELS; chan_enum++)
+		if (cur_chan_list[chan_enum].center_freq == freq)
+			if ((cur_chan_list[chan_enum].state !=
+			     CHANNEL_STATE_DISABLE) &&
+			    !(cur_chan_list[chan_enum].chan_flags &
+			      REGULATORY_CHAN_DISABLED))
+				return true;
+
+	reg_debug_rl("Channel center frequency %d not found", freq);
+
+	return false;
+}
+
 enum channel_state reg_get_channel_state_for_freq(struct wlan_objmgr_pdev *pdev,
 						  qdf_freq_t freq)
 {
@@ -3474,8 +3504,38 @@ enum reg_wifi_band reg_freq_to_band(qdf_freq_t freq)
 		return REG_BAND_6G;
 	return REG_BAND_UNKNOWN;
 }
+
 #endif /* CONFIG_CHAN_FREQ_API */
 
+uint8_t  reg_get_max_tx_power(struct wlan_objmgr_pdev *pdev)
+{
+	struct regulatory_channel *cur_chan_list;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+	uint8_t i, max_tx_power = 0;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("reg pdev private obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	cur_chan_list = pdev_priv_obj->cur_chan_list;
+
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (cur_chan_list[i].state != CHANNEL_STATE_DISABLE &&
+		    cur_chan_list[i].chan_flags != REGULATORY_CHAN_DISABLED) {
+			if (cur_chan_list[i].tx_power > max_tx_power)
+				max_tx_power = cur_chan_list[i].tx_power;
+		}
+	}
+
+	if (!max_tx_power)
+		reg_err_rl("max_tx_power is zero");
+
+	return max_tx_power;
+}
+
 QDF_STATUS reg_set_ignore_fw_reg_offload_ind(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_regulatory_psoc_priv_obj *psoc_reg;

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

@@ -741,6 +741,21 @@ QDF_STATUS reg_disable_chan_coex(struct wlan_objmgr_pdev *pdev,
 #endif
 
 #ifdef CONFIG_CHAN_FREQ_API
+/**
+ * reg_is_freq_present_in_cur_chan_list() - Check the input frequency
+ * @pdev: Pointer to pdev
+ * @freq: Channel center frequency in MHz
+ *
+ * Check if the input channel center frequency is present in the current
+ * channel list
+ *
+ * Return: Return true if channel center frequency is present in the current
+ * channel list, else return false.
+ */
+bool
+reg_is_freq_present_in_cur_chan_list(struct wlan_objmgr_pdev *pdev,
+				     qdf_freq_t freq);
+
 /**
  * reg_get_chan_enum_for_freq() - Get channel enum for given channel frequency
  * @freq: Channel Frequency
@@ -935,6 +950,15 @@ reg_get_5g_bonded_channel_for_freq(struct wlan_objmgr_pdev *pdev,
 				   **bonded_chan_ptr_ptr);
 #endif /* CONFIG_CHAN_FREQ_API */
 
+/**
+ * reg_get_max_tx_power() - Get maximum tx power from the current channel list
+ * @pdev: Pointer to pdev
+ *
+ * Return: return the value of the maximum tx power in the current channel list
+ *
+ */
+uint8_t reg_get_max_tx_power(struct wlan_objmgr_pdev *pdev);
+
 /**
  * reg_set_ignore_fw_reg_offload_ind() - Set if regdb offload indication
  * needs to be ignored

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

@@ -597,6 +597,30 @@ struct reg_dmn_op_class_map_t {
 	uint8_t channels[REG_MAX_CHANNELS_PER_OPERATING_CLASS];
 };
 
+/**
+ * struct regdmn_ap_cap_opclass_t: AP Cap operation class table
+ * @op_class: operating class number
+ * @ch_width: channel width in MHz
+ * @start_freq: Starting Frequency in MHz
+ * @behav_limit: OR of bitmaps of enum behav_limit
+ * @max_tx_pwr_dbm: Maximum tx power in dbm
+ * @num_supported_chan: Number of supported channels
+ * @num_non_supported_chan: Number of non-supported channels
+ * @sup_chan_list: Array of supported channel numbers
+ * @non_sup_chan_list: Array of non supported channel numbers
+ */
+struct regdmn_ap_cap_opclass_t {
+	uint8_t op_class;
+	uint8_t ch_width;
+	qdf_freq_t start_freq;
+	uint16_t behav_limit;
+	uint8_t max_tx_pwr_dbm;
+	uint8_t num_supported_chan;
+	uint8_t num_non_supported_chan;
+	uint8_t sup_chan_list[REG_MAX_CHANNELS_PER_OPERATING_CLASS];
+	uint8_t non_sup_chan_list[REG_MAX_CHANNELS_PER_OPERATING_CLASS];
+};
+
 /**
  * struct reg_dmn_supp_op_classes: operating classes
  * @num_classes: number of classes

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

@@ -605,6 +605,23 @@ uint16_t wlan_reg_dmn_get_curr_opclasses(uint8_t *num_classes,
 					 uint8_t *class);
 
 
+/**
+ * wlan_reg_get_opclass_details() - Get details about the current opclass table.
+ * @pdev: Pointer to pdev.
+ * @reg_ap_cap: Pointer to reg_ap_cap.
+ * @n_opclasses: Pointer to number of opclasses.
+ * @max_supp_op_class: Maximum number of operating classes supported.
+ * @global_tbl_lookup: Whether to lookup global op class tbl.
+ *
+ * Return: QDF_STATUS_SUCCESS if success, else return QDF_STATUS_FAILURE.
+ */
+QDF_STATUS
+wlan_reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+			     struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+			     uint8_t *n_opclasses,
+			     uint8_t max_supp_op_class,
+			     bool global_tbl_lookup);
+
 /**
  * wlan_regulatory_init() - init regulatory component
  *

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

@@ -302,6 +302,18 @@ uint16_t wlan_reg_dmn_get_curr_opclasses(uint8_t *num_classes,
 	return reg_dmn_get_curr_opclasses(num_classes, class);
 }
 
+QDF_STATUS
+wlan_reg_get_opclass_details(struct wlan_objmgr_pdev *pdev,
+			     struct regdmn_ap_cap_opclass_t *reg_ap_cap,
+			     uint8_t *n_opclasses,
+			     uint8_t max_supp_op_class,
+			     bool global_tbl_lookup)
+{
+	return reg_get_opclass_details(pdev, reg_ap_cap, n_opclasses,
+				       max_supp_op_class,
+				       global_tbl_lookup);
+}
+
 QDF_STATUS wlan_regulatory_init(void)
 {
 	QDF_STATUS status;