From 36f9799626fb74e038704347f05cb8dc3a05c4e3 Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Sun, 3 Jan 2021 15:35:02 +0530 Subject: [PATCH] qcacld-3.0: Add support for TWT setup additional parameters Add support for below TWT setup additional parameters: Minimum TWT wake interval Maximum TWT wake interval Minimum TWT wake duration Maximum TWT wake duration Make the TWT setup command handling as asynchronous. Send QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT event to userspace when add dialog complete event is received from firmware. Change-Id: Ia56bbecd04e0c02a55dc1a7f43ee533a85f82f1d CRs-Fixed: 2842895 --- core/hdd/inc/wlan_hdd_twt.h | 8 +- core/hdd/src/wlan_hdd_cfg80211.c | 7 +- core/hdd/src/wlan_hdd_twt.c | 196 ++++++++++++++++++------------- core/sme/inc/sme_api.h | 4 +- core/sme/inc/sme_internal.h | 8 +- core/sme/src/common/sme_api.c | 8 +- 6 files changed, 131 insertions(+), 100 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_twt.h b/core/hdd/inc/wlan_hdd_twt.h index 60ee83353d05..c297ee7a476f 100644 --- a/core/hdd/inc/wlan_hdd_twt.h +++ b/core/hdd/inc/wlan_hdd_twt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-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 @@ -42,6 +42,12 @@ struct wmi_twt_resume_dialog_cmd_param; extern const struct nla_policy wlan_hdd_wifi_twt_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1]; +#define FEATURE_TWT_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT, \ +}, + /** * enum twt_role - TWT role definitions * @TWT_REQUESTOR: Individual/Bcast TWT requestor role diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index d5f8f14fa7d0..16aec4f0c4d1 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -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 @@ -1678,7 +1678,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = [QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX] = { .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO, - } + }, +#ifdef WLAN_SUPPORT_TWT + FEATURE_TWT_VENDOR_EVENTS +#endif }; /** diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index 62c25e513bf7..eda7442d4cd0 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2018-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 @@ -107,6 +107,10 @@ qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 }, }; static const struct nla_policy @@ -238,6 +242,21 @@ int hdd_twt_get_add_dialog_values(struct nlattr **tb, return -EINVAL; } + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION; + if (tb[cmd_id]) + params->min_wake_dura_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION; + if (tb[cmd_id]) + params->max_wake_dura_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_dura_us > params->max_wake_dura_us) { + hdd_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero", + params->min_wake_dura_us, params->max_wake_dura_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; if (!tb[cmd_id]) { hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must"); @@ -266,11 +285,30 @@ int hdd_twt_get_add_dialog_values(struct nlattr **tb, params->wake_intvl_us = params->wake_intvl_mantis; } - hdd_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, mantis %d", + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL; + if (tb[cmd_id]) + params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL; + if (tb[cmd_id]) + params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_intvl_us > params->max_wake_intvl_us) { + hdd_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero", + params->min_wake_intvl_us, + params->max_wake_intvl_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + + hdd_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d", params->dialog_id, params->vdev_id, params->wake_intvl_us, + params->min_wake_intvl_us, params->max_wake_intvl_us, params->wake_intvl_mantis); - hdd_debug("twt: wake dura %d, sp_offset %d, cmd %d", - params->wake_dura_us, params->sp_offset_us, + + hdd_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d", + params->wake_dura_us, params->min_wake_dura_us, + params->max_wake_dura_us, params->sp_offset_us, params->twt_cmd); hdd_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d", params->flag_bcast, params->flag_trigger, @@ -689,6 +727,13 @@ uint32_t hdd_get_twt_setup_event_len(bool additional_params_present) uint32_t len = 0; len += NLMSG_HDRLEN; + + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + len += NLA_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ len += nla_total_size(sizeof(u8)); /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ @@ -904,12 +949,26 @@ static QDF_STATUS hdd_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb, struct twt_add_dialog_complete_event *event) { + struct nlattr *config_attr; uint64_t sp_offset_tsf; enum qca_wlan_vendor_twt_status vendor_status; int response_type; hdd_enter(); + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SET)) { + hdd_err("TWT: 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) { + hdd_err("TWT: nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + sp_offset_tsf = event->additional_params.sp_tsf_us_hi; sp_offset_tsf = (sp_offset_tsf << 32) | event->additional_params.sp_tsf_us_lo; @@ -1011,11 +1070,56 @@ hdd_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb, } } + nla_nest_end(reply_skb, config_attr); + hdd_exit(); return QDF_STATUS_SUCCESS; } +/** + * hdd_send_twt_setup_response - Send TWT setup response to userspace + * @hdd_handle: Pointer to opaque HDD handle + * @add_dialog_comp_ev_params: Add dialog completion event structure + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_send_twt_setup_response( + hdd_handle_t hdd_handle, + struct twt_add_dialog_complete_event *add_dialog_comp_ev_params) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + bool additional_params_present = false; + + if (add_dialog_comp_ev_params->params.num_additional_twt_params != 0) + additional_params_present = true; + + data_len = hdd_get_twt_setup_event_len(additional_params_present); + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("TWT: Alloc setup resp skb fail"); + return QDF_STATUS_E_NOMEM; + } + + status = hdd_twt_setup_pack_resp_nlmsg(twt_vendor_event, + add_dialog_comp_ev_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl add dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + return status; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + return status; +} + /** * hdd_twt_add_dialog_comp_cb() - HDD callback for twt add dialog * complete event @@ -1025,32 +1129,17 @@ hdd_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb, * Return: None */ static void -hdd_twt_add_dialog_comp_cb(void *context, +hdd_twt_add_dialog_comp_cb(hdd_handle_t hdd_handle, struct twt_add_dialog_complete_event *add_dialog_event) { - struct osif_request *request; - struct twt_add_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->add_dialog_comp_ev_buf, add_dialog_event, - sizeof(*add_dialog_event)); - osif_request_complete(request); - osif_request_put(request); - hdd_debug("TWT: add dialog_id:%d, status:%d vdev_id %d peer mac_addr " QDF_MAC_ADDR_FMT, add_dialog_event->params.dialog_id, add_dialog_event->params.status, add_dialog_event->params.vdev_id, QDF_MAC_ADDR_REF(add_dialog_event->params.peer_macaddr)); + hdd_send_twt_setup_response(hdd_handle, add_dialog_event); hdd_exit(); } @@ -1066,76 +1155,17 @@ static int hdd_send_twt_add_dialog_cmd(struct hdd_context *hdd_ctx, struct wmi_twt_add_dialog_param *twt_params) { - struct twt_add_dialog_complete_event *add_dialog_comp_ev_params; - struct twt_add_dialog_comp_ev_priv *priv; - static const struct osif_request_params osif_req_params = { - .priv_size = sizeof(*priv), - .timeout_ms = TWT_SETUP_COMPLETE_TIMEOUT, - .dealloc = NULL, - }; - struct osif_request *request; - struct sk_buff *reply_skb = NULL; - bool additional_params_present = false; - void *cookie; QDF_STATUS status; - 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_add_dialog_cmd(hdd_ctx->mac_handle, hdd_twt_add_dialog_comp_cb, - twt_params, - cookie); - if (!QDF_IS_STATUS_SUCCESS(status)) { + twt_params); + if (!QDF_IS_STATUS_SUCCESS(status)) hdd_err("Failed to send add dialog command"); - ret = qdf_status_to_os_return(status); - goto err; - } - ret = osif_request_wait_for_response(request); - if (ret) { - hdd_err("twt: add dialog req timedout"); - ret = -ETIMEDOUT; - goto err; - } + ret = qdf_status_to_os_return(status); - priv = osif_request_priv(request); - add_dialog_comp_ev_params = &priv->add_dialog_comp_ev_buf; - if (add_dialog_comp_ev_params->params.num_additional_twt_params != 0) - additional_params_present = true; - - skb_len = hdd_get_twt_setup_event_len(additional_params_present); - - reply_skb = 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_setup_pack_resp_nlmsg(reply_skb, - add_dialog_comp_ev_params); - if (QDF_IS_STATUS_ERROR(status)) { - hdd_err("Failed to pack nl add dialog response"); - ret = qdf_status_to_os_return(status); - goto err; - } - ret = cfg80211_vendor_cmd_reply(reply_skb); - -err: - if (request) - osif_request_put(request); - - if (ret && reply_skb) - kfree_skb(reply_skb); return ret; } diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 2bb4434509d4..5c7f3177d1d8 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -3686,14 +3686,12 @@ QDF_STATUS sme_register_twt_disable_complete_cb(mac_handle_t mac_handle, * @mac_handle: MAC handle * @twt_add_dialog_cb: Function callback to handle add_dialog event * @twt_params: TWT add dialog parameters - * @context: os_if_request cookie * * Return: QDF Status */ QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle, twt_add_dialog_cb twt_add_dialog_cb, - struct wmi_twt_add_dialog_param *twt_params, - void *context); + struct wmi_twt_add_dialog_param *twt_params); /** * sme_del_dialog_cmd() - Register callback and send TWT del dialog diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index eef8b2ab1d13..6df53c90ec9e 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-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 @@ -162,11 +162,10 @@ typedef void (*twt_disable_cb)(hdd_handle_t hdd_handle); /** * typedef twt_add_dialog_cb - TWT add dialog callback signature. - * @context: Opaque context that the client can use to associate the - * callback with the request. + * @hdd_handle: Opaque handle to the HDD context * @add_dialog_event: pointer to event buf containing twt response parameters */ -typedef void (*twt_add_dialog_cb)(void *context, +typedef void (*twt_add_dialog_cb)(hdd_handle_t hdd_handle, struct twt_add_dialog_complete_event *add_dialog_event); /** @@ -410,7 +409,6 @@ struct sme_context { 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_add_dialog_context; void *twt_del_dialog_context; void *twt_pause_dialog_context; void *twt_resume_dialog_context; diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 1599dabc5773..64ccd9d0ee2c 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -2062,13 +2062,11 @@ sme_process_twt_add_dialog_event(struct mac_context *mac, struct twt_add_dialog_complete_event *add_dialog_event) { twt_add_dialog_cb callback; - void *context; callback = mac->sme.twt_add_dialog_cb; - context = mac->sme.twt_add_dialog_context; mac->sme.twt_add_dialog_cb = NULL; if (callback) - callback(context, add_dialog_event); + callback(mac->hdd_handle, add_dialog_event); } /** @@ -14513,8 +14511,7 @@ QDF_STATUS sme_deregister_twt_disable_complete_cb(mac_handle_t mac_handle) QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle, twt_add_dialog_cb twt_add_dialog_cb, - struct wmi_twt_add_dialog_param *twt_params, - void *context) + struct wmi_twt_add_dialog_param *twt_params) { struct mac_context *mac = MAC_CONTEXT(mac_handle); struct scheduler_msg twt_msg = {0}; @@ -14552,7 +14549,6 @@ QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle, /* Serialize the req through MC thread */ mac->sme.twt_add_dialog_cb = twt_add_dialog_cb; - mac->sme.twt_add_dialog_context = context; twt_msg.bodyptr = cmd_params; twt_msg.type = WMA_TWT_ADD_DIALOG_REQUEST; sme_release_global_lock(&mac->sme);