Răsfoiți Sursa

qcacld-3.0: Add support op QCA_WLAN_TWT_NUDGE

This is the new OP for vendor sub command
QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT to set twt
suspend/resume parameters.

Change-Id: If4ec03364f41ca4960673fb7a13b91a929cfe567
CRs-Fixed: 2797664
Paul Zhang 4 ani în urmă
părinte
comite
90eb7a933b

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

@@ -40,6 +40,7 @@
 #define TWT_DISABLE_COMPLETE_TIMEOUT 4000
 #define TWT_TERMINATE_COMPLETE_TIMEOUT 4000
 #define TWT_PAUSE_COMPLETE_TIMEOUT 4000
+#define TWT_NUDGE_COMPLETE_TIMEOUT 4000
 #define TWT_RESUME_COMPLETE_TIMEOUT 4000
 
 #define TWT_FLOW_TYPE_ANNOUNCED 0
@@ -62,6 +63,18 @@ struct twt_pause_dialog_comp_ev_priv {
 	struct wmi_twt_pause_dialog_complete_event_param pause_dialog_comp_ev_buf;
 };
 
+/**
+ * struct twt_nudge_dialog_comp_ev_priv - private struct for twt nudge dialog
+ * @nudge_dialog_comp_ev_buf: buffer from TWT nudge dialog complete_event
+ *
+ * This TWT nudge dialog private structure is registered with os_if to
+ * retrieve the TWT nudge dialog response event buffer.
+ */
+struct twt_nudge_dialog_comp_ev_priv {
+	struct wmi_twt_nudge_dialog_complete_event_param
+						nudge_dialog_comp_ev_buf;
+};
+
 /**
  * struct twt_resume_dialog_comp_ev_priv - private struct for twt resume dialog
  * @resume_dialog_comp_ev_buf: buffer from TWT resume dialog complete_event
@@ -126,6 +139,14 @@ wlan_hdd_wifi_twt_config_policy[
 			.type = NLA_NESTED},
 };
 
+static const struct nla_policy
+qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 },
+	[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR,
+};
+
 /**
  * hdd_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd
  * @req_type: twt setup request type
@@ -785,6 +806,37 @@ wmi_twt_pause_status_to_vendor_twt_status(enum WMI_HOST_PAUSE_TWT_STATUS status)
 	}
 }
 
+/**
+ * wmi_twt_nudge_status_to_vendor_twt_status() - convert from
+ * WMI_HOST_NUDGE_TWT_STATUS to qca_wlan_vendor_twt_status
+ * @status: WMI_HOST_NUDGE_TWT_STATUS value from firmware
+ *
+ * Return: qca_wlan_vendor_twt_status values corresponding
+ * to the firmware failure status
+ */
+static int
+wmi_twt_nudge_status_to_vendor_twt_status(enum WMI_HOST_NUDGE_TWT_STATUS status)
+{
+	switch (status) {
+	case WMI_HOST_NUDGE_TWT_STATUS_OK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
+	case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_NOT_EXIST:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
+	case WMI_HOST_NUDGE_TWT_STATUS_INVALID_PARAM:
+		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
+	case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_BUSY:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
+	case WMI_HOST_NUDGE_TWT_STATUS_NO_RESOURCE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
+	case WMI_HOST_NUDGE_TWT_STATUS_NO_ACK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
+	case WMI_HOST_NUDGE_TWT_STATUS_UNKNOWN_ERROR:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	default:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	}
+}
+
 /**
  * wmi_twt_add_cmd_to_vendor_twt_resp_type() - convert from
  * WMI_HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type
@@ -1468,6 +1520,43 @@ hdd_twt_pause_dialog_comp_cb(void *context,
 	hdd_exit();
 }
 
+/**
+ * hdd_twt_nudge_dialog_comp_cb() - callback function
+ * to get twt nudge command complete event
+ * @context: private context
+ * @params: Pointer to nudge dialog complete event buffer
+ *
+ * Return: None
+ */
+static void
+hdd_twt_nudge_dialog_comp_cb(void *context,
+		       struct wmi_twt_nudge_dialog_complete_event_param *params)
+{
+	struct osif_request *request;
+	struct twt_nudge_dialog_comp_ev_priv *priv;
+
+	hdd_enter();
+
+	request = osif_request_get(context);
+	if (!request) {
+		hdd_err("Obsolete request");
+		return;
+	}
+
+	priv = osif_request_priv(request);
+
+	priv->nudge_dialog_comp_ev_buf = *params;
+	osif_request_complete(request);
+	osif_request_put(request);
+
+	hdd_debug("TWT: nudge dialog_id:%d, status:%d vdev_id %d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, params->dialog_id,
+		  params->status, params->vdev_id,
+		  QDF_MAC_ADDR_REF(params->peer_macaddr));
+
+	hdd_exit();
+}
+
 /**
  * hdd_twt_pause_pack_resp_nlmsg() - pack the skb with
  * firmware response for twt pause command
@@ -1499,6 +1588,38 @@ hdd_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_twt_nudge_pack_resp_nlmsg() - pack the skb with
+ * firmware response for twt nudge command
+ * @reply_skb: skb to store the response
+ * @params: Pointer to nudge dialog complete event buffer
+ *
+ * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE
+ * on failure
+ */
+static QDF_STATUS
+hdd_twt_nudge_pack_resp_nlmsg(struct sk_buff *reply_skb,
+		      struct wmi_twt_nudge_dialog_complete_event_param *params)
+{
+	int vendor_status;
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID,
+		       params->dialog_id)) {
+		hdd_debug("TWT: Failed to put dialog_id");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	vendor_status =
+		     wmi_twt_nudge_status_to_vendor_twt_status(params->status);
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS,
+		       vendor_status)) {
+		hdd_err("TWT: Failed to put QCA_WLAN_TWT_NUDGE status");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /**
  * hdd_send_twt_pause_dialog_cmd() - Send TWT pause dialog command to target
  * @hdd_ctx: HDD Context
@@ -1638,6 +1759,164 @@ static int hdd_twt_pause_session(struct hdd_adapter *adapter,
 	return ret;
 }
 
+/**
+ * hdd_send_twt_nudge_dialog_cmd() - Send TWT nudge dialog command to target
+ * @hdd_ctx: HDD Context
+ * @twt_params: Pointer to nudge dialog cmd params structure
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static
+int hdd_send_twt_nudge_dialog_cmd(struct hdd_context *hdd_ctx,
+			struct wmi_twt_nudge_dialog_cmd_param *twt_params)
+{
+	struct wmi_twt_nudge_dialog_complete_event_param *comp_ev_params;
+	struct twt_nudge_dialog_comp_ev_priv *priv;
+	static const struct osif_request_params osif_req_params = {
+		.priv_size = sizeof(*priv),
+		.timeout_ms = TWT_NUDGE_COMPLETE_TIMEOUT,
+		.dealloc = NULL,
+	};
+	struct osif_request *request;
+	struct sk_buff *reply_skb = NULL;
+	QDF_STATUS status;
+	void *cookie;
+	int skb_len;
+	int ret;
+
+	request = osif_request_alloc(&osif_req_params);
+	if (!request) {
+		hdd_err("twt osif request allocation failure");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	cookie = osif_request_cookie(request);
+
+	status = sme_nudge_dialog_cmd(hdd_ctx->mac_handle,
+				      hdd_twt_nudge_dialog_comp_cb,
+				      twt_params, cookie);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to send nudge dialog command");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+
+	ret = osif_request_wait_for_response(request);
+	if (ret) {
+		hdd_err("twt: nudge dialog req timedout");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	priv = osif_request_priv(request);
+	comp_ev_params = &priv->nudge_dialog_comp_ev_buf;
+
+	skb_len = hdd_get_twt_event_len();
+	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
+							     skb_len);
+	if (!reply_skb) {
+		hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	status = hdd_twt_nudge_pack_resp_nlmsg(reply_skb, comp_ev_params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to pack nl nudge dialog response");
+		ret = qdf_status_to_os_return(status);
+		goto err;
+	}
+
+	ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
+
+err:
+	if (request)
+		osif_request_put(request);
+	if (ret && reply_skb)
+		kfree_skb(reply_skb);
+	return ret;
+}
+
+/**
+ * hdd_twt_nudge_session - Process TWT nudge operation
+ * in the received vendor command and send it to firmware
+ * @adapter: adapter pointer
+ * @twt_param_attr: nl attributes
+ *
+ * Handles QCA_WLAN_TWT_NUDGE
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static int hdd_twt_nudge_session(struct hdd_adapter *adapter,
+				 struct nlattr *twt_param_attr)
+{
+	struct hdd_station_ctx *hdd_sta_ctx;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1];
+	struct wmi_twt_nudge_dialog_cmd_param params = {0};
+	int id;
+	int ret;
+
+	if (adapter->device_mode != QDF_STA_MODE &&
+	    adapter->device_mode != QDF_P2P_CLIENT_MODE) {
+		return -EOPNOTSUPP;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (hdd_sta_ctx->conn_info.conn_state != eConnectionState_Associated) {
+		hdd_err_rl("Invalid state, vdev %d mode %d state %d",
+			   adapter->vdev_id, adapter->device_mode,
+			   hdd_sta_ctx->conn_info.conn_state);
+		return -EINVAL;
+	}
+
+	params.vdev_id = adapter->vdev_id;
+
+	ret = wlan_cfg80211_nla_parse_nested(tb,
+				      QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX,
+				      twt_param_attr,
+				      qca_wlan_vendor_twt_nudge_dialog_policy);
+	if (ret)
+		return ret;
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR;
+	if (tb[id]) {
+		nla_memcpy(params.peer_macaddr, tb[id], QDF_MAC_ADDR_SIZE);
+		hdd_debug("peer mac_addr "QDF_MAC_ADDR_FMT,
+			  QDF_MAC_ADDR_REF(params.peer_macaddr));
+	}
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID;
+	if (!tb[id]) {
+		hdd_debug("TWT: FLOW_ID not specified.");
+		return -EINVAL;
+	}
+	params.dialog_id = nla_get_u8(tb[id]);
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME;
+	if (!tb[id]) {
+		hdd_debug("TWT: WAKE_TIME not specified.");
+		return -EINVAL;
+	}
+	params.suspend_duration = nla_get_u32(tb[id]);
+
+	id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE;
+	if (!tb[id]) {
+		hdd_debug("TWT: NEXT_TWT_SIZE not specified.");
+		return -EINVAL;
+	}
+	params.next_twt_size = nla_get_u32(tb[id]);
+
+	hdd_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id,
+		  params.dialog_id);
+	hdd_debug("twt_nudge: suspend_duration %d next_twt_size %d",
+		  params.suspend_duration, params.next_twt_size);
+
+	ret = hdd_send_twt_nudge_dialog_cmd(adapter->hdd_ctx, &params);
+
+	return ret;
+}
+
 /**
  * hdd_twt_resume_dialog_comp_cb() - callback function
  * to get twt resume command complete event
@@ -1918,6 +2197,9 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
 	case QCA_WLAN_TWT_RESUME:
 		ret = hdd_twt_resume_session(adapter, twt_param_attr);
 		break;
+	case QCA_WLAN_TWT_NUDGE:
+		ret = hdd_twt_nudge_session(adapter, twt_param_attr);
+		break;
 	default:
 		hdd_err("Invalid TWT Operation");
 		ret = -EINVAL;

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

@@ -249,7 +249,8 @@ enum eWniMsgTypes {
 	eWNI_SME_TWT_DEL_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 166,
 	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_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 169
+	eWNI_SME_TWT_NUDGE_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 169,
+	eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 170
 };
 
 typedef struct sAniCfgTxRateCtrs {

+ 1 - 0
core/mac/src/include/sir_params.h

@@ -664,6 +664,7 @@ enum halmsgtype {
 	SIR_HAL_TWT_PAUSE_DIALOG_REQUEST  = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 419),
 	SIR_HAL_TWT_RESUME_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 420),
 	SIR_HAL_PEER_CREATE_REQ           = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 421),
+	SIR_HAL_TWT_NUDGE_DIALOG_REQUEST  = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 422),
 
 
 	SIR_HAL_MSG_TYPES_END               = (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF),

+ 1 - 0
core/mac/src/sys/legacy/src/utils/src/mac_trace.c

@@ -558,6 +558,7 @@ uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg)
 		CASE_RETURN_STRING(WMA_TWT_DEL_DIALOG_REQUEST);
 		CASE_RETURN_STRING(WMA_TWT_PAUSE_DIALOG_REQUEST);
 		CASE_RETURN_STRING(WMA_TWT_RESUME_DIALOG_REQUEST);
+		CASE_RETURN_STRING(WMA_TWT_NUDGE_DIALOG_REQUEST);
 #endif
 		CASE_RETURN_STRING(WMA_RX_SCAN_EVENT);
 		CASE_RETURN_STRING(WMA_RX_CHN_STATUS_EVENT);

+ 17 - 0
core/sme/inc/sme_api.h

@@ -3737,6 +3737,23 @@ sme_pause_dialog_cmd(mac_handle_t mac_handle,
 		     struct wmi_twt_pause_dialog_cmd_param *twt_params,
 		     void *context);
 
+/**
+ * sme_nudge_dialog_cmd() - Register callback and send TWT nudge dialog
+ * command to firmware
+ * @mac_handle: MAC handle
+ * @twt_nudge_dialog_cb: Function callback to handle nudge_dialog event
+ * @twt_params: TWT nudge dialog parameters
+ * @context: os_if_request cookie
+ *
+ * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
+ * on failure
+ */
+QDF_STATUS
+sme_nudge_dialog_cmd(mac_handle_t mac_handle,
+		     twt_nudge_dialog_cb nudge_dialog_cb,
+		     struct wmi_twt_nudge_dialog_cmd_param *twt_params,
+		     void *context);
+
 /**
  * sme_resume_dialog_cmd() - Register callback and send TWT resume dialog
  * command to firmware

+ 12 - 0
core/sme/inc/sme_internal.h

@@ -188,6 +188,16 @@ typedef
 void (*twt_pause_dialog_cb)(void *context,
 			    struct wmi_twt_pause_dialog_complete_event_param *params);
 
+/**
+ * typedef twt_nudge_dialog_cb - TWT nudge dialog callback signature.
+ * @context: Opaque context that the client can use to associate the
+ *           callback with the request.
+ * @params: TWT nudge dialog complete event parameters.
+ */
+typedef
+void (*twt_nudge_dialog_cb)(void *context,
+		      struct wmi_twt_nudge_dialog_complete_event_param *params);
+
 /**
  * typedef twt_resume_dialog_cb - TWT resume dialog callback signature.
  * @context: Opaque context that the client can use to associate the
@@ -409,10 +419,12 @@ struct sme_context {
 	twt_add_dialog_cb twt_add_dialog_cb;
 	twt_del_dialog_cb twt_del_dialog_cb;
 	twt_pause_dialog_cb twt_pause_dialog_cb;
+	twt_nudge_dialog_cb twt_nudge_dialog_cb;
 	twt_resume_dialog_cb twt_resume_dialog_cb;
 	void *twt_add_dialog_context;
 	void *twt_del_dialog_context;
 	void *twt_pause_dialog_context;
+	void *twt_nudge_dialog_context;
 	void *twt_resume_dialog_context;
 #endif
 #ifdef FEATURE_WLAN_APF

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

@@ -2121,6 +2121,28 @@ sme_process_twt_pause_dialog_event(struct mac_context *mac,
 		callback(context, param);
 }
 
+/**
+ * sme_process_twt_nudge_dialog_event() - Process twt nudge dialog event
+ * response from firmware
+ * @mac: Global MAC pointer
+ * @param: pointer to wmi_twt_nudge_dialog_complete_event_param buffer
+ *
+ * Return: None
+ */
+static void
+sme_process_twt_nudge_dialog_event(struct mac_context *mac,
+			struct wmi_twt_nudge_dialog_complete_event_param *param)
+{
+	twt_nudge_dialog_cb callback;
+	void *context;
+
+	callback = mac->sme.twt_nudge_dialog_cb;
+	context = mac->sme.twt_nudge_dialog_context;
+	mac->sme.twt_nudge_dialog_cb = NULL;
+	if (callback)
+		callback(context, param);
+}
+
 /**
  * sme_process_twt_resume_dialog_event() - Process twt resume dialog event
  * response from firmware
@@ -2167,6 +2189,12 @@ sme_process_twt_resume_dialog_event(struct mac_context *mac,
 				    struct wmi_twt_resume_dialog_complete_event_param *param)
 {
 }
+
+static void
+sme_process_twt_nudge_dialog_event(struct mac_context *mac,
+				   struct wmi_twt_nudge_dialog_complete_event_param *param)
+{
+}
 #endif
 
 QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
@@ -2488,6 +2516,10 @@ QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg)
 		sme_process_twt_resume_dialog_event(mac, pMsg->bodyptr);
 		qdf_mem_free(pMsg->bodyptr);
 		break;
+	case eWNI_SME_TWT_NUDGE_DIALOG_EVENT:
+		sme_process_twt_nudge_dialog_event(mac, pMsg->bodyptr);
+		qdf_mem_free(pMsg->bodyptr);
+		break;
 	default:
 
 		if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN)
@@ -14466,6 +14498,67 @@ sme_pause_dialog_cmd(mac_handle_t mac_handle,
 	return status;
 }
 
+QDF_STATUS
+sme_nudge_dialog_cmd(mac_handle_t mac_handle,
+		     twt_nudge_dialog_cb nudge_dialog_cb,
+		     struct wmi_twt_nudge_dialog_cmd_param *twt_params,
+		     void *context)
+{
+	struct mac_context *mac = MAC_CONTEXT(mac_handle);
+	struct wmi_twt_nudge_dialog_cmd_param *cmd_params;
+	struct scheduler_msg twt_msg = {0};
+	QDF_STATUS status;
+	void *wma_handle;
+
+	SME_ENTER();
+	wma_handle = cds_get_context(QDF_MODULE_ID_WMA);
+	if (!wma_handle) {
+		sme_err("wma_handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*bodyptr should be freeable*/
+	cmd_params = qdf_mem_malloc(sizeof(*cmd_params));
+	if (!cmd_params)
+		return QDF_STATUS_E_NOMEM;
+
+	qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params));
+
+	status = sme_acquire_global_lock(&mac->sme);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		sme_err("failed to register nudge dialog callback");
+		qdf_mem_free(cmd_params);
+		return status;
+	}
+
+	if (mac->sme.twt_nudge_dialog_cb) {
+		sme_release_global_lock(&mac->sme);
+		qdf_mem_free(cmd_params);
+		sme_err_rl("TWT: Command in progress - STATUS E_BUSY");
+		return QDF_STATUS_E_BUSY;
+	}
+
+	/* Serialize the req through MC thread */
+	mac->sme.twt_nudge_dialog_cb = nudge_dialog_cb;
+	mac->sme.twt_nudge_dialog_context = context;
+	twt_msg.bodyptr = cmd_params;
+	twt_msg.type = WMA_TWT_NUDGE_DIALOG_REQUEST;
+	sme_release_global_lock(&mac->sme);
+
+	status = scheduler_post_message(QDF_MODULE_ID_SME,
+					QDF_MODULE_ID_WMA,
+					QDF_MODULE_ID_WMA, &twt_msg);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			  FL("Post twt nudge dialog msg fail"));
+		qdf_mem_free(cmd_params);
+	}
+
+	SME_EXIT();
+	return status;
+}
+
 QDF_STATUS
 sme_resume_dialog_cmd(mac_handle_t mac_handle,
 		      twt_resume_dialog_cb resume_dialog_cb,

+ 21 - 0
core/wma/inc/wma_twt.h

@@ -117,6 +117,18 @@ QDF_STATUS
 wma_twt_process_pause_dialog(t_wma_handle *wma_handle,
 			     struct wmi_twt_pause_dialog_cmd_param *params);
 
+/**
+ * wma_twt_process_nudge_dialog() - Process nudge dialog command
+ * @wma_handle: wma handle
+ * @params: nudge dialog configuration parameters
+ *
+ * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code
+ * on failure
+ */
+QDF_STATUS
+wma_twt_process_nudge_dialog(t_wma_handle *wma_handle,
+			     struct wmi_twt_nudge_dialog_cmd_param *params);
+
 /**
  * wma_twt_process_resume_dialog() - Process resume dialog command
  * @wma_handle: wma handle
@@ -195,6 +207,15 @@ wma_twt_process_pause_dialog(t_wma_handle *wma_handle,
 	return QDF_STATUS_E_INVAL;
 }
 
+static inline QDF_STATUS
+wma_twt_process_nudge_dialog(t_wma_handle *wma_handle,
+			     struct wmi_twt_nudge_dialog_cmd_param *params)
+{
+	wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled");
+
+	return QDF_STATUS_E_INVAL;
+}
+
 static inline QDF_STATUS
 wma_twt_process_resume_dialog(t_wma_handle *wma_handle,
 			      struct wmi_twt_resume_dialog_cmd_param *params)

+ 1 - 0
core/wma/inc/wma_types.h

@@ -439,6 +439,7 @@ enum wmamsgtype {
 	WMA_TWT_PAUSE_DIALOG_REQUEST = SIR_HAL_TWT_PAUSE_DIALOG_REQUEST,
 	WMA_TWT_RESUME_DIALOG_REQUEST =  SIR_HAL_TWT_RESUME_DIALOG_REQUEST,
 	WMA_PEER_CREATE_REQ = SIR_HAL_PEER_CREATE_REQ,
+	WMA_TWT_NUDGE_DIALOG_REQUEST = SIR_HAL_TWT_NUDGE_DIALOG_REQUEST,
 };
 
 #define WMA_DATA_STALL_TRIGGER 6

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

@@ -8988,6 +8988,10 @@ static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg)
 		wma_twt_process_resume_dialog(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case WMA_TWT_NUDGE_DIALOG_REQUEST:
+		wma_twt_process_nudge_dialog(wma_handle, msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	default:
 		wma_debug("Unhandled WMA message of type %d", msg->type);
 		if (msg->bodyptr)

+ 76 - 0
core/wma/src/wma_twt.c

@@ -303,6 +303,24 @@ wma_twt_process_pause_dialog(t_wma_handle *wma_handle,
 	return wmi_unified_twt_pause_dialog_cmd(wmi_handle, params);
 }
 
+QDF_STATUS
+wma_twt_process_nudge_dialog(t_wma_handle *wma_handle,
+			     struct wmi_twt_nudge_dialog_cmd_param *params)
+{
+	wmi_unified_t wmi_handle;
+
+	if (wma_validate_handle(wma_handle))
+		return QDF_STATUS_E_INVAL;
+
+	wmi_handle = (wmi_unified_t)wma_handle->wmi_handle;
+	if (!wmi_handle) {
+		wma_err("Invalid wmi handle, twt nudge dialog failed");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return wmi_unified_twt_nudge_dialog_cmd(wmi_handle, params);
+}
+
 /**
  * wma_twt_pause_dialog_complete_event_handler - TWT pause dlg complete evt
  * handler
@@ -355,6 +373,59 @@ int wma_twt_pause_dialog_complete_event_handler(void *handle, uint8_t *event,
 	return status;
 }
 
+/**
+ * wma_twt_nudge_dialog_complete_event_handler - TWT nudge dlg complete evt
+ * handler
+ * @handle: wma handle
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static
+int wma_twt_nudge_dialog_complete_event_handler(void *handle, uint8_t *event,
+						uint32_t len)
+{
+	struct wmi_twt_nudge_dialog_complete_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 nudge dialog complete");
+		return status;
+	}
+
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param)
+		return -ENOMEM;
+
+	if (wmi_handle->ops->extract_twt_nudge_dialog_comp_event)
+		status = wmi_handle->ops->extract_twt_nudge_dialog_comp_event(
+						      wmi_handle, event, param);
+
+	wma_debug("TWT: Extract nudge dialog comp event status:%d", status);
+
+	sme_msg.type = eWNI_SME_TWT_NUDGE_DIALOG_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 status;
+}
 QDF_STATUS
 wma_twt_process_resume_dialog(t_wma_handle *wma_handle,
 			      struct wmi_twt_resume_dialog_cmd_param *params)
@@ -485,4 +556,9 @@ void wma_register_twt_events(tp_wma_handle wma_handle)
 				 wmi_twt_resume_dialog_complete_event_id,
 				 wma_twt_resume_dialog_complete_event_handler,
 				 WMA_RX_SERIALIZER_CTX);
+	wmi_unified_register_event_handler
+				(wma_handle->wmi_handle,
+				 wmi_twt_nudge_dialog_complete_event_id,
+				 wma_twt_nudge_dialog_complete_event_handler,
+				 WMA_RX_SERIALIZER_CTX);
 }