Browse Source

qcacld-3.0: Add support to handle twt_notify event

Add support to handle twt_notify event. Firmware can
terminate a TWT session without a Host trigger due to internal
reasons. In that case it sends an event to notify that it is
again ready for a TWT session setup.

Change-Id: I3508687cee93e16a26221a1bc7ad9c626a4f4523
CRs-Fixed: 2847158
Rajasekaran Kalidoss 4 years ago
parent
commit
741def98ba

+ 74 - 0
core/hdd/src/wlan_hdd_twt.c

@@ -2310,6 +2310,79 @@ static int hdd_twt_resume_session(struct hdd_adapter *adapter,
 	return ret;
 }
 
+/**
+ * hdd_twt_notify_pack_nlmsg() - pack the skb with
+ * twt notify event from firmware
+ * @reply_skb: skb to store the response
+ *
+ * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
+ * on failure
+ */
+static QDF_STATUS
+hdd_twt_notify_pack_nlmsg(struct sk_buff *reply_skb)
+{
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
+		       QCA_WLAN_TWT_SETUP_READY_NOTIFY)) {
+		hdd_err("Failed to put TWT notify operation");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hdd_twt_notify_cb() - callback function
+ * to get twt notify event
+ * @psoc: Pointer to global psoc
+ * @params: Pointer to notify param event buffer
+ *
+ * Return: None
+ */
+static void
+hdd_twt_notify_cb(struct wlan_objmgr_psoc *psoc,
+		  struct wmi_twt_notify_event_param *params)
+{
+	struct hdd_adapter *adapter =
+		wlan_hdd_get_adapter_from_vdev(psoc, params->vdev_id);
+	struct wireless_dev *wdev;
+	struct sk_buff *twt_vendor_event;
+	size_t data_len;
+	QDF_STATUS status;
+
+	hdd_enter();
+
+	if (hdd_validate_adapter(adapter))
+		return;
+
+	wdev = adapter->dev->ieee80211_ptr;
+
+	data_len = NLA_HDRLEN;
+	data_len += nla_total_size(sizeof(u8));
+
+	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
+				adapter->wdev.wiphy, wdev,
+				data_len,
+				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
+				GFP_KERNEL);
+	if (!twt_vendor_event) {
+		hdd_err("Notify skb alloc failed");
+		return;
+	}
+
+	hdd_debug("Notify vdev_id %d", params->vdev_id);
+
+	status = hdd_twt_notify_pack_nlmsg(twt_vendor_event);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to pack nl notify event");
+		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
+		return;
+	}
+
+	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
+
+	hdd_exit();
+}
+
 /**
  * hdd_twt_configure - Process the TWT
  * operation in the received vendor command
@@ -2720,6 +2793,7 @@ void wlan_hdd_twt_init(struct hdd_context *hdd_ctx)
 	twt_cb.twt_del_dialog_cb = hdd_twt_del_dialog_comp_cb;
 	twt_cb.twt_pause_dialog_cb = hdd_twt_pause_dialog_comp_cb;
 	twt_cb.twt_resume_dialog_cb = hdd_twt_resume_dialog_comp_cb;
+	twt_cb.twt_notify_cb = hdd_twt_notify_cb;
 	status = sme_register_twt_callbacks(hdd_ctx->mac_handle, &twt_cb);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Register twt enable complete failed");

+ 3 - 2
core/mac/inc/wni_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021 The Linux Foundation. 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
@@ -250,7 +250,8 @@ enum eWniMsgTypes {
 	eWNI_SME_TWT_PAUSE_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 167,
 	eWNI_SME_TWT_RESUME_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 168,
 	eWNI_SME_TWT_NUDGE_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 169,
-	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 170
+	eWNI_SME_TWT_NOTIFY_EVENT = SIR_SME_MSG_TYPES_BEGIN + 170,
+	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 171
 };
 
 typedef struct sAniCfgTxRateCtrs {

+ 2 - 1
core/sme/inc/sme_api.h

@@ -3675,7 +3675,8 @@ QDF_STATUS sme_clear_twt_complete_cb(mac_handle_t mac_handle);
  * @mac_handle: MAC handle
  * @twt_cb: TWT callbacks
  *
- * Return: QDF Status
+ * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
+ * on failure
  */
 QDF_STATUS sme_register_twt_callbacks(mac_handle_t mac_handle,
 				      struct twt_callbacks *twt_cb);

+ 13 - 1
core/sme/inc/sme_internal.h

@@ -207,13 +207,22 @@ void (*twt_resume_dialog_cb)(struct wlan_objmgr_psoc *psoc,
 			     struct wmi_twt_resume_dialog_complete_event_param *params);
 
 /**
- * struct twt_callbacks  - TWT response callback pointers
+ * typedef twt_notify_cb - TWT notify callback signature.
+ * @psoc: Pointer to global psoc
+ * @params: TWT twt notify event parameters.
+ */
+typedef
+void (*twt_notify_cb)(struct wlan_objmgr_psoc *psoc,
+		      struct wmi_twt_notify_event_param *params);
+/**
+ * struct twt_callbacks - TWT response callback pointers
  * @twt_enable_cb: TWT enable completion callback
  * @twt_disable_cb: TWT disable completion callback
  * @twt_add_dialog_cb: TWT add dialog completion callback
  * @twt_del_dialog_cb: TWT delete dialog completion callback
  * @twt_pause_dialog_cb: TWT pause dialog completion callback
  * @twt_resume_dialog_cb: TWT resume dialog completion callback
+ * @twt_notify_cb: TWT notify event callback
  */
 struct twt_callbacks {
 	void (*twt_enable_cb)(hdd_handle_t hdd_handle,
@@ -227,6 +236,8 @@ struct twt_callbacks {
 				    struct wmi_twt_pause_dialog_complete_event_param *params);
 	void (*twt_resume_dialog_cb)(struct wlan_objmgr_psoc *psoc,
 				     struct wmi_twt_resume_dialog_complete_event_param *params);
+	void (*twt_notify_cb)(struct wlan_objmgr_psoc *psoc,
+			      struct wmi_twt_notify_event_param *params);
 };
 #endif
 
@@ -442,6 +453,7 @@ struct sme_context {
 	twt_pause_dialog_cb twt_pause_dialog_cb;
 	twt_nudge_dialog_cb twt_nudge_dialog_cb;
 	twt_resume_dialog_cb twt_resume_dialog_cb;
+	twt_notify_cb twt_notify_cb;
 	void *twt_nudge_dialog_context;
 #endif
 #ifdef FEATURE_WLAN_APF

+ 37 - 0
core/sme/src/common/sme_api.c

@@ -72,6 +72,7 @@
 #include "wlan_mlme_twt_api.h"
 #include "parser_api.h"
 #include <../../core/src/wlan_cm_vdev_api.h>
+#include <wlan_mlme_twt_api.h>
 
 static QDF_STATUS init_sme_cmd_list(struct mac_context *mac);
 
@@ -2263,6 +2264,30 @@ sme_process_twt_resume_dialog_event(struct mac_context *mac,
 			mac->psoc, (struct qdf_mac_addr *)param->peer_macaddr,
 			param->dialog_id, WLAN_TWT_NONE);
 }
+
+/**
+ * sme_process_twt_notify_event() - Process twt ready for setup notification
+ * event from firmware
+ * @mac: Global MAC pointer
+ * @twt_notify_event: pointer to event buf containing twt notify parameters
+ *
+ * Return: None
+ */
+static void
+sme_process_twt_notify_event(struct mac_context *mac,
+			     struct wmi_twt_notify_event_param *notify_event)
+{
+	twt_notify_cb callback;
+	struct csr_roam_session *session;
+
+	session = CSR_GET_SESSION(mac, notify_event->vdev_id);
+	mlme_twt_set_wait_for_notify(mac->psoc,
+				     &session->connectedProfile.bssid,
+				     FALSE);
+	callback = mac->sme.twt_notify_cb;
+	if (callback)
+		callback(mac->psoc, notify_event);
+}
 #else
 static void
 sme_process_twt_add_dialog_event(struct mac_context *mac,
@@ -2293,6 +2318,12 @@ sme_process_twt_nudge_dialog_event(struct mac_context *mac,
 				   struct wmi_twt_nudge_dialog_complete_event_param *param)
 {
 }
+
+static void
+sme_process_twt_notify_event(struct mac_context *mac,
+			     struct wmi_twt_notify_event_param *notify_event)
+{
+}
 #endif
 
 QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
@@ -2618,6 +2649,10 @@ QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
 		sme_process_twt_nudge_dialog_event(mac, pMsg->bodyptr);
 		qdf_mem_free(pMsg->bodyptr);
 		break;
+	case eWNI_SME_TWT_NOTIFY_EVENT:
+		sme_process_twt_notify_event(mac, pMsg->bodyptr);
+		qdf_mem_free(pMsg->bodyptr);
+		break;
 	default:
 
 		if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN)
@@ -13954,6 +13989,7 @@ QDF_STATUS sme_clear_twt_complete_cb(mac_handle_t mac_handle)
 		mac->sme.twt_del_dialog_cb = NULL;
 		mac->sme.twt_pause_dialog_cb = NULL;
 		mac->sme.twt_resume_dialog_cb = NULL;
+		mac->sme.twt_notify_cb = NULL;
 		sme_release_global_lock(&mac->sme);
 
 		sme_debug("TWT: callbacks Initialized");
@@ -13976,6 +14012,7 @@ QDF_STATUS sme_register_twt_callbacks(mac_handle_t mac_handle,
 		mac->sme.twt_pause_dialog_cb = twt_cb->twt_pause_dialog_cb;
 		mac->sme.twt_resume_dialog_cb = twt_cb->twt_resume_dialog_cb;
 		mac->sme.twt_disable_cb = twt_cb->twt_disable_cb;
+		mac->sme.twt_notify_cb = twt_cb->twt_notify_cb;
 		sme_release_global_lock(&mac->sme);
 		sme_debug("TWT: callbacks registered");
 	}

+ 58 - 1
core/wma/src/wma_twt.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019-2021 The Linux Foundation. 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
@@ -442,6 +442,58 @@ wma_twt_process_resume_dialog(t_wma_handle *wma_handle,
 	return wmi_unified_twt_resume_dialog_cmd(wmi_handle, params);
 }
 
+/**
+ * wma_twt_notify_event_handler - TWT notify event handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static
+int wma_twt_notify_event_handler(void *handle, uint8_t *event, uint32_t len)
+{
+	struct wmi_twt_notify_event_param *param;
+	struct scheduler_msg sme_msg = {0};
+	tp_wma_handle wma_handle = handle;
+	wmi_unified_t wmi_handle;
+	struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE);
+	int status = -EINVAL;
+
+	if (!mac)
+		return status;
+
+	if (wma_validate_handle(wma_handle))
+		return status;
+
+	wmi_handle = (wmi_unified_t)wma_handle->wmi_handle;
+	if (!wmi_handle) {
+		wma_err("Invalid wmi handle for TWT notify event");
+		return status;
+	}
+
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param)
+		return -ENOMEM;
+
+	if (wmi_handle->ops->extract_twt_notify_event)
+		status = wmi_handle->ops->extract_twt_notify_event(wmi_handle,
+								   event,
+								   param);
+	wma_debug("Extract Notify event status:%d", status);
+
+	sme_msg.type = eWNI_SME_TWT_NOTIFY_EVENT;
+	sme_msg.bodyptr = param;
+	sme_msg.bodyval = 0;
+	status = scheduler_post_message(QDF_MODULE_ID_WMA,
+					QDF_MODULE_ID_SME,
+					QDF_MODULE_ID_SME, &sme_msg);
+	if (QDF_IS_STATUS_ERROR(status))
+		return -EINVAL;
+
+	return 0;
+}
+
 /**
  * wma_twt_resume_dialog_complete_event_handler - TWT resume dlg complete evt
  * handler
@@ -561,4 +613,9 @@ void wma_register_twt_events(tp_wma_handle wma_handle)
 				 wmi_twt_nudge_dialog_complete_event_id,
 				 wma_twt_nudge_dialog_complete_event_handler,
 				 WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler
+				(wma_handle->wmi_handle,
+				 wmi_twt_notify_event_id,
+				 wma_twt_notify_event_handler,
+				 WMA_RX_SERIALIZER_CTX);
 }