Преглед изворни кода

qcacmn: Add an API to enable or disable channels based on opclass

Add an API ucfg_reg_enable_disable_opclass_chans where given the
operating class, disable/enable the channels listed in the input
channel list.

The input channel list and operating class should be of 2 GHz or
5 GHz band.

Change-Id: Ie9dbbadbe28e5b5fdc2ec9c60c284da9c9e2286f
CRs-Fixed: 3301654
Hariharan Basuthkar пре 2 година
родитељ
комит
8d466ff361

+ 31 - 0
umac/regulatory/core/src/reg_build_chan_list.c

@@ -2864,6 +2864,35 @@ reg_compute_super_chan_list(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
 }
 #endif /* CONFIG_BAND_6GHZ */
 
+#ifndef CONFIG_REG_CLIENT
+/**
+ * reg_disable_enable_opclass_channels() - Disable the channels in the
+ * current channel list that have opclass_chan_disable flag set.
+ * @pdev_priv_obj: Pointer to pdev_priv_obj
+ *
+ * Return: void
+ */
+static void
+reg_disable_enable_opclass_channels(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+	uint8_t i;
+	struct regulatory_channel *cur_chan_list;
+
+	cur_chan_list = pdev_priv_obj->cur_chan_list;
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (cur_chan_list[i].opclass_chan_disable) {
+			cur_chan_list[i].state = CHANNEL_STATE_DISABLE;
+			cur_chan_list[i].chan_flags |= REGULATORY_CHAN_DISABLED;
+		}
+	}
+}
+#else
+static void
+reg_disable_enable_opclass_channels(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj)
+{
+}
+#endif
+
 void reg_compute_pdev_current_chan_list(struct wlan_regulatory_pdev_priv_obj
 					*pdev_priv_obj)
 {
@@ -2925,6 +2954,8 @@ void reg_compute_pdev_current_chan_list(struct wlan_regulatory_pdev_priv_obj
 	reg_modify_chan_list_for_avoid_chan_ext(pdev_priv_obj);
 
 	reg_modify_sec_chan_list_for_6g_edge_chan(pdev_priv_obj);
+
+	reg_disable_enable_opclass_channels(pdev_priv_obj);
 }
 
 void reg_reset_reg_rules(struct reg_rule_info *reg_rules)

+ 195 - 0
umac/regulatory/core/src/reg_opclass.c

@@ -2041,4 +2041,199 @@ reg_get_opclass_for_cur_hwmode(struct wlan_objmgr_pdev *pdev,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifndef CONFIG_REG_CLIENT
+/**
+ * reg_enable_disable_freq_in_mas_chan_list() - Mark the opclass flag of the
+ * freq/channel as disabled in the master channel list. Then based on that
+ * regulatory disable/enable the freq/channel in the current channel list
+ * @pdev: Pointer to pdev
+ * @chan_num:  2.4Ghz or 5Ghz channel number
+ * @is_disable: Boolean to disable or enable
+ *
+ * Return: void
+ */
+static void
+reg_enable_disable_chan_in_mas_chan_list(struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj,
+					 uint8_t chan_num,
+					 bool is_disable)
+{
+	enum channel_enum chan_enum;
+	struct regulatory_channel *mas_chan_list;
+	qdf_freq_t freq;
+
+	freq = reg_legacy_chan_to_freq(pdev_priv_obj->pdev_ptr, chan_num);
+
+	/*
+	 * freq = 0 represent a regulatory disabled channel in master channel
+	 * list. Do not apply opclass disable/enable on a channel disabled in
+	 * the master channel list.
+	 */
+	if (!freq) {
+		reg_err("Frequency should not be zero");
+		return;
+	}
+
+	chan_enum = reg_get_chan_enum_for_freq(freq);
+	if (reg_is_chan_enum_invalid(chan_enum)) {
+		reg_err("Invalid chan enum %d", chan_enum);
+		return;
+	}
+
+	mas_chan_list = pdev_priv_obj->mas_chan_list;
+
+	if (is_disable) {
+		mas_chan_list[chan_enum].opclass_chan_disable = true;
+	} else {
+		/* A channel can be enabled only if its not in NOL */
+		if (!mas_chan_list[chan_enum].nol_chan)
+			mas_chan_list[chan_enum].opclass_chan_disable = false;
+	}
+}
+
+/**
+ * reg_enable_disable_chan_freq() - Disable or enable a channel in the master
+ * channel list, that is present in the operating class table's channel set.
+ * @pdev: Pointer to pdev.
+ * @is_disable: Boolean to disable or enable
+ * @ieee_chan_list: Pointer to ieee_chan_list
+ * @chan_list_size: Size of ieee_chan_list
+ *
+ * Return: void.
+ */
+static void
+reg_enable_disable_chan_freq(struct wlan_objmgr_pdev *pdev,
+			     bool is_disable,
+			     uint8_t *ieee_chan_list,
+			     uint8_t chan_list_size)
+{
+	uint8_t i;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!pdev_priv_obj) {
+		reg_err("pdev priv obj is NULL");
+		return;
+	}
+
+	for (i = 0; i < chan_list_size; i++) {
+		reg_enable_disable_chan_in_mas_chan_list(pdev_priv_obj,
+							 ieee_chan_list[i],
+							 is_disable);
+	}
+
+	reg_compute_pdev_current_chan_list(pdev_priv_obj);
+}
+
+/**
+ * reg_is_chan_in_opclass_chan_list() - Check if a channel is present in the
+ * operating class table's channel set
+ * @chan: IEEE channel number
+ * @opclass_chan_list: Pointer to opclass_chan_list
+ *
+ * Return: bool.
+ */
+static bool
+reg_is_chan_in_opclass_chan_list(uint8_t chan, const uint8_t *opclass_chan_list)
+{
+	uint8_t j;
+
+	for (j = 0; j < REG_MAX_CHANNELS_PER_OPERATING_CLASS &&
+	     opclass_chan_list[j]; j++) {
+		if (chan == opclass_chan_list[j])
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * reg_is_inlst_subset_of_opchanlst() - Check if a channel present
+ * in the input ieee_chan_list, is absent in the operating class table
+ * channel set.
+ * @opclass_chan_list: Pointer to opclass_chan_list
+ * @ieee_chan_list: Pointer to ieee_chan_list
+ * @ieee_chan_list_size: Size of ieee_chan_list
+ *
+ * Return: True if channel is absent in operating class table channel set.
+ */
+static bool
+reg_is_inlst_subset_of_opchanlst(const uint8_t *opclass_chan_list,
+				 uint8_t *ieee_chan_list,
+				 uint8_t ieee_chan_list_size)
+{
+	uint8_t i;
+
+	for (i = 0; i < ieee_chan_list_size; i++) {
+		if (!reg_is_chan_in_opclass_chan_list(ieee_chan_list[i],
+						      opclass_chan_list))
+			return true;
+	}
+
+	return false;
+}
+
+static bool reg_is_opclass_20mhz(uint8_t opclass)
+{
+	return (opclass >= BW_20_MHZ) && (opclass <= BW_25_MHZ);
+}
+
+QDF_STATUS reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
+					    bool is_disable, uint8_t opclass,
+					    uint8_t *ieee_chan_list,
+					    uint8_t chan_list_size,
+					    bool global_tbl_lookup)
+{
+	const struct reg_dmn_op_class_map_t *op_class_tbl;
+	struct wlan_regulatory_pdev_priv_obj *pdev_priv_obj;
+
+	if (!ieee_chan_list) {
+		reg_err("IEEE channel list is empty");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev_priv_obj = reg_get_pdev_obj(pdev);
+	if (!IS_VALID_PDEV_REG_OBJ(pdev_priv_obj)) {
+		reg_err("pdev reg obj is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (global_tbl_lookup)
+		op_class_tbl = global_op_class;
+	else
+		reg_get_op_class_tbl_by_chan_map(&op_class_tbl);
+
+	if (reg_is_6ghz_op_class(pdev, opclass)) {
+		reg_err("6GHz operating class is not supported");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	while (op_class_tbl->op_class) {
+		if (opclass == op_class_tbl->op_class) {
+			if (!reg_is_opclass_20mhz(opclass)) {
+				reg_err("Opclass should only be 20 MHz opclass");
+				return QDF_STATUS_E_INVAL;
+			}
+
+			if (reg_is_inlst_subset_of_opchanlst(op_class_tbl->channels,
+							     ieee_chan_list,
+							     chan_list_size)) {
+				reg_err("Invalid channel present in chan list");
+				return QDF_STATUS_E_INVAL;
+			}
+
+			reg_enable_disable_chan_freq(pdev, is_disable,
+						     ieee_chan_list,
+						     chan_list_size);
+
+			return QDF_STATUS_SUCCESS;
+		}
+
+		op_class_tbl++;
+	}
+
+	reg_err("The opclass is not found %d", opclass);
+	return QDF_STATUS_E_INVAL;
+}
+#endif /* #ifndef CONFIG_REG_CLIENT */
 #endif

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

@@ -533,4 +533,24 @@ void reg_dmn_free_6g_opclasses_and_channels(struct wlan_objmgr_pdev *pdev,
 					    uint8_t *chansize_lst,
 					    uint8_t *channel_lists[]);
 #endif
+
+#ifndef CONFIG_REG_CLIENT
+/**
+ * reg_enable_disable_opclass_chans() - Disable or enable the input 20 MHz
+ * operating channels in the radio's current channel list
+ * @pdev: Pointer to pdev
+ * @is_disable: Boolean to disable or enable the channels
+ * @opclass: Operating class. Only 20MHz opclasses are supported.
+ * @ieee_chan_list: Pointer to ieee_chan_list
+ * @chan_list_size: Size of ieee_chan_list
+ * @global_tbl_lookup: Whether to lookup global op class table
+ *
+ * Return - Return QDF_STATUS
+ */
+QDF_STATUS reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
+					    bool is_disable, uint8_t opclass,
+					    uint8_t *ieee_chan_list,
+					    uint8_t chan_list_size,
+					    bool global_tbl_lookup);
+#endif
 #endif

+ 9 - 1
umac/regulatory/dispatcher/inc/reg_services_public_struct.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -972,6 +972,11 @@ struct get_usable_chan_req_params {
  * @psd_flag: is PSD channel or not
  * @psd_eirp: PSD power level
  * @is_static_punctured: is static punctured
+ * @opclass_chan_disable: Whether the channel is disabled/enabled by a user
+ *                        command. The command provides an opclass and a
+ *                        subset of the channels belonging to that opclass
+ *                        as inputs and expects the driver to disable/enable
+ *                        the channels in the subset.
  */
 struct regulatory_channel {
 	qdf_freq_t center_freq;
@@ -995,6 +1000,9 @@ struct regulatory_channel {
 #ifdef CONFIG_REG_CLIENT
 	uint8_t is_static_punctured;
 #endif
+#ifndef CONFIG_REG_CLIENT
+	bool opclass_chan_disable;
+#endif
 };
 
 /** struct ap_cli_pwr_mode_info: AP and client power mode information

+ 34 - 1
umac/regulatory/dispatcher/inc/wlan_reg_ucfg_api.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -686,4 +686,37 @@ ucfg_reg_send_afc_resp_rx_ind(struct wlan_objmgr_pdev *pdev,
  */
 QDF_STATUS ucfg_reg_afc_start(struct wlan_objmgr_pdev *pdev, uint64_t req_id);
 #endif
+
+#ifndef CONFIG_REG_CLIENT
+/**
+ * ucfg_reg_enable_disable_opclass_chans() - Disable or enable the input 20 MHz
+ * operating channels in the radio's current channel list.
+ * @pdev: Pointer to pdev
+ * @is_disable: Boolean to disable or enable the channels
+ * @opclass: Operating class. Only 20MHz opclasses are supported.
+ * @ieee_chan_list: Pointer to ieee_chan_list
+ * @chan_list_size: Size of ieee_chan_list
+ * @global_tbl_lookup: Whether to lookup global op class table
+ *
+ * Return - Return QDF_STATUS
+ */
+QDF_STATUS ucfg_reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
+						 bool is_disable,
+						 uint8_t opclass,
+						 uint8_t *ieee_chan_list,
+						 uint8_t chan_list_size,
+						 bool global_tbl_lookup);
+#else
+static inline QDF_STATUS
+ucfg_reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
+				      bool is_disable,
+				      uint8_t opclass,
+				      uint8_t *ieee_chan_list,
+				      uint8_t chan_list_size,
+				      bool global_tbl_lookup)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
 #endif

+ 16 - 1
umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  *
  * Permission to use, copy, modify, and/or distribute this software for
@@ -29,6 +29,7 @@
 #include <../../core/src/reg_priv_objs.h>
 #include <../../core/src/reg_utils.h>
 #include <../../core/src/reg_services_common.h>
+#include <../../core/src/reg_opclass.h>
 #include <../../core/src/reg_lte.h>
 #include <../../core/src/reg_offload_11d_scan.h>
 #include <../../core/src/reg_build_chan_list.h>
@@ -492,3 +493,17 @@ ucfg_reg_afc_start(struct wlan_objmgr_pdev *pdev, uint64_t req_id)
 	return reg_afc_start(pdev, req_id);
 }
 #endif
+
+#ifndef CONFIG_REG_CLIENT
+QDF_STATUS ucfg_reg_enable_disable_opclass_chans(struct wlan_objmgr_pdev *pdev,
+						 bool is_disable,
+						 uint8_t opclass,
+						 uint8_t *ieee_chan_list,
+						 uint8_t chan_list_size,
+						 bool global_tbl_lookup)
+{
+	return reg_enable_disable_opclass_chans(pdev, is_disable, opclass,
+						ieee_chan_list, chan_list_size,
+						global_tbl_lookup);
+}
+#endif