浏览代码

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
Pragaspathi Thilagaraj 4 年之前
父节点
当前提交
7a16e63693

+ 7 - 1
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

+ 4 - 1
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
@@ -1682,6 +1682,9 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
 		.subcmd = QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO,
 	},
 	FEATURE_THERMAL_VENDOR_EVENTS
+#ifdef WLAN_SUPPORT_TWT
+	FEATURE_TWT_VENDOR_EVENTS
+#endif
 };
 
 /**

+ 113 - 83
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
@@ -120,6 +120,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
@@ -255,6 +259,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");
@@ -283,11 +302,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,
@@ -706,6 +744,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 */
@@ -952,12 +997,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;
@@ -1059,11 +1118,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
@@ -1073,32 +1177,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();
 }
@@ -1114,76 +1203,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;
 }
 

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

@@ -3731,14 +3731,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

+ 3 - 5
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);
 
 /**
@@ -421,7 +420,6 @@ struct sme_context {
 	twt_pause_dialog_cb twt_pause_dialog_cb;
 	twt_nudge_dialog_cb twt_nudge_dialog_cb;
 	twt_resume_dialog_cb twt_resume_dialog_cb;
-	void *twt_add_dialog_context;
 	void *twt_del_dialog_context;
 	void *twt_pause_dialog_context;
 	void *twt_nudge_dialog_context;

+ 2 - 6
core/sme/src/common/sme_api.c

@@ -2092,13 +2092,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);
 }
 
 /**
@@ -14415,8 +14413,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};
@@ -14452,7 +14449,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);