ソースを参照

qcacld-3.0: User MCC quota setting

Set the MCC quota for a given interface.

Change-Id: I313cdf1673f8fc5f50a049d429c0d88fd213e66f
CRs-Fixed: 3106146
Madhvapathi Sriram 3 年 前
コミット
79e13b55ab

+ 11 - 0
Kbuild

@@ -507,6 +507,10 @@ ifeq ($(CONFIG_QCACLD_WLAN_CONNECTIVITY_LOGGING), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_connectivity_logging.o
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mcc_quota.o
+endif
+
 $(call add-wlan-objs,hdd,$(HDD_OBJS))
 
 ###### OSIF_SYNC ########
@@ -4329,6 +4333,13 @@ endif
 
 cppflags-$(CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET) += -DWLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET
 
+ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y)
+cppflags-y += -DWLAN_FEATURE_MCC_QUOTA
+ifdef CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA
+ccflags-y += -DWLAN_MCC_MIN_CHANNEL_QUOTA=$(CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA)
+endif
+endif
+
 KBUILD_CPPFLAGS += $(cppflags-y)
 
 # Currently, for versions of gcc which support it, the kernel Makefile

+ 21 - 3
components/mlme/core/src/wlan_mlme_main.c

@@ -2483,7 +2483,6 @@ mlme_init_dot11_mode_cfg(struct wlan_objmgr_psoc *psoc,
 
 /**
  * mlme_iot_parse_aggr_info - parse aggr related items in ini
- *
  * @psoc: PSOC pointer
  * @iot: IOT related CFG items
  *
@@ -2589,7 +2588,6 @@ end:
 
 /**
  * mlme_iot_parse_aggr_info - parse IOT related items in ini
- *
  * @psoc: PSOC pointer
  * @iot: IOT related CFG items
  *
@@ -2604,7 +2602,6 @@ mlme_init_iot_cfg(struct wlan_objmgr_psoc *psoc,
 
 /**
  * mlme_init_dual_sta_config - Initialize dual sta configuratons
- *
  * @gen: Generic CFG config items
  *
  * Return: None
@@ -2617,6 +2614,26 @@ mlme_init_dual_sta_config(struct wlan_mlme_generic *gen)
 				QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED;
 }
 
+#ifdef WLAN_FEATURE_MCC_QUOTA
+/**
+ * mlme_init_user_mcc_quota_config - Initialize mcc quota
+ * @gen: Generic CFG config items
+ *
+ * Return: None
+ */
+static void
+mlme_init_user_mcc_quota_config(struct wlan_mlme_generic *gen)
+{
+	gen->user_mcc_quota.quota = 0;
+	gen->user_mcc_quota.op_mode = QDF_MAX_NO_OF_MODE;
+	gen->user_mcc_quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX;
+}
+#else
+static void
+mlme_init_user_mcc_quota_config(struct wlan_mlme_generic *gen)
+{
+}
+#endif
 QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_mlme_psoc_ext_obj *mlme_obj;
@@ -2672,6 +2689,7 @@ QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc)
 	mlme_init_ratemask_cfg(psoc, &mlme_cfg->ratemask_cfg);
 	mlme_init_iot_cfg(psoc, &mlme_cfg->iot);
 	mlme_init_dual_sta_config(&mlme_cfg->gen);
+	mlme_init_user_mcc_quota_config(&mlme_cfg->gen);
 
 	return status;
 }

+ 50 - 18
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -761,7 +761,6 @@ QDF_STATUS wlan_mlme_get_sap_chan_switch_rate_enabled(struct wlan_objmgr_psoc
 
 /**
  * wlan_mlme_get_sap_force_11n_for_11ac() - get the sap 11n for 11ac
- *
  * @psoc: pointer to psoc object
  * @value: Value that needs to be set from the caller
  *
@@ -772,7 +771,6 @@ QDF_STATUS wlan_mlme_get_sap_force_11n_for_11ac(struct wlan_objmgr_psoc
 
 /**
  * wlan_mlme_get_go_force_11n_for_11ac() - get the go 11n for 11ac
- *
  * @psoc: pointer to psoc object
  * @value: Value that needs to be set from the caller
  *
@@ -783,7 +781,6 @@ QDF_STATUS wlan_mlme_get_go_force_11n_for_11ac(struct wlan_objmgr_psoc
 
 /**
  * wlan_mlme_is_go_11ac_override() - Override 11ac bandwdith for P2P GO
- *
  * @psoc: pointer to psoc object
  * @value: pointer to the value which will be filled for the caller
  *
@@ -794,7 +791,6 @@ QDF_STATUS wlan_mlme_is_go_11ac_override(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_is_sap_11ac_override() - Override 11ac bandwdith for SAP
- *
  * @psoc: pointer to psoc object
  * @value: pointer to the value which will be filled for the caller
  *
@@ -805,7 +801,6 @@ QDF_STATUS wlan_mlme_is_sap_11ac_override(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_set_go_11ac_override() - set override 11ac bandwdith for P2P GO
- *
  * @psoc: pointer to psoc object
  * @value: pointer to the value which will be filled for the caller
  *
@@ -816,7 +811,6 @@ QDF_STATUS wlan_mlme_set_go_11ac_override(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_set_sap_11ac_override() - set override 11ac bandwdith for SAP
- *
  * @psoc: pointer to psoc object
  * @value: pointer to the value which will be filled for the caller
  *
@@ -946,7 +940,6 @@ QDF_STATUS wlan_mlme_cfg_get_enable_ul_ofdm(struct wlan_objmgr_psoc *psoc,
 
 /**
  * mlme_update_tgt_he_caps_in_cfg() - Update tgt he cap in mlme component
- *
  * @psoc: pointer to psoc object
  * @cfg: pointer to config params from target
  *
@@ -962,7 +955,6 @@ QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc,
 #ifdef WLAN_FEATURE_11BE
 /**
  * mlme_update_tgt_eht_caps_in_cfg() - Update tgt eht cap in mlme component
- *
  * @psoc: pointer to psoc object
  * @cfg: pointer to config params from target
  *
@@ -2262,7 +2254,6 @@ wlan_mlme_is_relaxed_6ghz_conn_policy_enabled(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_get_sta_miracast_mcc_rest_time() - Get STA/MIRACAST MCC rest time
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -2276,7 +2267,6 @@ wlan_mlme_get_sta_miracast_mcc_rest_time(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_get_scan_probe_unicast_ra() - Get scan probe unicast RA cfg
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -2290,7 +2280,6 @@ wlan_mlme_get_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_set_scan_probe_unicast_ra() - Set scan probe unicast RA cfg
- *
  * @psoc: pointer to psoc object
  * @value: set value
  *
@@ -2304,7 +2293,6 @@ wlan_mlme_set_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_get_sap_mcc_chnl_avoid() - Check if SAP MCC needs to be avoided
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -2318,7 +2306,6 @@ wlan_mlme_get_sap_mcc_chnl_avoid(struct wlan_objmgr_psoc *psoc,
 				 uint8_t *value);
 /**
  * wlan_mlme_get_mcc_bcast_prob_resp() - Get broadcast probe rsp in MCC
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -2333,7 +2320,6 @@ wlan_mlme_get_mcc_bcast_prob_resp(struct wlan_objmgr_psoc *psoc,
 				  uint8_t *value);
 /**
  * wlan_mlme_get_mcc_rts_cts_prot() - To get RTS-CTS protection in MCC.
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -2348,7 +2334,6 @@ wlan_mlme_get_mcc_rts_cts_prot(struct wlan_objmgr_psoc *psoc,
 			       uint8_t *value);
 /**
  * wlan_mlme_get_mcc_feature() - To find out to enable/disable MCC feature
- *
  * @psoc: pointer to psoc object
  * @value: value which needs to filled by API
  *
@@ -3396,7 +3381,6 @@ bool mlme_get_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id);
 #ifdef WLAN_FEATURE_P2P_P2P_STA
 /**
  * wlan_mlme_get_p2p_p2p_conc_support() - Get p2p+p2p conc support
- *
  * @psoc: pointer to psoc object
  * @val : value
  *
@@ -3421,7 +3405,6 @@ enum phy_ch_width mlme_get_vht_ch_width(void);
 
 /**
  * wlan_mlme_get_mgmt_hw_tx_retry_count() - Get mgmt frame hw tx retry count
- *
  * @psoc: pointer to psoc object
  * @frm_type: frame type of the query
  *
@@ -3433,7 +3416,6 @@ wlan_mlme_get_mgmt_hw_tx_retry_count(struct wlan_objmgr_psoc *psoc,
 
 /**
  * wlan_mlme_get_tx_retry_multiplier() - Get the tx retry multiplier percentage
- *
  * @psoc: pointer to psoc object
  * @tx_retry_multiplier: pointer to hold user config value of
  * tx_retry_multiplier
@@ -3469,4 +3451,54 @@ QDF_STATUS
 wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev,
 				 uint8_t num_ratemask,
 				 struct config_ratemask_params *rate_params);
+#ifdef WLAN_FEATURE_MCC_QUOTA
+/**
+ * wlan_mlme_set_user_mcc_quota() - set the user mcc quota in mlme
+ * @psoc: pointer to psoc object
+ * @quota: pointer to user set mcc quota object
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota);
+
+/**
+ * wlan_mlme_get_user_mcc_quota() - Get the user mcc quota from mlme
+ * @psoc: pointer to psoc object
+ * @quota: pointer to user set mcc quota object
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota);
+
+/**
+ * wlan_mlme_get_user_mcc_duty_cycle_percentage() - Get user mcc duty cycle
+ * @psoc: pointer to psoc object
+ *
+ * Return: MCC duty cycle if MCC exists for the user MCC quota, else 0
+ */
+uint32_t
+wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc);
+#else
+static inline QDF_STATUS
+wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+			     struct wlan_user_mcc_quota *quota)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS
+wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+			     struct wlan_user_mcc_quota *quota)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline uint32_t
+wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc)
+{
+	return 0;
+}
+#endif /* WLAN_FEATURE_MCC_QUOTA */
 #endif /* _WLAN_MLME_API_H_ */

+ 15 - 0
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -1290,6 +1290,18 @@ enum mlme_cfg_frame_type {
 
 #define MAX_MGMT_HW_TX_RETRY_COUNT 127
 
+/**
+ * struct wlan_user_mcc_quota - User MCC quota configuration
+ * @op_mode: Mode for which MCC quota needs to be applied
+ * @quota: User MCC quota value
+ * @vdev_id: Intended VDEV id for the quota
+ */
+struct wlan_user_mcc_quota {
+	enum QDF_OPMODE op_mode;
+	uint8_t quota;
+	uint8_t vdev_id;
+};
+
 /* struct wlan_mlme_generic - Generic CFG config items
  *
  * @band_capability: HW Band Capability - Both or 2.4G only or 5G only
@@ -1391,6 +1403,9 @@ struct wlan_mlme_generic {
 #ifdef CONFIG_BAND_6GHZ
 	bool relaxed_6ghz_conn_policy;
 #endif
+#ifdef WLAN_FEATURE_MCC_QUOTA
+	struct wlan_user_mcc_quota user_mcc_quota;
+#endif
 };
 
 /*

+ 50 - 1
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -4443,7 +4443,6 @@ bool ucfg_mlme_get_coex_unsafe_chan_reg_disable(
  *
  * Return: QDF_STATUS
  */
-
 static inline QDF_STATUS
 ucfg_set_ratemask_params(struct wlan_objmgr_vdev *vdev,
 			 uint8_t num_ratemask,
@@ -4452,4 +4451,54 @@ ucfg_set_ratemask_params(struct wlan_objmgr_vdev *vdev,
 	return wlan_mlme_update_ratemask_params(vdev, num_ratemask,
 						rate_params);
 }
+
+/*
+ * ucfg_mlme_set_user_mcc_quota() - Set the user set mcc quota in mlme
+ * value
+ * @psoc: pointer to psoc object
+ * @quota: pointer to user mcc quota object
+ *
+ * Return: QDF Status
+ */
+static inline
+QDF_STATUS ucfg_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota)
+{
+	return wlan_mlme_set_user_mcc_quota(psoc, quota);
+}
+
+/**
+ * ucfg_mlme_get_user_mcc_quota() - Get the user set mcc quota from mlme
+ * value
+ * @psoc: pointer to psoc object
+ * @quota: pointer to user mcc quota object
+ *
+ * Return: QDF Status
+ */
+static inline
+QDF_STATUS ucfg_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota)
+{
+	return wlan_mlme_get_user_mcc_quota(psoc, quota);
+}
+
+/**
+ * ucfg_mlme_get_user_mcc_quota_percentage() - Get user mcc quota percentage
+ * duty-cycle for a i/f type or mode
+ * @psoc: pointer to psoc object
+ *
+ * MCC duty-cycle value in below format
+ * ******************************************************
+ * |bit 31-24 | bit 23-16 | bits 15-8   |bits 7-0   |
+ * | Unused   | Quota for | chan. # for |chan. # for|
+ * |          | 1st chan  | 1st chan.   |2nd chan.  |
+ * *****************************************************
+ *
+ * Return: primary iface MCC duty-cycle value
+ */
+static inline
+uint32_t ucfg_mlme_get_user_mcc_quota_percentage(struct wlan_objmgr_psoc *psoc)
+{
+	return  wlan_mlme_get_user_mcc_duty_cycle_percentage(psoc);
+}
 #endif /* _WLAN_MLME_UCFG_API_H_ */

+ 130 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -5462,3 +5462,133 @@ wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev,
 	}
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_MCC_QUOTA
+#define WLAN_MCC_MIN_QUOTA 10 /* in %age */
+#define WLAN_MCC_MAX_QUOTA 90 /* in %age */
+QDF_STATUS wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota)
+
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	if (!quota)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_FAILURE;
+
+	if (quota->quota < WLAN_MCC_MIN_QUOTA)
+		quota->quota = WLAN_MCC_MIN_QUOTA;
+	else if (quota->quota > WLAN_MCC_MAX_QUOTA)
+		quota->quota = WLAN_MCC_MAX_QUOTA;
+
+	mlme_obj->cfg.gen.user_mcc_quota.quota = quota->quota;
+	mlme_obj->cfg.gen.user_mcc_quota.op_mode = quota->op_mode;
+	mlme_obj->cfg.gen.user_mcc_quota.vdev_id = quota->vdev_id;
+
+	mlme_debug("quota : %u, op_mode : %d, vdev_id : %u",
+		   quota->quota, quota->op_mode, quota->vdev_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc,
+					struct wlan_user_mcc_quota *quota)
+{
+	struct wlan_mlme_psoc_ext_obj *mlme_obj;
+
+	if (!quota)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	mlme_obj = mlme_get_psoc_ext_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_FAILURE;
+
+	quota->quota = mlme_obj->cfg.gen.user_mcc_quota.quota;
+	quota->op_mode = mlme_obj->cfg.gen.user_mcc_quota.op_mode;
+	quota->vdev_id = mlme_obj->cfg.gen.user_mcc_quota.vdev_id;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint32_t
+wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t mcc_freq, ch_freq, quota_value;
+	struct wlan_user_mcc_quota quota;
+	uint8_t operating_channel;
+	int status;
+
+	quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX;
+	quota.quota = 0;
+	if (QDF_IS_STATUS_ERROR(wlan_mlme_get_user_mcc_quota(psoc, &quota))) {
+		mlme_debug("Error getting user quota set");
+		return 0;
+	}
+
+	if (quota.vdev_id == WLAN_UMAC_VDEV_ID_MAX || quota.quota == 0) {
+		mlme_debug("Invalid quota : vdev %u, quota %u",
+			   quota.vdev_id, quota.quota);
+		return 0;
+	}
+	status = policy_mgr_get_chan_by_session_id(psoc, quota.vdev_id,
+						   &ch_freq);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlme_debug("Could not get vdev %u chan", quota.vdev_id);
+		return 0;
+	}
+	mcc_freq = policy_mgr_get_mcc_operating_channel(psoc, quota.vdev_id);
+	if (mcc_freq == INVALID_CHANNEL_ID)
+		return 0;
+
+	operating_channel = wlan_freq_to_chan(ch_freq);
+	if (!operating_channel) {
+		mlme_debug("Primary op channel is invalid");
+		return 0;
+	}
+	/*
+	 * The channel numbers for both adapters and the time
+	 * quota for the 1st adapter, i.e., one specified in cmd
+	 * are formatted as a bit vector
+	 * ******************************************************
+	 * |bit 31-24  | bit 23-16 |  bits 15-8  |bits 7-0   |
+	 * |  Unused   | Quota for | chan. # for |chan. # for|
+	 * |           |  1st chan | 1st chan.   |2nd chan.  |
+	 * ******************************************************
+	 */
+	mlme_debug("Opmode (%d) vdev (%u) channel %u and quota %u",
+		   quota.op_mode, quota.vdev_id,
+		   operating_channel, quota.quota);
+	quota_value = quota.quota;
+	/* Move the time quota for first channel to bits 15-8 */
+	quota_value = quota_value << 8;
+	/*
+	 * Store the channel number of 1st channel at bits 7-0
+	 * of the bit vector
+	 */
+	quota_value |= operating_channel;
+
+	operating_channel = wlan_freq_to_chan(mcc_freq);
+	if (!operating_channel) {
+		mlme_debug("Secondary op channel is invalid");
+		return 0;
+	}
+
+	/*
+	 * Now move the time quota and channel number of the
+	 * 1st adapter to bits 23-16 and bits 15-8 of the bit
+	 * vector, respectively.
+	 */
+	quota_value = quota_value << 8;
+	/*
+	 * Set the channel number for 2nd MCC vdev at bits
+	 * 7-0 of set_value
+	 */
+	quota_value |= operating_channel;
+	mlme_debug("quota value:%x", quota_value);
+
+	return quota_value;
+}
+#endif /* WLAN_FEATURE_MCC_QUOTA */

+ 16 - 1
core/hdd/inc/wlan_hdd_main.h

@@ -3747,7 +3747,22 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind);
  *
  */
 struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx,
-					     const char *iface_name);
+						  const char *iface_name);
+
+/**
+ * hdd_get_adapter_by_ifindex() - Return adapter associated with an ifndex
+ * @hdd_ctx: hdd context.
+ * @if_index: netdev interface index
+ *
+ * This function is used to get the adapter associated with a netdev with the
+ * given interface index.
+ *
+ * Return: adapter pointer if found, NULL otherwise
+ *
+ */
+struct hdd_adapter *hdd_get_adapter_by_ifindex(struct hdd_context *hdd_ctx,
+					       uint32_t if_index);
+
 enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width);
 
 /**

+ 2 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -178,6 +178,7 @@
 #include "wlan_pkt_capture_ucfg_api.h"
 #include "os_if_pkt_capture.h"
 #include "wlan_hdd_son.h"
+#include "wlan_hdd_mcc_quota.h"
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -17639,6 +17640,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 			      QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX)
 	},
 #endif
+	FEATURE_MCC_QUOTA_VENDOR_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)

+ 3 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -107,6 +107,7 @@
 #include <wlan_mlo_mgr_ap.h>
 #endif
 #include "wlan_hdd_son.h"
+#include "wlan_hdd_mcc_quota.h"
 
 #define ACS_SCAN_EXPIRY_TIMEOUT_S 4
 
@@ -2154,6 +2155,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
 			hdd_err("qdf_event_set failed! status: %d", qdf_status);
 			goto stopbss;
 		}
+
+		wlan_hdd_apply_user_mcc_quota(adapter);
 		break;          /* Event will be sent after Switch-Case stmt */
 
 	case eSAP_STOP_BSS_EVENT:

+ 21 - 0
core/hdd/src/wlan_hdd_main.c

@@ -9375,6 +9375,27 @@ struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx,
 	return NULL;
 }
 
+struct hdd_adapter *hdd_get_adapter_by_ifindex(struct hdd_context *hdd_ctx,
+					       uint32_t if_index)
+{
+	struct hdd_adapter *adapter, *next_adapter = NULL;
+	wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER;
+
+	hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter,
+					   dbgid) {
+		if (adapter->dev->ifindex == if_index) {
+			hdd_adapter_dev_put_debug(adapter, dbgid);
+			if (next_adapter)
+				hdd_adapter_dev_put_debug(next_adapter,
+							  dbgid);
+			return adapter;
+		}
+		hdd_adapter_dev_put_debug(adapter, dbgid);
+	}
+
+	return NULL;
+}
+
 /**
  * hdd_get_adapter() - to get adapter matching the mode
  * @hdd_ctx: hdd context

+ 241 - 0
core/hdd/src/wlan_hdd_mcc_quota.c

@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2022 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_hdd_mcc_quota.c
+ *
+ * WLAN Host Device Driver MCC quota feature cfg80211 APIs implementation
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include "osif_sync.h"
+#include <wlan_hdd_includes.h>
+#include <net/cfg80211.h>
+#include "sme_api.h"
+#include "wlan_hdd_cfg80211.h"
+#include "wlan_hdd_hostapd.h"
+#include "wlan_hdd_main.h"
+#include "wlan_hdd_mcc_quota.h"
+#include "wlan_hdd_trace.h"
+#include "qdf_str.h"
+#include "qdf_trace.h"
+#include "qdf_types.h"
+#include "wlan_policy_mgr_api.h"
+#include <qca_vendor.h>
+#include "wlan_utility.h"
+#include "wlan_policy_mgr_ucfg.h"
+#include "wlan_mlme_ucfg_api.h"
+#include "wlan_mlme_public_struct.h"
+#include "wlan_hdd_object_manager.h"
+#include "sme_api.h"
+
+const struct nla_policy
+set_mcc_quota_policy[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE] =	{ .type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES] =
+				VENDOR_NLA_POLICY_NESTED(set_mcc_quota_policy),
+	[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ] =	{
+					.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE] =	{
+							.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX] = { .type = NLA_U32 },
+};
+
+int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc, bool enable)
+{
+	bool enable_mcc_adaptive_sch;
+
+	hdd_debug("enable : %d", enable);
+	ucfg_policy_mgr_get_mcc_adaptive_sch(psoc, &enable_mcc_adaptive_sch);
+	if (enable_mcc_adaptive_sch) {
+		ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch(psoc, enable);
+		if (QDF_IS_STATUS_ERROR(sme_set_mas(enable))) {
+			hdd_err("Fail to config mcc adaptive sched.");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int wlan_hdd_cfg80211_set_mcc_quota(struct wiphy *wiphy,
+				    struct wireless_dev *wdev,
+				    const void *attr,
+				    int attr_len)
+{
+	struct hdd_adapter *if_adapter;
+	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1];
+	struct nlattr *quota_entries[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1];
+	struct nlattr *curr_attr;
+	struct wlan_objmgr_psoc *psoc;
+	uint32_t duty_cycle, cmd_id, quota_type, rem_bytes, entries, if_idx;
+	struct wlan_user_mcc_quota mcc_quota;
+	int att_id, rc;
+
+	hdd_enter();
+
+	if (wlan_hdd_validate_context(hdd_ctx))
+		return -EINVAL;
+
+	psoc = hdd_ctx->psoc;
+	if (!psoc)
+		return -EINVAL;
+
+	if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX,
+				    attr, attr_len, set_mcc_quota_policy)) {
+		hdd_err("Error parsing attributes");
+		return -EINVAL;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE;
+	if (!tb[cmd_id]) {
+		hdd_err("Quota type not specified");
+		return -EINVAL;
+	}
+	quota_type = nla_get_u32(tb[cmd_id]);
+	if (quota_type != QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED &&
+	    quota_type != QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR) {
+		hdd_err("Quota type is not valid %u", quota_type);
+		return -EINVAL;
+	}
+
+	if (quota_type == QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR) {
+		/* Remove quota, enable MCC adaptive scheduling */
+		if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, true))
+			return -EAGAIN;
+		mcc_quota.op_mode = QDF_MAX_NO_OF_MODE;
+		mcc_quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX;
+		ucfg_mlme_set_user_mcc_quota(psoc, &mcc_quota);
+		return 0;
+	}
+
+	cmd_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES;
+	if (!tb[cmd_id]) {
+		hdd_err("No entries present");
+		return -EINVAL;
+	}
+
+	entries = 0;
+	nla_for_each_nested(curr_attr, tb[cmd_id], rem_bytes) {
+		if (entries > 0) {
+			hdd_debug("Only one entry permitted");
+			hdd_debug("Entry (%d) for (%u) is ignored",
+				  entries, nla_type(curr_attr));
+			entries++;
+			continue;
+		}
+		rc = wlan_cfg80211_nla_parse_nested(quota_entries,
+			       QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX,
+			       curr_attr,
+			       set_mcc_quota_policy);
+		if (rc) {
+			hdd_err("Entry parse error %d", rc);
+			return -EINVAL;
+		}
+
+		att_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX;
+		if (!quota_entries[att_id]) {
+			hdd_err("if_index not specified");
+			return -EINVAL;
+		}
+
+		if_idx = nla_get_u32(quota_entries[att_id]);
+		if (if_idx == 0) {
+			hdd_debug("Invalid if_index");
+			return -EINVAL;
+		}
+		if_adapter = hdd_get_adapter_by_ifindex(hdd_ctx, if_idx);
+
+		if (!if_adapter) {
+			hdd_err("interface (%u) not found", if_idx);
+			return -EINVAL;
+		}
+
+		if (wlan_hdd_validate_vdev_id(if_adapter->vdev_id))
+			return -EINVAL;
+
+		att_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE;
+		if (!quota_entries[att_id]) {
+			hdd_err("Quota not specified");
+			return -EINVAL;
+		}
+		mcc_quota.quota = nla_get_u32(quota_entries[att_id]);
+		mcc_quota.vdev_id = if_adapter->vdev_id;
+		mcc_quota.op_mode = if_adapter->device_mode;
+
+		entries++;
+	}
+
+	if (entries == 0) {
+		hdd_err("No entries found");
+		return -EINVAL;
+	}
+
+	ucfg_mlme_set_user_mcc_quota(psoc, &mcc_quota);
+
+	duty_cycle = ucfg_mlme_get_user_mcc_quota_percentage(psoc);
+
+	if (duty_cycle == 0) {
+		hdd_debug("Quota will be configured when MCC scenario exists");
+		return 0;
+	}
+
+	if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, false))
+		return -EAGAIN;
+
+	if (wlan_hdd_send_mcc_vdev_quota(if_adapter, duty_cycle))
+		return -EINVAL;
+
+	return 0;
+}
+
+int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter)
+{
+	struct hdd_context *hdd_ctx;
+	uint32_t quota_val;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	if (!hdd_ctx)
+		return -EINVAL;
+
+	quota_val =
+		ucfg_mlme_get_user_mcc_quota_percentage(hdd_ctx->psoc);
+
+	if (quota_val == 0) {
+		hdd_debug("no mcc/quota for mode %d, vdev_id : %u",
+			  adapter->device_mode, adapter->vdev_id);
+		return 0;
+	}
+
+	if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, false))
+		return 0;
+
+	if (wlan_hdd_send_mcc_vdev_quota(adapter, quota_val)) {
+		hdd_info("Could not send quota");
+		wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, true);
+	}
+
+	return 0;
+}

+ 95 - 0
core/hdd/src/wlan_hdd_mcc_quota.h

@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2022 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_hdd_mcc_quota.h
+ *
+ * WLAN Host Device Driver MCC quota feature interface definitions
+ *
+ */
+#ifndef WLAN_HDD_MCC_QUOTA_H
+#define WLAN_HDD_MCC_QUOTA_H
+#include "qdf_types.h"
+#include "qdf_status.h"
+#include "qca_vendor.h"
+#include <net/cfg80211.h>
+
+struct hdd_context;
+struct hdd_adapter;
+struct wlan_objmgr_psoc;
+
+#ifdef WLAN_FEATURE_MCC_QUOTA
+extern const struct nla_policy
+set_mcc_quota_policy[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1];
+
+/**
+ * wlan_hdd_set_mcc_adaptive_sched: Enable or disable MCC adaptive scheduling
+ * @hdd_ctx: HDD context
+ * @enable: Enable (true) or disable (false)
+ *
+ * Return: 0 for success, Non zero failure code for errors
+ */
+int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc,
+				    bool enable);
+
+/**
+ * wlan_hdd_cfg80211_set_mcc_quota() - Set user MCC quota to the target
+ * @wiphy: Wireless info object
+ * @wdev: Wireless dev object
+ * @attr: Command attributes
+ * @attr_len: Length of attributes
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int wlan_hdd_cfg80211_set_mcc_quota(struct wiphy *wiphy,
+				    struct wireless_dev *wdev,
+				    const void *attr,
+				    int attr_len);
+
+#define	FEATURE_MCC_QUOTA_VENDOR_COMMANDS				   \
+{									   \
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,			   \
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA,		   \
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,\
+	.doit = wlan_hdd_cfg80211_set_mcc_quota,			   \
+	vendor_command_policy(set_mcc_quota_policy,			   \
+			      QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX)	   \
+},
+
+/**
+ * wlan_hdd_apply_user_mcc_quota() - Apply the user MCC quota to the target
+ * @adapter: pointer to HDD adapter object
+ *
+ * Return: 0 on succcess, errno for error
+ */
+int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter);
+#else /* WLAN_FEATURE_MCC_QUOTA */
+#define	FEATURE_MCC_QUOTA_VENDOR_COMMANDS
+
+static inline int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter)
+{
+	return 0;
+}
+
+static inline int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc,
+						  bool enable)
+{
+	return 0;
+}
+#endif /* WLAN_FEATURE_MCC_QUOTA */
+#endif /* WLAN_HDD_MCC_QUOTA_H */

+ 20 - 0
core/sme/src/csr/csr_api_roam.c

@@ -6650,6 +6650,26 @@ cm_csr_connect_done_ind(struct wlan_objmgr_vdev *vdev,
 				return -EAGAIN;
 			}
 		}
+	} else {
+		QDF_STATUS status = QDF_STATUS_SUCCESS;
+		uint32_t quota_val;
+
+		quota_val =
+			ucfg_mlme_get_user_mcc_quota_percentage(mac_ctx->psoc);
+
+		if (quota_val) {
+			if (enable_mcc_adaptive_sch) {
+				policy_mgr_set_dynamic_mcc_adaptive_sch(
+							mac_ctx->psoc, false);
+				status = sme_set_mas(false);
+			}
+			if (status == QDF_STATUS_SUCCESS)
+				sme_cli_set_command(wlan_vdev_get_id(vdev),
+						    WMA_VDEV_MCC_SET_TIME_QUOTA,
+						    quota_val, VDEV_CMD);
+		} else {
+			sme_debug("no applicable user mcc/quota");
+		}
 	}
 
 	/*