diff --git a/core/hdd/inc/wlan_hdd_twt.h b/core/hdd/inc/wlan_hdd_twt.h index 730e8682c1a3..4e1447fa1057 100644 --- a/core/hdd/inc/wlan_hdd_twt.h +++ b/core/hdd/inc/wlan_hdd_twt.h @@ -36,6 +36,8 @@ struct hdd_adapter; struct wma_tgt_cfg; struct wmi_twt_add_dialog_param; struct wmi_twt_del_dialog_param; +struct wmi_twt_pause_dialog_cmd_param; +struct wmi_twt_resume_dialog_cmd_param; extern const struct nla_policy qca_wlan_vendor_twt_add_dialog_policy[ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; @@ -45,7 +47,6 @@ wlan_hdd_wifi_twt_config_policy[ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1]; #ifdef WLAN_SUPPORT_TWT - /** * enum twt_status - TWT target state * @TWT_INIT: Init State diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index 3e84c8c6be66..ccedfb460739 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -37,6 +37,30 @@ #define TWT_SETUP_COMPLETE_TIMEOUT 1000 #define TWT_DISABLE_COMPLETE_TIMEOUT 1000 #define TWT_TERMINATE_COMPLETE_TIMEOUT 1000 +#define TWT_PAUSE_COMPLETE_TIMEOUT 1000 +#define TWT_RESUME_COMPLETE_TIMEOUT 1000 + +/** + * struct twt_pause_dialog_comp_ev_priv - private struct for twt pause dialog + * @pause_dialog_comp_ev_buf: buffer from TWT pause dialog complete_event + * + * This TWT pause dialog private structure is registered with os_if to + * retrieve the TWT pause dialog response event buffer. + */ +struct twt_pause_dialog_comp_ev_priv { + struct wmi_twt_pause_dialog_complete_event_param pause_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 + * + * This TWT resume dialog private structure is registered with os_if to + * retrieve the TWT resume dialog response event buffer. + */ +struct twt_resume_dialog_comp_ev_priv { + struct wmi_twt_resume_dialog_complete_event_param res_dialog_comp_ev_buf; +}; /** * struct twt_add_dialog_complete_event - TWT add dialog complete event @@ -73,6 +97,14 @@ struct twt_del_dialog_comp_ev_priv { struct wmi_twt_del_dialog_complete_event_param del_dialog_comp_ev_buf; }; +static const struct nla_policy +qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 }, +}; + const struct nla_policy wlan_hdd_wifi_twt_config_policy[ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = { @@ -117,6 +149,70 @@ static uint32_t hdd_get_twt_setup_event_len(void) return len; } +/** + * wmi_twt_resume_status_to_vendor_twt_status() - convert from + * WMI_HOST_RESUME_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_RESUME_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +wmi_twt_resume_status_to_vendor_twt_status(enum WMI_HOST_RESUME_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_RESUME_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_RESUME_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_RESUME_TWT_STATUS_NOT_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED; + case WMI_HOST_RESUME_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_RESUME_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_RESUME_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * wmi_twt_pause_status_to_vendor_twt_status() - convert from + * WMI_HOST_PAUSE_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_PAUSE_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +wmi_twt_pause_status_to_vendor_twt_status(enum WMI_HOST_PAUSE_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_PAUSE_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_PAUSE_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_PAUSE_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_PAUSE_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_PAUSE_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 @@ -505,12 +601,13 @@ static int hdd_twt_setup_session(struct hdd_adapter *adapter, } /** - * hdd_get_twt_terminate_event_len() - calculate length of skb - * required for sending twt terminate response. + * hdd_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 hdd_get_twt_terminate_event_len(void) +static uint32_t hdd_get_twt_event_len(void) { uint32_t len = 0; @@ -644,7 +741,7 @@ int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx, priv = osif_request_priv(request); del_dialog_comp_ev_params = &priv->del_dialog_comp_ev_buf; - skb_len = hdd_get_twt_terminate_event_len(); + skb_len = hdd_get_twt_event_len(); reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len); if (!reply_skb) { @@ -673,7 +770,7 @@ err: /** * hdd_twt_terminate_session - Process TWT terminate - * operation in the recevied vendor command and + * operation in the received vendor command and * send it to firmare * @adapter: adapter pointer * @twt_param_attr: nl attributes @@ -733,9 +830,441 @@ static int hdd_twt_terminate_session(struct hdd_adapter *adapter, return ret; } +/** + * hdd_twt_pause_dialog_comp_cb() - callback function + * to get twt pause command complete event + * @context: private context + * @params: Pointer to pause dialog complete event buffer + * + * Return: None + */ +static void +hdd_twt_pause_dialog_comp_cb(void *context, + struct wmi_twt_pause_dialog_complete_event_param *params) +{ + struct osif_request *request; + struct twt_pause_dialog_comp_ev_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + qdf_mem_copy(&priv->pause_dialog_comp_ev_buf, params, sizeof(*params)); + osif_request_complete(request); + osif_request_put(request); + + hdd_debug("TWT: pause 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 + * @reply_skb: skb to store the response + * @params: Pointer to pause dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_pause_dialog_complete_event_param *params) +{ + int vendor_status; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID, + params->dialog_id)) { + hdd_debug("TWT: Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + vendor_status = wmi_twt_pause_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_PAUSE 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 + * @twt_params: Pointer to pause dialog cmd params structure + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +static +int hdd_send_twt_pause_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_pause_dialog_cmd_param *twt_params) +{ + struct wmi_twt_pause_dialog_complete_event_param *comp_ev_params; + struct twt_pause_dialog_comp_ev_priv *priv; + static const struct osif_request_params osif_req_params = { + .priv_size = sizeof(*priv), + .timeout_ms = TWT_PAUSE_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_pause_dialog_cmd(hdd_ctx->mac_handle, + hdd_twt_pause_dialog_comp_cb, + twt_params, cookie); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send pause dialog command"); + ret = qdf_status_to_os_return(status); + goto err; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("twt: pause dialog req timedout"); + ret = -ETIMEDOUT; + goto err; + } + + priv = osif_request_priv(request); + comp_ev_params = &priv->pause_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_pause_pack_resp_nlmsg(reply_skb, comp_ev_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl pause 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_pause_session - Process TWT pause operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_SUSPEND + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_pause_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_SETUP_MAX + 1]; + struct wmi_twt_pause_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; + } + + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->vdev_id; + + 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 { + params.dialog_id = 0; + hdd_debug("TWT: FLOW_ID not specified. set to zero"); + } + + hdd_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_twt_pause_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +/** + * hdd_twt_resume_dialog_comp_cb() - callback function + * to get twt resume command complete event + * @context: private context + * @params: Pointer to resume dialog complete event buffer + * + * Return: None + */ +static void +hdd_twt_resume_dialog_comp_cb(void *context, + struct wmi_twt_resume_dialog_complete_event_param *params) +{ + struct osif_request *request; + struct twt_resume_dialog_comp_ev_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + qdf_mem_copy(&priv->res_dialog_comp_ev_buf, params, sizeof(*params)); + osif_request_complete(request); + osif_request_put(request); + + hdd_debug("TWT: resume 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_resume_pack_resp_nlmsg() - pack the skb with + * firmware response for twt resume command + * @reply_skb: skb to store the response + * @params: Pointer to resume dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_resume_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_resume_dialog_complete_event_param *params) +{ + int vendor_status; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID, + params->dialog_id)) { + hdd_debug("TWT: Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + vendor_status = wmi_twt_resume_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_RESUME status"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_send_twt_resume_dialog_cmd() - Send TWT resume dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to resume dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static int +hdd_send_twt_resume_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_resume_dialog_cmd_param *twt_params) +{ + struct wmi_twt_resume_dialog_complete_event_param *comp_ev_params; + struct twt_resume_dialog_comp_ev_priv *priv; + static const struct osif_request_params osif_req_params = { + .priv_size = sizeof(*priv), + .timeout_ms = TWT_RESUME_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_resume_dialog_cmd(hdd_ctx->mac_handle, + hdd_twt_resume_dialog_comp_cb, + twt_params, cookie); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send resume dialog command"); + ret = qdf_status_to_os_return(status); + goto err; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("twt: resume dialog req timedout"); + ret = -ETIMEDOUT; + goto err; + } + + priv = osif_request_priv(request); + comp_ev_params = &priv->res_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_resume_pack_resp_nlmsg(reply_skb, comp_ev_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl resume 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_resume_session - Process TWT resume operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_RESUME + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_resume_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_RESUME_MAX + 1]; + struct wmi_twt_resume_dialog_cmd_param params = {0}; + int id, id2; + 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; + } + + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX, + twt_param_attr, + qca_wlan_vendor_twt_resume_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID; + if (tb[id]) { + params.dialog_id = nla_get_u8(tb[id]); + } else { + params.dialog_id = 0; + hdd_debug("TWT_RESUME_FLOW_ID not specified. set to zero"); + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT; + id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT; + if (tb[id2]) + params.sp_offset_us = nla_get_u32(tb[id2]); + else if (tb[id]) + params.sp_offset_us = nla_get_u8(tb[id]); + else + params.sp_offset_us = 0; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE; + if (tb[id]) { + params.next_twt_size = nla_get_u32(tb[id]); + } else { + hdd_err_rl("TWT_RESUME NEXT_TWT_SIZE is must"); + return -EINVAL; + } + + hdd_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_twt_resume_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + /** * hdd_twt_configure - Process the TWT - * operation in the recevied vendor command + * operation in the received vendor command * @adapter: adapter pointer * @tb: nl attributes * @@ -781,8 +1310,10 @@ static int hdd_twt_configure(struct hdd_adapter *adapter, ret = hdd_twt_terminate_session(adapter, twt_param_attr); break; case QCA_WLAN_TWT_SUSPEND: + ret = hdd_twt_pause_session(adapter, twt_param_attr); break; case QCA_WLAN_TWT_RESUME: + ret = hdd_twt_resume_session(adapter, twt_param_attr); break; default: hdd_err("Invalid TWT Operation"); diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 69dfa58c3343..90f46e718d48 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -3662,6 +3662,40 @@ QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle, struct wmi_twt_del_dialog_param *twt_params, void *context); +/** + * sme_pause_dialog_cmd() - Register callback and send TWT pause dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_pause_dialog_cb: Function callback to handle pause_dialog event + * @twt_params: TWT pause dialog parameters + * @context: os_if_request cookie + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_pause_dialog_cmd(mac_handle_t mac_handle, + twt_pause_dialog_cb pause_dialog_cb, + struct wmi_twt_pause_dialog_cmd_param *twt_params, + void *context); + +/** + * sme_resume_dialog_cmd() - Register callback and send TWT resume dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_resume_dialog_cb: Function callback to handle resume_dialog event + * @twt_params: TWT resume dialog parameters + * @context: os_if_request cookie + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_resume_dialog_cmd(mac_handle_t mac_handle, + twt_resume_dialog_cb resume_dialog_cb, + struct wmi_twt_resume_dialog_cmd_param *twt_params, + void *context); + /** * sme_deregister_twt_enable_complete_cb() - TWT enable deregistrar * @mac_handle: Opaque handle to the global MAC context diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index 84540f728f20..15e08f705857 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -178,6 +178,26 @@ typedef void (*twt_add_dialog_cb)(void *context, */ typedef void (*twt_del_dialog_cb)(void *context, struct wmi_twt_del_dialog_complete_event_param *params); + +/** + * typedef twt_pause_dialog_cb - TWT pause dialog callback signature. + * @context: Opaque context that the client can use to associate the + * callback with the request. + * @params: TWT pause dialog complete event parameters. + */ +typedef +void (*twt_pause_dialog_cb)(void *context, + struct wmi_twt_pause_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 + * callback with the request. + * @params: TWT resume dialog complete event parameters. + */ +typedef +void (*twt_resume_dialog_cb)(void *context, + struct wmi_twt_resume_dialog_complete_event_param *params); #endif #ifdef FEATURE_WLAN_APF @@ -385,10 +405,14 @@ struct sme_context { #endif /* FEATURE_FW_STATE */ tx_queue_cb tx_queue_cb; #ifdef WLAN_SUPPORT_TWT - twt_enable_cb twt_enable_cb; - twt_disable_cb twt_disable_cb; - twt_add_dialog_cb twt_add_dialog_cb; - twt_del_dialog_cb twt_del_dialog_cb; + union { + twt_enable_cb twt_enable_cb; + twt_disable_cb twt_disable_cb; + 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_resume_dialog_cb twt_resume_dialog_cb; + }; void *twt_context; #endif #ifdef FEATURE_WLAN_APF diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 65f7714f6232..5bbb69d0c698 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -14522,6 +14522,76 @@ QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle, return status; } +QDF_STATUS +sme_pause_dialog_cmd(mac_handle_t mac_handle, + twt_pause_dialog_cb pause_dialog_cb, + struct wmi_twt_pause_dialog_cmd_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + 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; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register pause dialog callback"); + return status; + } + + mac->sme.twt_pause_dialog_cb = pause_dialog_cb; + mac->sme.twt_context = context; + sme_release_global_lock(&mac->sme); + + status = wma_twt_process_pause_dialog(twt_params); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("failed to call wma_twt_process_pause_dialog"); + + SME_EXIT(); + return status; +} + +QDF_STATUS +sme_resume_dialog_cmd(mac_handle_t mac_handle, + twt_resume_dialog_cb resume_dialog_cb, + struct wmi_twt_resume_dialog_cmd_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + 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; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register resume dialog callback"); + return status; + } + + mac->sme.twt_resume_dialog_cb = resume_dialog_cb; + mac->sme.twt_context = context; + sme_release_global_lock(&mac->sme); + + status = wma_twt_process_resume_dialog(twt_params); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("failed to call wma_twt_process_resume_dialog"); + + SME_EXIT(); + return status; +} + #endif QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index f5646c87952d..401cf33c8d2b 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -1707,48 +1707,12 @@ int wma_vdev_bss_color_collision_info_handler(void *handle, #ifdef WLAN_SUPPORT_TWT /** - * wma_twt_en_complete_event_handler - TWT enable complete event handler + * wma_register_twt_events - Register TWT wmi event handlers * @handle: wma handle - * @event: buffer with event - * @len: buffer length * - * Return: 0 on success + * Return: None */ -int wma_twt_en_complete_event_handler(void *handle, - uint8_t *event, uint32_t len); - -/** - * wma_twt_disable_comp_event_handler- TWT disable complete event handler - * @handle: wma handle - * @event: buffer with event - * @len: buffer length - * - * Return: 0 on success - */ -int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event, - uint32_t len); - -/** - * wma_twt_add_dialog_complete_event_handler - TWT add dlg complete evt handler - * @handle: wma handle - * @event: buffer with event - * @len: buffer length - * - * Return: 0 on success - */ -int wma_twt_add_dialog_complete_event_handler(void *handle, - uint8_t *event, uint32_t len); - -/** - * wma_twt_del_dialog_complete_event_handler - TWT del dlg complete evt handler - * @handle: wma handle - * @event: buffer with event - * @len: buffer length - * - * Return: 0 on success - */ -int wma_twt_del_dialog_complete_event_handler(void *handle, - uint8_t *event, uint32_t len); +void wma_register_twt_events(tp_wma_handle wma_handle); #endif /** diff --git a/core/wma/inc/wma_twt.h b/core/wma/inc/wma_twt.h index aaffe22d20af..30f4242287f5 100644 --- a/core/wma/inc/wma_twt.h +++ b/core/wma/inc/wma_twt.h @@ -69,6 +69,26 @@ QDF_STATUS wma_twt_process_add_dialog(struct wmi_twt_add_dialog_param *params); */ QDF_STATUS wma_twt_process_del_dialog(struct wmi_twt_del_dialog_param *params); +/** + * wma_twt_process_pause_dialog() - Process pause dialog command + * @params: pause dialog configuration param + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS +wma_twt_process_pause_dialog(struct wmi_twt_pause_dialog_cmd_param *params); + +/** + * wma_twt_process_resume_dialog() - Process resume dialog command + * @params: resume dialog configuration param + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS +wma_twt_process_resume_dialog(struct wmi_twt_resume_dialog_cmd_param *params); + #else static inline void wma_send_twt_enable_cmd(uint32_t pdev_id, uint32_t congestion_timeout, @@ -101,6 +121,25 @@ static inline QDF_STATUS wma_twt_process_del_dialog( return QDF_STATUS_E_INVAL; } + +static inline QDF_STATUS wma_twt_process_pause_dialog( + struct wmi_twt_pause_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( + struct wmi_twt_resume_dialog_cmd_param *params) + +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + #endif #endif /* __WMA_HE_H */ diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index f4dd0c14d116..7387ad9bcc33 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3356,24 +3356,7 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, WMA_RX_WORK_CTX); #ifdef WLAN_SUPPORT_TWT - wmi_unified_register_event_handler(wma_handle->wmi_handle, - wmi_twt_enable_complete_event_id, - wma_twt_en_complete_event_handler, - WMA_RX_SERIALIZER_CTX); - wmi_unified_register_event_handler(wma_handle->wmi_handle, - wmi_twt_disable_complete_event_id, - wma_twt_disable_comp_event_handler, - WMA_RX_SERIALIZER_CTX); - wmi_unified_register_event_handler - (wma_handle->wmi_handle, - wmi_twt_add_dialog_complete_event_id, - wma_twt_add_dialog_complete_event_handler, - WMA_RX_SERIALIZER_CTX); - wmi_unified_register_event_handler - (wma_handle->wmi_handle, - wmi_twt_del_dialog_complete_event_id, - wma_twt_del_dialog_complete_event_handler, - WMA_RX_SERIALIZER_CTX); + wma_register_twt_events(wma_handle); #endif wma_register_apf_events(wma_handle); diff --git a/core/wma/src/wma_twt.c b/core/wma/src/wma_twt.c index 1cb4d0d84932..f52cd6c1645d 100644 --- a/core/wma/src/wma_twt.c +++ b/core/wma/src/wma_twt.c @@ -46,6 +46,15 @@ void wma_send_twt_enable_cmd(uint32_t pdev_id, wma_err("Failed to enable TWT"); } +/** + * wma_twt_en_complete_event_handler - TWT enable complete event handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int wma_twt_en_complete_event_handler(void *handle, uint8_t *event, uint32_t len) { @@ -98,6 +107,15 @@ void wma_send_twt_disable_cmd(uint32_t pdev_id) wma_err("Failed to disable TWT"); } +/** + * wma_twt_disable_comp_event_handler- TWT disable complete event handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int wma_twt_disable_comp_event_handler(void *handle, uint8_t *event, uint32_t len) { @@ -145,6 +163,16 @@ QDF_STATUS wma_twt_process_add_dialog( return wmi_unified_twt_add_dialog_cmd(wmi_handle, params); } +/** + * wma_twt_add_dialog_complete_event_handler - TWT add dialog complete event + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int wma_twt_add_dialog_complete_event_handler(void *handle, uint8_t *event, uint32_t len) { @@ -215,6 +243,16 @@ QDF_STATUS wma_twt_process_del_dialog( return wmi_unified_twt_del_dialog_cmd(wmi_handle, params); } +/** + * wma_twt_del_dialog_complete_event_handler - TWT del dialog complete event + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int wma_twt_del_dialog_complete_event_handler(void *handle, uint8_t *event, uint32_t len) { @@ -248,3 +286,174 @@ int wma_twt_del_dialog_complete_event_handler(void *handle, return status; } + +QDF_STATUS +wma_twt_process_pause_dialog(struct wmi_twt_pause_dialog_cmd_param *params) +{ + t_wma_handle *wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + wmi_unified_t wmi_handle; + + if (!wma_handle) { + wma_err("Invalid wma handle, twt pause dialog failed"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle, twt pause dialog failed"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_twt_pause_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_pause_dialog_complete_event_handler - TWT pause 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_pause_dialog_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_pause_dialog_complete_event_param param; + 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) { + wma_err("Invalid MAC context"); + return status; + } + + if (!wma_handle) { + wma_err("Invalid wma handle for TWT pause dialog complete"); + return status; + } + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle for TWT pause dialog complete"); + return status; + } + + if (wmi_handle->ops->extract_twt_pause_dialog_comp_event) + status = wmi_handle->ops->extract_twt_pause_dialog_comp_event(wmi_handle, + event, + ¶m); + wma_debug("TWT: Extract pause dialog comp event status:%d", status); + + if (mac->sme.twt_pause_dialog_cb) + mac->sme.twt_pause_dialog_cb(mac->sme.twt_context, ¶m); + + mac->sme.twt_pause_dialog_cb = NULL; + + return status; +} + +QDF_STATUS wma_twt_process_resume_dialog( + struct wmi_twt_resume_dialog_cmd_param *params) +{ + t_wma_handle *wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + wmi_unified_t wmi_handle; + + if (!wma_handle) { + wma_err("Invalid wma handle, twt resume dialog failed"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle, twt resume dialog failed"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_twt_resume_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_resume_dialog_complete_event_handler - TWT resume 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_resume_dialog_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_resume_dialog_complete_event_param param; + 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) { + wma_err("Invalid MAC context"); + return status; + } + + if (!wma_handle) { + wma_err("Invalid wma handle for TWT resume dialog complete"); + return status; + } + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle for TWT resume dialog complete"); + return status; + } + + if (wmi_handle->ops->extract_twt_resume_dialog_comp_event) + status = wmi_handle->ops->extract_twt_resume_dialog_comp_event(wmi_handle, + event, + ¶m); + wma_debug("TWT: Extract resume dialog comp event status:%d", status); + + if (mac->sme.twt_resume_dialog_cb) + mac->sme.twt_resume_dialog_cb(mac->sme.twt_context, ¶m); + + mac->sme.twt_resume_dialog_cb = NULL; + + return status; +} + +void wma_register_twt_events(tp_wma_handle wma_handle) +{ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_twt_enable_complete_event_id, + wma_twt_en_complete_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_twt_disable_complete_event_id, + wma_twt_disable_comp_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_add_dialog_complete_event_id, + wma_twt_add_dialog_complete_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_del_dialog_complete_event_id, + wma_twt_del_dialog_complete_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_pause_dialog_complete_event_id, + wma_twt_pause_dialog_complete_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_resume_dialog_complete_event_id, + wma_twt_resume_dialog_complete_event_handler, + WMA_RX_SERIALIZER_CTX); +}