Browse Source

qcacld-3.0: Add support to handle PEER_OPER_MODE_CHANGE event

Firmware sends PEER_OPER_MODE_CHANGE event to host in SAP
mode when a connected client indicates upgrade/downgrade
of its bandwidth.
Host needs this data as any further SAP bandwidth
upgrade/downgrade should honor the indicated bandwidth for
that specific peer.

Change-Id: I50fecf670b47c56e3f33b8519fde1d5eaec7523f
CRs-Fixed: 3604716
Vijay Patil 1 year ago
parent
commit
52e5d326f6

+ 71 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -119,11 +119,22 @@ struct peer_disconnect_stats_param {
 	qdf_mc_timer_t disconn_stats_timer;
 };
 
+/**
+ * struct wlan_mlme_rx_ops  - structure of tx function pointers for
+ * roaming related commands
+ * @peer_oper_mode_eventid : Rx ops function pointer for operating mode event
+ */
+struct wlan_mlme_rx_ops {
+	QDF_STATUS (*peer_oper_mode_eventid)(struct wlan_objmgr_psoc *psoc,
+					     struct peer_oper_mode_event *data);
+};
+
 /**
  * struct wlan_mlme_psoc_ext_obj -MLME ext psoc priv object
  * @cfg:     cfg items
  * @rso_tx_ops: Roam Tx ops to send roam offload commands to firmware
  * @rso_rx_ops: Roam Rx ops to receive roam offload events from firmware
+ * @mlme_rx_ops: mlme Rx ops to receive events from firmware
  * @wfa_testcmd: WFA config tx ops to send to FW
  * @disconnect_stats_param: Peer disconnect stats related params for SAP case
  * @scan_requester_id: mlme scan requester id
@@ -132,6 +143,7 @@ struct wlan_mlme_psoc_ext_obj {
 	struct wlan_mlme_cfg cfg;
 	struct wlan_cm_roam_tx_ops rso_tx_ops;
 	struct wlan_cm_roam_rx_ops rso_rx_ops;
+	struct wlan_mlme_rx_ops mlme_rx_ops;
 	struct wlan_mlme_wfa_cmd wfa_testcmd;
 	struct peer_disconnect_stats_param disconnect_stats_param;
 	wlan_scan_requester scan_requester_id;
@@ -175,6 +187,7 @@ struct sae_auth_retry {
  * @peer_set_key_runtime_wakelock: runtime pm wakelock for set key
  * @is_key_wakelock_set: flag to check if key wakelock is pending to release
  * @assoc_rsp: assoc rsp IE received during connection
+ * @peer_ind_bw: peer indication channel bandwidth
  */
 struct peer_mlme_priv_obj {
 	uint8_t last_pn_valid;
@@ -194,6 +207,7 @@ struct peer_mlme_priv_obj {
 	qdf_runtime_lock_t peer_set_key_runtime_wakelock;
 	bool is_key_wakelock_set;
 	struct element_info assoc_rsp;
+	enum phy_ch_width peer_ind_bw;
 };
 
 /**
@@ -1829,4 +1843,61 @@ static inline int mlme_sr_is_enable(struct wlan_objmgr_vdev *vdev)
 	return 0;
 }
 #endif /* WLAN_FEATURE_SR */
+
+/**
+ * mlme_peer_oper_mode_change_event_handler() - Handle peer oper mode event
+ * @scn: handle
+ * @event: Event data received from firmware
+ * @len: Event data length received from firmware
+ */
+int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn, uint8_t *event,
+					     uint32_t len);
+
+/**
+ * wmi_extract_peer_oper_mode_event() - Extract the peer operating
+ * mode change event and update the new bandwidth
+ * @wmi_handle: wmi handle
+ * @event: Event data received from firmware
+ * @len: Event data length received from firmware
+ * @data: Extract the event and fill in data
+ */
+QDF_STATUS
+wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle,
+				 uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data);
+
+/**
+ * wlan_mlme_register_rx_ops - Target IF mlme API to register mlme
+ * related rx op.
+ * @rx_ops: Pointer to rx ops fp struct
+ *
+ * Return: none
+ */
+void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops);
+
+/**
+ * mlme_get_rx_ops - Get mlme rx ops from psoc
+ * @psoc: psoc
+ *
+ * Return: Pointer to rx ops fp struct
+ */
+struct wlan_mlme_rx_ops *
+mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc);
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * wlan_mlme_register_common_events - Wrapper to register common events
+ * @psoc: psoc
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc);
+#else
+static inline QDF_STATUS
+wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #endif

+ 108 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -37,6 +37,8 @@
 #include "wlan_scan_api.h"
 #include "wlan_mlme_vdev_mgr_interface.h"
 #include "wlan_vdev_mgr_utils_api.h"
+#include <wmi_unified_priv.h>
+#include <target_if.h>
 
 #define NUM_OF_SOUNDING_DIMENSIONS     1 /*Nss - 1, (Nss = 2 for 2x2)*/
 
@@ -44,6 +46,29 @@
 #define MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME 40
 #define MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME 110
 
+struct wlan_mlme_rx_ops *
+mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_mlme_psoc_ext_obj *psoc_ext_priv;
+
+	if (!psoc) {
+		mlme_err("psoc object is NULL");
+		return NULL;
+	}
+	psoc_ext_priv = wlan_psoc_mlme_get_ext_hdl(psoc);
+	if (!psoc_ext_priv) {
+		mlme_err("psoc legacy private object is NULL");
+		return NULL;
+	}
+
+	return &psoc_ext_priv->mlme_rx_ops;
+}
+
+void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops)
+{
+	rx_ops->peer_oper_mode_eventid = wlan_mlme_set_peer_indicated_ch_width;
+}
+
 struct wlan_mlme_psoc_ext_obj *mlme_get_psoc_ext_obj_fl(
 			       struct wlan_objmgr_psoc *psoc,
 			       const char *func, uint32_t line)
@@ -898,6 +923,7 @@ mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer,
 	qdf_wake_lock_create(&peer_priv->peer_set_key_wakelock, "peer_set_key");
 	qdf_runtime_lock_init(&peer_priv->peer_set_key_runtime_wakelock);
 	peer_priv->is_key_wakelock_set = false;
+	peer_priv->peer_ind_bw = CH_WIDTH_INVALID;
 
 	return status;
 }
@@ -5330,3 +5356,85 @@ QDF_STATUS wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+QDF_STATUS
+wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle,
+				 uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data)
+{
+	if (wmi_handle->ops->extract_peer_oper_mode_event)
+		return wmi_handle->ops->extract_peer_oper_mode_event(wmi_handle,
+								     event,
+								     len, data);
+	return QDF_STATUS_E_FAILURE;
+}
+
+int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn,
+					      uint8_t *event,
+					      uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct peer_oper_mode_event data = {0};
+	struct wlan_mlme_rx_ops *mlme_rx_ops;
+	QDF_STATUS qdf_status;
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		mlme_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	qdf_status = wmi_extract_peer_oper_mode_event(wmi_handle, event,
+						      len, &data);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		mlme_err("parsing of event failed, %d", qdf_status);
+		return -EINVAL;
+	}
+
+	mlme_rx_ops = mlme_get_rx_ops(psoc);
+	if (!mlme_rx_ops || !mlme_rx_ops->peer_oper_mode_eventid) {
+		mlme_err("No valid roam rx ops");
+		return -EINVAL;
+	}
+
+	qdf_status = mlme_rx_ops->peer_oper_mode_eventid(psoc, &data);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		mlme_err("peer_oper_mode_change_event Failed");
+		return -EINVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!handle) {
+		mlme_err("handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Register for peer operating mode change devent */
+	ret = wmi_unified_register_event_handler(handle,
+				wmi_peer_oper_mode_change_event_id,
+				mlme_peer_oper_mode_change_event_handler,
+				WMI_RX_SERIALIZER_CTX);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		mlme_err("wmi event(%u) registration failed, ret: %d",
+			      wmi_peer_oper_mode_change_event_id, ret);
+		return QDF_STATUS_E_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+#endif

+ 1 - 0
components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c

@@ -1935,6 +1935,7 @@ QDF_STATUS psoc_mlme_ext_hdl_create(struct psoc_mlme_obj *psoc_mlme)
 			&psoc_mlme->ext_psoc_ptr->wfa_testcmd.tx_ops);
 	target_if_cm_roam_register_rx_ops(
 			&psoc_mlme->ext_psoc_ptr->rso_rx_ops);
+	wlan_mlme_register_rx_ops(&psoc_mlme->ext_psoc_ptr->mlme_rx_ops);
 
 	return QDF_STATUS_SUCCESS;
 }

+ 22 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -3524,6 +3524,28 @@ wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+/**
+ * wlan_mlme_set_peer_indicated_ch_width() - Set peer indicated channel width
+ * @psoc: pointer to psoc object
+ * @data: Pointer to peer operating mode change event status
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data);
+
+/**
+ * wlan_mlme_get_peer_indicated_ch_width() - Get peer indicated channel width
+ * @psoc: pointer to psoc object
+ * @data: Pointer to peer operating mode change event status
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data);
+
 /**
  * wlan_mlme_set_ft_over_ds() - Update ft_over_ds
  * @psoc: pointer to psoc object

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

@@ -3030,4 +3030,34 @@ struct sap_sel_ch_info {
 	struct sap_ch_info *ch_info;
 	uint8_t num_ch;
 };
+
+/**
+ * enum mlme_peer_oper_mode_ind - Peer mode indication type
+ * @mlme_peer_ind_smps: spatial multiplexing power save
+ * @mlme_peer_ind_omn: Operating mode notification
+ * @mlme_peer_ind_omi: Operating mode indication
+ */
+enum mlme_peer_oper_mode_ind {
+	mlme_peer_ind_smps,
+	mlme_peer_ind_omn,
+	mlme_peer_ind_omi,
+};
+
+/**
+ * struct peer_oper_mode_event - structure for peer oper mode indication data
+ * @peer_mac_address: mac address of peer
+ * @ind_type: indication type of type @enum mlme_peer_oper_mode_ind
+ * @new_rxnss: New Rx NSS
+ * @new_bw: New bandwidth
+ * @new_txnss: New Tx NSS, valid only for mlme_peer_ind_omi
+ * @new_disablemu: Disabled MU mode, valid only for mlme_peer_ind_omi
+ */
+struct peer_oper_mode_event {
+	struct qdf_mac_addr peer_mac_address;
+	uint32_t ind_type;
+	uint32_t new_rxnss;
+	uint32_t new_bw;
+	uint32_t new_txnss;
+	uint32_t new_disablemu;
+};
 #endif

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

@@ -5524,6 +5524,88 @@ wlan_mlme_get_self_bss_roam(struct wlan_objmgr_psoc *psoc,
 }
 #endif
 
+QDF_STATUS
+wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data)
+{
+	struct wlan_objmgr_peer *peer;
+	struct peer_mlme_priv_obj *peer_priv;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!data) {
+		mlme_err("Data params is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes,
+					   WLAN_MLME_NB_ID);
+	if (!peer) {
+		mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(data->peer_mac_address.bytes));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_MLME);
+	if (!peer_priv) {
+		mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(peer->macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto done;
+	}
+
+	if (peer_priv->peer_ind_bw == CH_WIDTH_INVALID) {
+		status = QDF_STATUS_E_INVAL;
+		goto done;
+	}
+
+	data->new_bw = peer_priv->peer_ind_bw;
+
+done:
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID);
+
+	return status;
+}
+
+QDF_STATUS
+wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc,
+				      struct peer_oper_mode_event *data)
+{
+	struct wlan_objmgr_peer *peer;
+	struct peer_mlme_priv_obj *peer_priv;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!data) {
+		mlme_err("Data params is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes,
+					   WLAN_MLME_NB_ID);
+	if (!peer) {
+		mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(data->peer_mac_address.bytes));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer,
+							  WLAN_UMAC_COMP_MLME);
+	if (!peer_priv) {
+		mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT,
+			 QDF_MAC_ADDR_REF(peer->macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto done;
+	}
+
+	peer_priv->peer_ind_bw =
+			target_if_wmi_chan_width_to_phy_ch_width(data->new_bw);
+
+done:
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID);
+
+	return status;
+}
+
 QDF_STATUS
 wlan_mlme_set_ft_over_ds(struct wlan_objmgr_psoc *psoc,
 			 uint8_t ft_over_ds_enable)

+ 43 - 0
components/wmi/src/wmi_unified_roam_tlv.c

@@ -3488,6 +3488,48 @@ extract_roam_candidate_frame_tlv(wmi_unified_t wmi_handle, uint8_t *event,
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+static QDF_STATUS
+extract_peer_oper_mode_event_tlv(wmi_unified_t wmi_handle, uint8_t *event,
+				 uint32_t len,
+				 struct peer_oper_mode_event *data)
+{
+	WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *param_buf = NULL;
+	wmi_peer_oper_mode_change_event_fixed_param *params = NULL;
+
+	if (!event || !len) {
+		wmi_debug("Empty operating mode change event");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	param_buf = (WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wmi_err("Received null buf from target");
+		return -EINVAL;
+	}
+
+	params =
+		(wmi_peer_oper_mode_change_event_fixed_param *)param_buf->fixed_param;
+
+	WMI_MAC_ADDR_TO_CHAR_ARRAY(&params->peer_mac_address,
+				   data->peer_mac_address.bytes);
+	data->ind_type = params->ind_type;
+	data->new_rxnss = params->new_rxnss;
+	data->new_bw = params->new_bw;
+	data->new_txnss = params->new_txnss;
+	data->new_disablemu = params->new_disablemu;
+
+	wmi_debug("peer_mac_addr: " QDF_MAC_ADDR_FMT " ind_type: %d new_rxnss: %d new_bw: %d new_txnss: %d new_disablemu: %d",
+		  QDF_MAC_ADDR_REF(data->peer_mac_address.bytes),
+		  data->ind_type,
+		  data->new_rxnss,
+		  data->new_bw,
+		  data->new_txnss,
+		  data->new_disablemu);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
 #ifdef WLAN_VENDOR_HANDOFF_CONTROL
 /**
  * convert_roam_vendor_control_param() - Function to convert
@@ -4125,6 +4167,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 	ops->send_vdev_set_pcl_cmd = send_vdev_set_pcl_cmd_tlv;
 	ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv;
 	ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv;
+	ops->extract_peer_oper_mode_event = extract_peer_oper_mode_event_tlv;
 	wmi_roam_offload_attach_vendor_handoff_tlv(ops);
 	wmi_roam_offload_attach_mlo_tlv(ops);
 }

+ 2 - 0
core/wma/src/wma_main.c

@@ -3580,6 +3580,8 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc,
 
 	wlan_mlme_set_assoc_sta_limit(psoc, cds_cfg->max_station);
 
+	wlan_mlme_register_common_events(psoc);
+
 	/* initialize default target config */
 	wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_psoc_info);
 	if (!wlan_res_cfg) {