Browse Source

qcacld-3.0: Add TWT pause support to componentization

In TWT component, add support for TWT pause command
i.e when host wants to suspend the TWT session.

Change-Id: I8a60bb40fe9d37121d700f246b91e3211af66189
CRs-Fixed: 3085990
Srinivas Girigowda 3 years ago
parent
commit
0142156257

+ 9 - 1
components/target_if/twt/src/target_if_ext_twt_cmd.c

@@ -58,7 +58,15 @@ QDF_STATUS
 target_if_twt_pause_req(struct wlan_objmgr_psoc *psoc,
 			struct twt_pause_dialog_cmd_param *req)
 {
-	return QDF_STATUS_SUCCESS;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return wmi_unified_twt_pause_dialog_cmd(wmi_handle, req);
 }
 
 QDF_STATUS

+ 51 - 1
components/target_if/twt/src/target_if_ext_twt_evt.c

@@ -133,11 +133,61 @@ done:
 
 }
 
+/**
+ * target_if_twt_pause_complete_event_handler - TWT pause complete handler
+ * @scn: scn
+ * @event: buffer with event
+ * @len: buffer length
+ *
+ * Return: 0 on success, negative value on failure
+ */
 static int
 target_if_twt_pause_complete_event_handler(ol_scn_t scn, uint8_t *event,
 					   uint32_t len)
 {
-	return 0;
+	QDF_STATUS qdf_status;
+	struct wmi_unified *wmi_handle;
+	struct wlan_objmgr_psoc *psoc;
+	struct twt_pause_dialog_complete_event_param *param;
+	struct wlan_lmac_if_twt_rx_ops *twt_rx_ops;
+
+	TARGET_IF_ENTER();
+
+	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) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	twt_rx_ops = wlan_twt_get_rx_ops(psoc);
+	if (!twt_rx_ops || !twt_rx_ops->twt_pause_comp_cb) {
+		target_if_err("No valid twt pause complete rx ops");
+		return -EINVAL;
+	}
+
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param)
+		return -ENOMEM;
+
+	qdf_status = wmi_extract_twt_pause_dialog_comp_event(wmi_handle,
+							     event, param);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		target_if_err("extract twt pause dialog event failed (status=%d)",
+			     qdf_status);
+		goto done;
+	}
+
+	qdf_status = twt_rx_ops->twt_pause_comp_cb(psoc, param);
+
+done:
+	qdf_mem_free(param);
+	return qdf_status_to_os_return(qdf_status);
 }
 
 static int

+ 89 - 1
components/umac/twt/core/src/wlan_twt_main.c

@@ -1226,6 +1226,52 @@ wlan_twt_sta_teardown_req(struct wlan_objmgr_psoc *psoc,
 	return status;
 }
 
+QDF_STATUS wlan_twt_pause_req(struct wlan_objmgr_psoc *psoc,
+			      struct twt_pause_dialog_cmd_param *req,
+			      void *context)
+{
+	QDF_STATUS status;
+	bool cmd_in_progress;
+	bool is_twt_setup_done;
+	enum wlan_twt_commands active_cmd = WLAN_TWT_NONE;
+
+	status = wlan_twt_check_all_twt_support(psoc, req->dialog_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		twt_err("All TWT sessions not supported by target");
+		return status;
+	}
+
+	is_twt_setup_done = wlan_twt_is_setup_done(psoc, &req->peer_macaddr,
+						   req->dialog_id);
+	if (!is_twt_setup_done) {
+		twt_err("TWT setup is not complete for dialog_id:%d",
+			req->dialog_id);
+		return QDF_STATUS_E_AGAIN;
+	}
+
+	cmd_in_progress = wlan_twt_is_command_in_progress(psoc,
+					&req->peer_macaddr, req->dialog_id,
+					WLAN_TWT_ANY, &active_cmd);
+	if (cmd_in_progress) {
+		twt_debug("Already TWT command:%d is in progress", active_cmd);
+		return QDF_STATUS_E_PENDING;
+	}
+
+	wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr,
+					 req->dialog_id, WLAN_TWT_SUSPEND);
+	wlan_twt_set_ack_context(psoc, &req->peer_macaddr,
+				 req->dialog_id, context);
+
+	status = tgt_twt_pause_req_send(psoc, req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		twt_err("tgt_twt_pause_req_send failed (status=%d)", status);
+		wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr,
+						 req->dialog_id, WLAN_TWT_NONE);
+	}
+
+	return status;
+}
+
 /**
  * wlan_twt_sap_teardown_req() - sap TWT teardown request
  * @psoc: Pointer to psoc object
@@ -1716,7 +1762,49 @@ QDF_STATUS
 wlan_twt_pause_complete_event_handler(struct wlan_objmgr_psoc *psoc,
 			    struct twt_pause_dialog_complete_event_param *event)
 {
-	return QDF_STATUS_SUCCESS;
+	enum QDF_OPMODE opmode;
+	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
+	uint32_t pdev_id, vdev_id;
+	struct wlan_objmgr_pdev *pdev;
+
+	vdev_id = event->vdev_id;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID);
+	if (pdev_id == WLAN_INVALID_PDEV_ID) {
+		twt_err("Invalid pdev id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID);
+	if (!pdev) {
+		twt_err("Invalid pdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id);
+
+	switch (opmode) {
+	case QDF_SAP_MODE:
+		qdf_status = mlme_twt_osif_pause_complete_ind(psoc, event);
+		break;
+	case QDF_STA_MODE:
+		qdf_status = mlme_twt_osif_pause_complete_ind(psoc, event);
+
+		wlan_twt_set_session_state(psoc, &event->peer_macaddr,
+					   event->dialog_id,
+					   WLAN_TWT_SETUP_STATE_SUSPEND);
+
+		qdf_status = wlan_twt_set_command_in_progress(psoc,
+					&event->peer_macaddr,
+					event->dialog_id, WLAN_TWT_NONE);
+		break;
+	default:
+		twt_debug("TWT Pause is not supported on %s",
+			  qdf_opmode_str(opmode));
+		break;
+	}
+
+	wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID);
+	return qdf_status;
 }
 
 QDF_STATUS

+ 14 - 0
components/umac/twt/core/src/wlan_twt_main.h

@@ -76,6 +76,20 @@ QDF_STATUS
 wlan_twt_teardown_req(struct wlan_objmgr_psoc *psoc,
 		      struct twt_del_dialog_param *req,
 		      void *context);
+
+/**
+ * wlan_twt_pause_req() - Process TWT pause req
+ * @psoc: psoc
+ * @req: pause dialog cmd param
+ * @context: context
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_twt_pause_req(struct wlan_objmgr_psoc *psoc,
+		   struct twt_pause_dialog_cmd_param *req,
+		   void *context);
+
 /**
  * wlan_twt_is_setup_in_progress() - Get if TWT setup command is in progress
  * for given dialog id

+ 23 - 0
components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h

@@ -81,6 +81,21 @@ QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc,
 				 struct twt_del_dialog_param *params,
 				 void *context);
 
+/**
+ * ucfg_twt_pause_req() - Process TWT pause req
+ * @psoc: psoc
+ * @params: pause dialog cmd param
+ * @context: context
+ *
+ * Perform validations and set WLAN_TWT_SUSPEND
+ * in progress
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc,
+			      struct twt_pause_dialog_cmd_param *params,
+			      void *context);
+
 /**
  * ucfg_twt_is_max_sessions_reached() - Check if the maximum number of
  * TWT sessions reached or not excluding the given dialog_id
@@ -216,6 +231,14 @@ QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+static inline
+QDF_STATUS ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc,
+			      struct twt_pause_dialog_cmd_param *params,
+			      void *context)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 static inline QDF_STATUS
 ucfg_twt_init_context(struct wlan_objmgr_psoc *psoc,
 		      struct qdf_mac_addr *peer_mac,

+ 1 - 1
components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c

@@ -44,7 +44,7 @@ static QDF_STATUS
 tgt_twt_pause_complete_resp_handler(struct wlan_objmgr_psoc *psoc,
 			    struct twt_pause_dialog_complete_event_param *event)
 {
-	return QDF_STATUS_SUCCESS;
+	return wlan_twt_pause_complete_event_handler(psoc, event);
 }
 
 static QDF_STATUS

+ 23 - 1
components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c

@@ -90,7 +90,29 @@ QDF_STATUS
 tgt_twt_pause_req_send(struct wlan_objmgr_psoc *psoc,
 		       struct twt_pause_dialog_cmd_param *req)
 {
-	return QDF_STATUS_SUCCESS;
+	struct wlan_lmac_if_twt_tx_ops *tx_ops;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		twt_err("psoc is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!req) {
+		twt_err("Invalid input");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tx_ops = wlan_twt_get_tx_ops(psoc);
+	if (!tx_ops || !tx_ops->pause_req) {
+		twt_err("pause tx_ops is null");
+		status = QDF_STATUS_E_NULL_VALUE;
+		return status;
+	}
+
+	status = tx_ops->pause_req(psoc, req);
+
+	return status;
 }
 
 QDF_STATUS

+ 8 - 0
components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c

@@ -62,6 +62,14 @@ QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc,
 	return wlan_twt_teardown_req(psoc, params, context);
 }
 
+QDF_STATUS
+ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc,
+		   struct twt_pause_dialog_cmd_param *params,
+		   void *context)
+{
+	return wlan_twt_pause_req(psoc, params, context);
+}
+
 bool ucfg_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc,
 				      struct qdf_mac_addr *peer_mac,
 				      uint8_t dialog_id)

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

@@ -236,6 +236,7 @@ static int hdd_twt_configure(struct hdd_adapter *adapter,
 		ret = hdd_twt_terminate_session(adapter, vdev, twt_param_attr);
 		break;
 	case QCA_WLAN_TWT_SUSPEND:
+		ret = osif_twt_pause_req(vdev, twt_param_attr);
 		break;
 	case QCA_WLAN_TWT_RESUME:
 		break;

+ 23 - 0
os_if/twt/inc/osif_twt_ext_req.h

@@ -93,6 +93,22 @@ void
 osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc,
 		       struct twt_add_dialog_complete_event *add_dialog_event);
 
+/**
+ * osif_twt_pause_req() - Process TWT pause operation
+ * in the received vendor command and send it to firmware
+ * @vdev: vdev
+ * @twt_param_attr: nl attributes
+ *
+ * sets up TWT pause request from HDD. request is passed
+ * to TWT core
+ *
+ * Handles QCA_WLAN_TWT_SUSPEND
+ *
+ * Return: success on 0, failure on non-zero
+ */
+int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev,
+		       struct nlattr *twt_param_attr);
+
 /**
  * osif_twt_get_capabilities() - Process TWT get capabilities
  * in the received vendor command.
@@ -155,6 +171,13 @@ int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev,
 	return 0;
 }
 
+static inline
+int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev,
+		       struct nlattr *twt_param_attr)
+{
+	return 0;
+}
+
 #endif
 #endif /* _OSIF_TWT_EXT_REQ_H_ */
 

+ 129 - 0
os_if/twt/src/osif_twt_ext_req.c

@@ -503,6 +503,87 @@ cleanup:
 	return ret;
 }
 
+/**
+ * osif_send_twt_pause_req() - Send TWT pause dialog command to target
+ * @vdev: vdev
+ * @psoc: psoc
+ * @twt_params: Pointer to pause dialog cmd params structure
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static int
+osif_send_twt_pause_req(struct wlan_objmgr_vdev *vdev,
+			struct wlan_objmgr_psoc *psoc,
+			struct twt_pause_dialog_cmd_param *twt_params)
+{
+	QDF_STATUS status;
+	int ret = 0, twt_cmd;
+	struct osif_request *request;
+	struct twt_ack_context *ack_priv;
+	void *context;
+	static const struct osif_request_params params = {
+				.priv_size = sizeof(*ack_priv),
+				.timeout_ms = TWT_ACK_COMPLETE_TIMEOUT,
+	};
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		osif_err("Request allocation failure");
+		return -ENOMEM;
+	}
+
+	context = osif_request_cookie(request);
+
+	status = ucfg_twt_pause_req(psoc, twt_params, context);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_err("Failed to send pause dialog command");
+		ret = qdf_status_to_os_return(status);
+		goto cleanup;
+	}
+
+	twt_cmd = HOST_TWT_PAUSE_DIALOG_CMDID;
+	status = osif_twt_ack_wait_response(psoc, request, twt_cmd);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ret = qdf_status_to_os_return(status);
+		goto cleanup;
+	}
+
+	ack_priv = osif_request_priv(request);
+	if (ack_priv->status != HOST_TWT_PAUSE_STATUS_OK) {
+		osif_err("Received TWT ack error:%d. Reset twt command",
+			 ack_priv->status);
+
+		switch (ack_priv->status) {
+		case HOST_TWT_PAUSE_STATUS_INVALID_PARAM:
+		case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED:
+		case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR:
+			ret = -EINVAL;
+			break;
+		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST:
+			ret = -EAGAIN;
+			break;
+		case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY:
+			ret = -EINPROGRESS;
+			break;
+		case HOST_TWT_PAUSE_STATUS_NO_RESOURCE:
+			ret = -ENOMEM;
+			break;
+		case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS:
+		case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS:
+		case HOST_TWT_PAUSE_STATUS_SCAN_IN_PROGRESS:
+			ret = -EBUSY;
+			break;
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+	}
+
+cleanup:
+	osif_request_put(request);
+	return ret;
+}
+
 static int
 osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev *vdev,
 			       struct wlan_objmgr_psoc *psoc,
@@ -1037,3 +1118,51 @@ void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc,
 	}
 }
 
+int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev,
+		       struct nlattr *twt_param_attr)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1];
+	struct wlan_objmgr_psoc *psoc;
+	int ret = 0, id;
+	uint32_t vdev_id;
+	struct  twt_pause_dialog_cmd_param params = {0};
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		osif_err("NULL psoc");
+		return -EINVAL;
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc);
+	if (ret)
+		return ret;
+
+	ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes);
+	if (ret)
+		return ret;
+
+	if (twt_param_attr) {
+		ret = wlan_cfg80211_nla_parse_nested(tb,
+					QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX,
+					twt_param_attr,
+					qca_wlan_vendor_twt_add_dialog_policy);
+		if (ret)
+			return ret;
+
+		id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+		if (tb[id])
+			params.dialog_id = nla_get_u8(tb[id]);
+		else
+			osif_debug("TWT: FLOW_ID not specified. set to zero");
+	} else {
+		osif_debug("TWT param not present. flow id set to zero");
+	}
+
+	osif_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr "
+		  QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id,
+		  QDF_MAC_ADDR_REF(params.peer_macaddr.bytes));
+
+	return osif_send_twt_pause_req(vdev, psoc, &params);
+}
+

+ 175 - 30
os_if/twt/src/osif_twt_ext_rsp.c

@@ -90,6 +90,28 @@ uint32_t osif_twt_get_setup_event_len(bool additional_params_present)
 	return len;
 }
 
+/**
+ * osif_twt_get_event_len() - calculate length of skb
+ * required for sending twt terminate, pause and resume
+ * command responses.
+ *
+ * Return: length of skb
+ */
+static uint32_t osif_twt_get_event_len(void)
+{
+	uint32_t len = 0;
+
+	len += NLMSG_HDRLEN;
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
+	len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
+	len += nla_total_size(sizeof(u8));
+	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
+	len += nla_total_size(QDF_MAC_ADDR_SIZE);
+
+	return len;
+}
+
 /**
  * twt_add_status_to_vendor_twt_status() - convert from
  * HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status
@@ -608,28 +630,6 @@ fail:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
 }
 
-/**
- * osif_get_twt_event_len() - calculate length of skb
- * required for sending twt terminate, pause and resume
- * command responses.
- *
- * Return: length of skb
- */
-static uint32_t osif_get_twt_event_len(void)
-{
-	uint32_t len = 0;
-
-	len += NLMSG_HDRLEN;
-	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */
-	len += nla_total_size(sizeof(u8));
-	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */
-	len += nla_total_size(sizeof(u8));
-	/* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/
-	len += nla_total_size(QDF_MAC_ADDR_SIZE);
-
-	return len;
-}
-
 static void
 osif_twt_teardown_response(struct wlan_objmgr_psoc *psoc,
 			   struct twt_del_dialog_complete_event_param *event)
@@ -660,7 +660,7 @@ osif_twt_teardown_response(struct wlan_objmgr_psoc *psoc,
 		goto fail;
 	}
 
-	data_len = osif_get_twt_event_len() + nla_total_size(sizeof(u8));
+	data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8));
 	data_len += NLA_HDRLEN;
 	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
 				wdev->wiphy, wdev, data_len,
@@ -720,13 +720,6 @@ osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS
-osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc,
-			   struct twt_pause_dialog_complete_event_param *event)
-{
-	return QDF_STATUS_SUCCESS;
-}
-
 QDF_STATUS
 osif_twt_resume_complete_cb(struct wlan_objmgr_psoc *psoc,
 			   struct twt_resume_dialog_complete_event_param *event)
@@ -796,6 +789,158 @@ osif_twt_notify_complete_cb(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * twt_pause_status_to_vendor_twt_status() - convert from
+ * HOST_TWT_PAUSE_STATUS to qca_wlan_vendor_twt_status
+ * @status: HOST_TWT_PAUSE_STATUS value from firmware
+ *
+ * Return: qca_wlan_vendor_twt_status values corresponding
+ * to the firmware failure status
+ */
+static int
+twt_pause_status_to_vendor_twt_status(enum HOST_TWT_PAUSE_STATUS status)
+{
+	switch (status) {
+	case HOST_TWT_PAUSE_STATUS_OK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_OK;
+	case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST;
+	case HOST_TWT_PAUSE_STATUS_INVALID_PARAM:
+		return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM;
+	case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY:
+		return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY;
+	case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED:
+		return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED;
+	case HOST_TWT_PAUSE_STATUS_NO_RESOURCE:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE;
+	case HOST_TWT_PAUSE_STATUS_NO_ACK:
+		return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK;
+	case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS:
+		return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS;
+	case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS:
+		return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS;
+	default:
+		return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR;
+	}
+}
+
+/**
+ * osif_twt_pause_pack_resp_nlmsg() - pack the skb with
+ * firmware response for twt pause command
+ * @reply_skb: skb to store the response
+ * @event: Pointer to pause dialog complete event buffer
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+osif_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb,
+			struct twt_pause_dialog_complete_event_param *event)
+{
+	struct nlattr *config_attr;
+	int vendor_status, attr;
+
+	if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION,
+		       QCA_WLAN_TWT_SUSPEND)) {
+		osif_err("Failed to put TWT operation");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	config_attr = nla_nest_start(reply_skb,
+				     QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS);
+	if (!config_attr) {
+		osif_err("nla_nest_start error");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID;
+	if (nla_put_u8(reply_skb, attr, event->dialog_id)) {
+		osif_debug("Failed to put dialog_id");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS;
+	vendor_status = twt_pause_status_to_vendor_twt_status(event->status);
+	if (nla_put_u8(reply_skb, attr, vendor_status)) {
+		osif_err("Failed to put QCA_WLAN_TWT_PAUSE status");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR;
+	if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE,
+		    event->peer_macaddr.bytes)) {
+		osif_err("Failed to put mac_addr");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	nla_nest_end(reply_skb, config_attr);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc,
+			   struct twt_pause_dialog_complete_event_param *event)
+
+{
+	struct wireless_dev *wdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t vdev_id = event->vdev_id;
+	struct sk_buff *twt_vendor_event;
+	size_t data_len;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id,
+						    WLAN_TWT_ID);
+	if (!vdev) {
+		osif_err("vdev is null");
+		return status;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		osif_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		osif_err("wireless dev is null");
+		goto fail;
+	}
+
+	osif_debug("TWT: pause dialog_id:%d status:%d vdev_id:%d peer macaddr "
+		   QDF_MAC_ADDR_FMT, event->dialog_id,
+		   event->status, vdev_id,
+		   QDF_MAC_ADDR_REF(event->peer_macaddr.bytes));
+
+	data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8));
+	data_len += NLA_HDRLEN;
+
+	twt_vendor_event = wlan_cfg80211_vendor_event_alloc(
+				wdev->wiphy, wdev, data_len,
+				QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX,
+				GFP_KERNEL);
+	if (!twt_vendor_event) {
+		osif_err("TWT: Alloc pause resp skb fail");
+		goto fail;
+	}
+
+	status = osif_twt_pause_pack_resp_nlmsg(twt_vendor_event, event);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		osif_err("Failed to pack nl add dialog response");
+		wlan_cfg80211_vendor_free_skb(twt_vendor_event);
+		goto fail;
+	}
+	wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL);
+
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID);
+	return status;
+}
+
 QDF_STATUS
 osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc,
 			 struct twt_ack_complete_event_param *params,