From 14bb318ac8b8fd1e38248ec75984236065bc8782 Mon Sep 17 00:00:00 2001
From: Ian Lin <ian.lin@infineon.com>
Date: Thu, 20 Oct 2022 21:02:43 -0500
Subject: [PATCH 126/296] non-upstream: Add IFX TWT Offload support

Define the NL80211 Vendor attributes and subcmd for IFX
TWT Setup/Teardown process, and add the corresponding subcmd handler.
The handler convert the TWT params from userspace into FW format,
then pass it to FW through iovar "twt"


Signed-off-by: Ian Lin <ian.lin@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/Makefile      |   3 +-
 .../broadcom/brcm80211/brcmfmac/cfg80211.c    |  10 +
 .../broadcom/brcm80211/brcmfmac/fweh.h        |   1 +
 .../broadcom/brcm80211/brcmfmac/vendor.c      |   9 +
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.c  | 373 +++++++++++++++++
 .../broadcom/brcm80211/brcmfmac/vendor_ifx.h  | 375 +++++++++++++++++-
 6 files changed, 765 insertions(+), 6 deletions(-)
 create mode 100644 drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
index 9cfa6429ae03..7d620029b32d 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile
@@ -25,7 +25,8 @@ brcmfmac-objs += \
 		btcoex.o \
 		vendor.o \
 		pno.o \
-		xtlv.o
+		xtlv.o \
+		vendor_ifx.o
 brcmfmac-$(CONFIG_BRCMFMAC_PROTO_BCDC) += \
 		bcdc.o \
 		fwsignal.o
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index bf695010dee8..736e3f6c2f39 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -7971,6 +7971,14 @@ brcmf_notify_beacon_loss(struct brcmf_if *ifp,
 	return 0;
 }
 
+int brcmf_notify_twt(struct brcmf_if *ifp,
+				     const struct brcmf_event_msg *e,
+				     void *data)
+{
+	brcmf_dbg(TRACE, "Enter\n");
+	return 0;
+}
+
 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
 {
 	conf->frag_threshold = (u32)-1;
@@ -8029,6 +8037,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
 			    brcmf_notify_rssi_change_ind);
 	brcmf_fweh_register(cfg->pub, BRCMF_E_BCNLOST_MSG,
 			    brcmf_notify_beacon_loss);
+	brcmf_fweh_register(cfg->pub, BRCMF_E_TWT_SETUP,
+				brcmf_notify_twt);
 }
 
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
index f92700237d0c..0950131e6ed6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
@@ -93,6 +93,7 @@ struct brcmf_cfg80211_info;
 	BRCMF_ENUM_DEF(PHY_TEMP, 111) \
 	BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
 	BRCMF_ENUM_DEF(ULP, 146) \
+	BRCMF_ENUM_DEF(TWT_SETUP, 157) \
 	BRCMF_ENUM_DEF(EXT_AUTH_REQ, 187) \
 	BRCMF_ENUM_DEF(EXT_AUTH_FRAME_RX, 188) \
 	BRCMF_ENUM_DEF(MGMT_FRAME_TXSTATUS, 189) \
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
index fe181a5b8c3c..aff77e1028df 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor.c
@@ -254,6 +254,15 @@ const struct wiphy_vendor_command brcmf_vendor_cmds[] = {
 			   VENDOR_CMD_RAW_DATA,
 			   brcmf_cfg80211_vndr_cmds_frameburst)
 	},
+	{
+		IFX_SUBCMD(TWT,
+			   (WIPHY_VENDOR_CMD_NEED_WDEV |
+			    WIPHY_VENDOR_CMD_NEED_NETDEV),
+			   ifx_vendor_attr_twt_policy,
+			   ifx_cfg80211_vndr_cmds_twt),
+		.maxattr = IFX_VENDOR_ATTR_TWT_MAX
+	},
+
 };
 
 const struct nl80211_vendor_cmd_info brcmf_vendor_events[] = {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
new file mode 100644
index 000000000000..3e04a7dfe7cd
--- /dev/null
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.c
@@ -0,0 +1,373 @@
+/*
+ * Infineon WLAN driver: vendor specific implement
+ *
+ * ©2022 Cypress Semiconductor Corporation (an Infineon company)
+ * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
+ * This software, including source code, documentation and related materials
+ * ("Software") is owned by Cypress Semiconductor Corporation or one of its
+ * affiliates ("Cypress") and is protected by and subject to
+ * worldwide patent protection (United States and foreign),
+ * United States copyright laws and international treaty provisions.
+ * Therefore, you may use this Software only as provided in the license agreement
+ * accompanying the software package from which you obtained this Software ("EULA").
+ * If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
+ * non-transferable license to copy, modify, and compile the Software source code
+ * solely for use in connection with Cypress's integrated circuit products.
+ * Any reproduction, modification, translation, compilation, or representation
+ * of this Software except as specified above is prohibited without
+ * the expresswritten permission of Cypress.
+ * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Cypress reserves the right to make changes to the Software without notice.
+ * Cypress does not assume any liability arising out of the application or
+ * use of the Software or any product or circuit described in the Software.
+ * Cypress does not authorize its products for use in any products where a malfunction
+ * or failure of the Cypress product may reasonably be expected to result in
+ * significant property damage, injury or death ("High Risk Product").
+ * By including Cypress's product in a High Risk Product, the manufacturer
+ * of such system or application assumes all risk of such use and in doing so
+ * agrees to indemnify Cypress against all liability.
+ */
+
+#include <net/netlink.h>
+#include "core.h"
+#include "cfg80211.h"
+#include "debug.h"
+#include "fwil.h"
+#include "vendor_ifx.h"
+
+/*
+ * Wake Duration derivation from Nominal Minimum Wake Duration
+ */
+static inline u32
+ifx_twt_min_twt_to_wake_dur(u8 min_twt, u8 min_twt_unit)
+{
+	u32 wake_dur;
+
+	if (min_twt_unit == 1) {
+		/*
+		 * If min_twt_unit is 1, then min_twt is
+		 * in units of TUs (i.e) 102400 usecs.
+		 */
+		wake_dur = (u32)min_twt * 102400;
+	} else if (min_twt_unit == 0) {
+		/*
+		 * If min_twt_unit is 0, then min_twt is
+		 * in units of 256 usecs.
+		 */
+		wake_dur = (u32)min_twt * 256;
+	} else {
+		/* Invalid min_twt */
+		wake_dur = 0;
+	}
+
+	return wake_dur;
+}
+
+/*
+ * Wake Interval derivation from Wake Interval Mantissa & Exponent
+ */
+static inline u32
+ifx_twt_float_to_uint32(u8 exponent, u16 mantissa)
+{
+	return (u32)mantissa << exponent;
+}
+
+int ifx_twt_setup(struct wireless_dev *wdev, struct ifx_twt twt)
+{
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	ifx_twt_setup_t val;
+	s32 err;
+
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+
+	memset(&val, 0, sizeof(val));
+	val.version = IFX_TWT_SETUP_VER;
+	val.length = sizeof(val.version) + sizeof(val.length);
+
+	/* Default values, Override Below */
+	val.desc.flow_flags = 0x0;
+	val.desc.wake_dur = 0xFFFFFFFF;
+	val.desc.wake_int = 0xFFFFFFFF;
+	val.desc.wake_int_max = 0xFFFFFFFF;
+
+	/* Setup command */
+	val.desc.setup_cmd = twt.setup_cmd;
+
+	/* Flow flags */
+	val.desc.flow_flags |= ((twt.negotiation_type & 0x02) >> 1 ?
+				IFX_TWT_FLOW_FLAG_BROADCAST : 0);
+	val.desc.flow_flags |= (twt.implicit ? IFX_TWT_FLOW_FLAG_IMPLICIT : 0);
+	val.desc.flow_flags |= (twt.flow_type ? IFX_TWT_FLOW_FLAG_UNANNOUNCED : 0);
+	val.desc.flow_flags |= (twt.trigger ? IFX_TWT_FLOW_FLAG_TRIGGER : 0);
+	val.desc.flow_flags |= ((twt.negotiation_type & 0x01) ?
+				IFX_TWT_FLOW_FLAG_WAKE_TBTT_NEGO : 0);
+	val.desc.flow_flags |= (twt.requestor ? IFX_TWT_FLOW_FLAG_REQUEST : 0);
+	val.desc.flow_flags |= (twt.protection ? IFX_TWT_FLOW_FLAG_PROTECT : 0);
+
+	if (twt.flow_id) {
+		/* Flow ID */
+		val.desc.flow_id = twt.flow_id;
+	} else if (twt.bcast_twt_id) {
+		/* Broadcast TWT ID */
+		val.desc.bid = twt.bcast_twt_id;
+	} else {
+		/* Let the FW choose the Flow ID, Broadcast TWT ID */
+		val.desc.flow_id = 0xFF;
+		val.desc.bid = 0xFF;
+	}
+
+	if (twt.twt) {
+		/* Target Wake Time parameter */
+		val.desc.wake_time_h = (u32)(twt.twt >> 32);
+		val.desc.wake_time_l = (u32)(twt.twt);
+		val.desc.wake_type = IFX_TWT_TIME_TYPE_BSS;
+	} else if (twt.twt_offset) {
+		/* Target Wake Time offset parameter */
+		val.desc.wake_time_h = (u32)(twt.twt_offset >> 32);
+		val.desc.wake_time_l = (u32)(twt.twt_offset);
+		val.desc.wake_type = IFX_TWT_TIME_TYPE_OFFSET;
+	} else {
+		/* Let the FW choose the Target Wake Time */
+		val.desc.wake_time_h = 0x0;
+		val.desc.wake_time_l = 0x0;
+		val.desc.wake_type = IFX_TWT_TIME_TYPE_AUTO;
+	}
+
+	/* Wake Duration or Service Period */
+	val.desc.wake_dur = ifx_twt_min_twt_to_wake_dur(twt.min_twt,
+							      twt.min_twt_unit);
+	/* Wake Interval or Service Interval */
+	val.desc.wake_int = ifx_twt_float_to_uint32(twt.exponent,
+							  twt.mantissa);
+	/* TWT Negotiation_type */
+	val.desc.negotiation_type = (u8)twt.negotiation_type;
+	err = brcmf_fil_xtlv_data_set(ifp, "twt", IFX_TWT_CMD_SETUP,
+		(void *)&val, sizeof(val));
+
+	brcmf_dbg(TRACE, "TWT setup\n"
+		"Setup command	: %u\n"
+		"Flow flags 	: 0x %02x\n"
+		"Flow ID		: %u\n"
+		"Broadcast TWT ID	: %u\n"
+		"Wake Time H,L	: 0x %08x %08x\n"
+		"Wake Type		: %u\n"
+		"Wake Dururation	: %u usecs\n"
+		"Wake Interval	: %u usecs\n"
+		"Negotiation type	: %u\n",
+		val.desc.setup_cmd,
+		val.desc.flow_flags,
+		val.desc.flow_id,
+		val.desc.bid,
+		val.desc.wake_time_h,
+		val.desc.wake_time_l,
+		val.desc.wake_type,
+		val.desc.wake_dur,
+		val.desc.wake_int,
+		val.desc.negotiation_type);
+
+	if (err < 0) {
+		brcmf_err("TWT setup failed. ret:%d\n", err);
+	} 
+
+	return err;
+}
+
+int ifx_twt_teardown(struct wireless_dev *wdev, struct ifx_twt twt)
+{
+	struct brcmf_cfg80211_vif *vif;
+	struct brcmf_if *ifp;
+	ifx_twt_teardown_t val;
+	s32 err;
+
+	vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+	ifp = vif->ifp;
+
+	memset(&val, 0, sizeof(val));
+	val.version = IFX_TWT_TEARDOWN_VER;
+	val.length = sizeof(val.version) + sizeof(val.length);
+
+	if (twt.flow_id) {
+		/* Flow ID */
+		val.teardesc.flow_id = twt.flow_id;
+	} else if (twt.bcast_twt_id) {
+		/* Broadcast TWT ID */
+		val.teardesc.bid = twt.bcast_twt_id;
+	} else {
+		/* Let the FW choose the Flow ID, Broadcast TWT */
+		val.teardesc.flow_id = 0xFF;
+		val.teardesc.bid = 0xFF;
+	}
+
+	/* TWT Negotiation_type */
+	val.teardesc.negotiation_type = (u8)twt.negotiation_type;
+	/* Teardown all Negotiated TWT */
+	val.teardesc.alltwt = twt.teardown_all_twt;
+	err = brcmf_fil_xtlv_data_set(ifp, "twt", IFX_TWT_CMD_TEARDOWN,
+		(void *)&val, sizeof(val));
+
+	brcmf_dbg(TRACE, "TWT teardown\n"
+		"Flow ID		: %u\n"
+		"Broadcast TWT ID	: %u\n"
+		"Negotiation type	: %u\n"
+		"Teardown all TWT	: %u\n",
+		val.teardesc.flow_id,
+		val.teardesc.bid,
+		val.teardesc.negotiation_type,
+		val.teardesc.alltwt);
+
+	if (err < 0) {
+		brcmf_err("TWT teardown failed. ret:%d\n", err);
+	} 
+
+	return err;
+}
+
+int ifx_twt_oper(struct wireless_dev *wdev, struct ifx_twt twt)
+{
+	int ret = -1;
+
+	switch (twt.twt_oper) {
+		case IFX_TWT_OPER_SETUP:
+			ret = ifx_twt_setup(wdev, twt);
+			break;
+		case IFX_TWT_OPER_TEARDOWN:
+			ret = ifx_twt_teardown(wdev, twt);
+			break;
+		default:
+			brcmf_err("Requested TWT operation (%d) is not supported\n",
+				twt.twt_oper);
+			ret = -EINVAL;
+			goto exit;
+	}
+exit:
+	return ret;
+}
+
+static void
+ifx_cfgvendor_twt_parse_params(const struct nlattr *attr_iter, 
+	struct ifx_twt *twt)
+{
+	int tmp, twt_param;
+	const struct nlattr *twt_param_iter;
+
+	nla_for_each_nested(twt_param_iter, attr_iter, tmp) {
+		twt_param = nla_type(twt_param_iter);
+		switch (twt_param) {
+			case IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE:
+				twt->negotiation_type = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE:
+				twt->setup_cmd = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN:
+				twt->dialog_token = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME:
+				twt->twt = nla_get_u64(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME_OFFSET:
+				twt->twt_offset = nla_get_u64(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION:
+				twt->min_twt = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT:
+				twt->exponent = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA:
+				twt->mantissa = nla_get_u16(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR:
+				twt->requestor = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER:
+				twt->trigger = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT:
+				twt->implicit = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE:
+				twt->flow_type = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID:
+				twt->flow_id = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID:
+				twt->bcast_twt_id = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION:
+				twt->protection = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL:
+				twt->twt_channel = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED:
+				twt->twt_info_frame_disabled =
+					nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT:
+				twt->min_twt_unit = nla_get_u8(twt_param_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAM_TEARDOWN_ALL_TWT:
+				twt->teardown_all_twt =
+					nla_get_u8(twt_param_iter);
+				break;
+			default:
+				brcmf_dbg(TRACE, "Unknown TWT param %d, skipping\n", 
+					twt_param);
+				break;
+		}
+	}
+}
+
+int ifx_cfg80211_vndr_cmds_twt(struct wiphy *wiphy, 
+	struct wireless_dev *wdev, const void  *data, int len)
+{
+	int tmp, attr_type;
+	const struct nlattr *attr_iter;
+
+	struct ifx_twt twt = {
+		.twt_oper = 0,
+		.negotiation_type = IFX_TWT_PARAM_NEGO_TYPE_ITWT,
+		.setup_cmd = IFX_TWT_OPER_SETUP_CMD_TYPE_REQUEST,
+		.dialog_token = 1,
+		.twt = 0,
+		.twt_offset = 0,
+		.requestor = 1,
+		.trigger = 0,
+		.implicit = 1,
+		.flow_type = 0,
+		.flow_id = 0,
+		.bcast_twt_id = 0,
+		.protection = 0,
+		.twt_channel = 0,
+		.twt_info_frame_disabled = 0,
+		.min_twt_unit = 0,
+		.teardown_all_twt = 0
+	};
+
+	nla_for_each_attr(attr_iter, data, len, tmp) {
+		attr_type = nla_type(attr_iter);
+
+		switch (attr_type) {
+			case IFX_VENDOR_ATTR_TWT_OPER:
+				twt.twt_oper = nla_get_u8(attr_iter);
+				break;
+			case IFX_VENDOR_ATTR_TWT_PARAMS:
+				ifx_cfgvendor_twt_parse_params(attr_iter, &twt);
+				break;
+			default:
+				brcmf_dbg(TRACE, "Unknown TWT attribute %d, skipping\n",
+					   attr_type);
+				break;
+		}
+	}
+
+	return ifx_twt_oper(wdev, twt);
+}
+
+
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
index 522e617885e3..92bf53d26bce 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/vendor_ifx.h
@@ -1,13 +1,40 @@
-/* SPDX-License-Identifier: ISC
+/*
+ * Infineon WLAN driver: vendor specific implement
  *
- * Infineon Technologies OUI and vendor specific assignments
- *
- * $ Copyright Infineon $
+ * ©2022 Cypress Semiconductor Corporation (an Infineon company)
+ * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
+ * This software, including source code, documentation and related materials
+ * ("Software") is owned by Cypress Semiconductor Corporation or one of its
+ * affiliates ("Cypress") and is protected by and subject to
+ * worldwide patent protection (United States and foreign),
+ * United States copyright laws and international treaty provisions.
+ * Therefore, you may use this Software only as provided in the license agreement
+ * accompanying the software package from which you obtained this Software ("EULA").
+ * If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
+ * non-transferable license to copy, modify, and compile the Software source code
+ * solely for use in connection with Cypress's integrated circuit products.
+ * Any reproduction, modification, translation, compilation, or representation
+ * of this Software except as specified above is prohibited without
+ * the expresswritten permission of Cypress.
+ * Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Cypress reserves the right to make changes to the Software without notice.
+ * Cypress does not assume any liability arising out of the application or
+ * use of the Software or any product or circuit described in the Software.
+ * Cypress does not authorize its products for use in any products where a malfunction
+ * or failure of the Cypress product may reasonably be expected to result in
+ * significant property damage, injury or death ("High Risk Product").
+ * By including Cypress's product in a High Risk Product, the manufacturer
+ * of such system or application assumes all risk of such use and in doing so
+ * agrees to indemnify Cypress against all liability.
  */
 
 #ifndef IFX_VENDOR_H
 #define IFX_VENDOR_H
 
+#include <net/netlink.h>
+
 /* This file is a registry of identifier assignments from the Infineon
  * OUI 00:03:19 for purposes other than MAC address assignment. New identifiers
  * can be assigned through normal review process for changes to the upstream
@@ -56,7 +83,7 @@ enum ifx_nl80211_vendor_subcmds {
 	SCMD(RSV11)		= 11,
 	SCMD(RSV12)		= 12,
 	SCMD(RSV13)		= 13,
-	SCMD(RSV14)		= 14,
+	SCMD(TWT)		= 14,
 	SCMD(RSV15)		= 15,
 	SCMD(MAX)		= 16
 };
@@ -78,5 +105,343 @@ enum ifx_vendor_attr {
 	IFX_VENDOR_ATTR_MAX		= 11
 };
 
+/* TWT define/enum/struct
+ */
+/* TWT cmd version*/
+#define IFX_TWT_SETUP_VER	0u
+#define IFX_TWT_TEARDOWN_VER	0u
+/* Flow flags */
+#define IFX_TWT_FLOW_FLAG_BROADCAST	(1 << 0)
+#define IFX_TWT_FLOW_FLAG_IMPLICIT	(1 << 1)
+#define IFX_TWT_FLOW_FLAG_UNANNOUNCED	(1 << 2)
+#define IFX_TWT_FLOW_FLAG_TRIGGER	(1 << 3)
+#define IFX_TWT_FLOW_FLAG_WAKE_TBTT_NEGO (1 << 4)
+#define IFX_TWT_FLOW_FLAG_REQUEST	(1 << 5)
+#define IFX_TWT_FLOW_FLAG_PROTECT	(1u << 0u)
+#define IFX_TWT_FLOW_FLAG_RESPONDER_PM	(1u << 6u)
+#define IFX_TWT_FLOW_FLAG_UNSOLICITED	(1u << 7u)
+/* Flow id */
+#define IFX_TWT_FLOW_ID_FID	0x07u	/* flow id */
+#define IFX_TWT_FLOW_ID_GID_MASK	0x70u	/* group id - broadcast TWT only */
+#define IFX_TWT_FLOW_ID_GID_SHIFT 4u
+#define IFX_TWT_INV_BCAST_ID	0xFFu
+#define IFX_TWT_INV_FLOW_ID	0xFFu
+/* auto flow_id */
+#define IFX_TWT_SETUP_FLOW_ID_AUTO	0xFFu
+/* auto broadcast ID */
+#define IFX_TWT_SETUP_BCAST_ID_AUTO	0xFFu
+/* Infinite persistence for broadcast schedule */
+#define IFX_TWT_INFINITE_BTWT_PERSIST	0xFFFFFFFFu
+/* Wake type */
+/* TODO: not yet finalized */
+#define IFX_TWT_TIME_TYPE_BSS	0u	/* The time specified in wake_time_h/l is
+					 * the BSS TSF time.
+					 */
+#define IFX_TWT_TIME_TYPE_OFFSET	1u	/* The time specified in wake_time_h/l is an offset
+					 * of the TSF time when the iovar is processed.
+					 */
+#define IFX_TWT_TIME_TYPE_AUTO	2u	/* The target wake time is chosen internally by the FW */
+ 
+/*
+ * enum ifx_vendor_attr_twt - Attributes for the TWT vendor command
+ *
+ * @IFX_VENDOR_ATTR_TWT_UNSPEC: Reserved value 0
+ *
+ * @IFX_VENDOR_ATTR_TWT_OPER: To specify the type of TWT operation
+ *	to be performed. Uses attributes defined in enum ifx_twt_oper.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAMS: Nester attributes representing the
+ *	parameters configured for TWT. These parameters are defined in
+ *	the enum ifx_vendor_attr_twt_param.
+ *
+ * @IFX_VENDOR_ATTR_TWT_MAX: This acts as a the tail of cmds list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_vendor_attr_twt {
+	IFX_VENDOR_ATTR_TWT_UNSPEC,
+	IFX_VENDOR_ATTR_TWT_OPER,
+	IFX_VENDOR_ATTR_TWT_PARAMS,
+	IFX_VENDOR_ATTR_TWT_MAX
+};
+
+/*
+ * enum ifx_twt_oper - TWT operation to be specified using the vendor
+ * attribute IFX_VENDOR_ATTR_TWT_OPER
+ *
+ * @IFX_TWT_OPER_UNSPEC: Reserved value 0
+ *
+ * @IFX_TWT_OPER_SETUP: Setup a TWT session. Required parameters are
+ *	obtained through the nested attrs under IFX_VENDOR_ATTR_TWT_PARAMS.
+ *
+ * @IFX_TWT_OPER_TEARDOWN: Teardown the already negotiated TWT session.
+ *	Required parameters are obtained through the nested attrs under
+ *	IFX_VENDOR_ATTR_TWT_PARAMS.
+ *
+ * @IFX_TWT_OPER_MAX: This acts as a the tail of the list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_twt_oper {
+	IFX_TWT_OPER_UNSPEC,
+	IFX_TWT_OPER_SETUP,
+	IFX_TWT_OPER_TEARDOWN,
+	IFX_TWT_OPER_MAX
+};
+
+/*
+ * enum ifx_vendor_attr_twt_param - TWT parameters
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_UNSPEC: Reserved value 0
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE: Specifies the type of Negotiation to be
+ *	done during Setup. The four possible types are
+ *	0 - Individual TWT Negotiation
+ *	1 - Wake TBTT Negotiation
+ *	2 - Broadcast TWT in Beacon
+ *	3 - Broadcast TWT Membership Negotiation
+ *
+ *	The possible values are defined in the enum ifx_twt_param_nego_type
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE: Specifies the type of TWT Setup frame
+ *	when sent by the TWT Requesting STA
+ *	0 - Request
+ *	1 - Suggest
+ *	2 - Demand
+ *
+ *	when sent by the TWT Responding STA.
+ *	3 - Grouping
+ *	4 - Accept
+ *	5 - Alternate
+ *	6 - Dictate
+ *	7 - Reject
+ *
+ *	The possible values are defined in the enum ifx_twt_oper_setup_cmd_type.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN: Dialog Token used by the TWT Requesting STA to
+ *	identify the TWT Setup request/response transaction.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME: Target Wake Time.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME_OFFSET: Target Wake Time Offset.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION: Nominal Minimum TWT Wake Duration.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT: TWT Wake Interval Exponent.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA: TWT Wake Interval Mantissa.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR: Specify this is a TWT Requesting / Responding STA.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER: Specify Trigger based / Non-Trigger based TWT Session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT: Specify Implicit / Explicit TWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE: Specify Un-Announced / Announced TWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID: Flow ID of an iTWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID: Brocast TWT ID of a bTWT session.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION: Specifies whether Tx within SP is protected.
+ *	Set to 1 to indicate that TXOPs within the TWT SPs shall be initiated
+ *	with a NAV protection mechanism, such as (MU) RTS/CTS or CTS-to-self frame;
+ *	otherwise, it shall set it to 0.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL: TWT channel field which is set to 0, unless
+ * 	the HE STA sets up a subchannel selective transmission operation.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED: TWT Information frame RX handing
+ *	disabled / enabled.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT: Nominal Minimum TWT Wake Duration
+ *	Unit. 0 represents unit in "256 usecs" and 1 represents unit in "TUs".
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_TEARDOWN_ALL_TWT: Teardown all negotiated TWT sessions.
+ *
+ * @IFX_VENDOR_ATTR_TWT_PARAM_MAX: This acts as a the tail of the list.
+ *      Make sure it located at the end of the list.
+ */
+enum ifx_vendor_attr_twt_param {
+	IFX_VENDOR_ATTR_TWT_PARAM_UNSPEC,
+	IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME_OFFSET,
+	IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT,
+	IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA,
+	IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR,
+	IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER,
+	IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT,
+	IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE,
+	IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID,
+	IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID,
+	IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION,
+	IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL,
+	IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED,
+	IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT,
+	IFX_VENDOR_ATTR_TWT_PARAM_TEARDOWN_ALL_TWT,
+	IFX_VENDOR_ATTR_TWT_PARAM_MAX
+};
+
+enum ifx_twt_param_nego_type {
+	IFX_TWT_PARAM_NEGO_TYPE_INVALID			= -1,
+	IFX_TWT_PARAM_NEGO_TYPE_ITWT			= 0,
+	IFX_TWT_PARAM_NEGO_TYPE_WAKE_TBTT		= 1,
+	IFX_TWT_PARAM_NEGO_TYPE_BTWT_IE_BCN		= 2,
+	IFX_TWT_PARAM_NEGO_TYPE_BTWT			= 3,
+	IFX_TWT_PARAM_NEGO_TYPE_MAX			= 4
+};
+
+enum ifx_twt_oper_setup_cmd_type {
+	IFX_TWT_OPER_SETUP_CMD_TYPE_INVALID	= -1,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_REQUEST	= 0,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_SUGGEST	= 1,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_DEMAND	= 2,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_GROUPING	= 3,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_ACCEPT	= 4,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_ALTERNATE	= 5,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_DICTATE	= 6,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_REJECT	= 7,
+	IFX_TWT_OPER_SETUP_CMD_TYPE_MAX		= 8
+};
+
+/* TWT top level command IDs */
+enum {
+	IFX_TWT_CMD_ENAB = 0,
+	IFX_TWT_CMD_SETUP = 1,
+	IFX_TWT_CMD_TEARDOWN = 2,
+	IFX_TWT_CMD_INFO = 3,
+	IFX_TWT_CMD_AUTOSCHED = 4,
+	IFX_TWT_CMD_STATS = 5,
+	IFX_TWT_CMD_EARLY_TERM_TIME = 6,
+	IFX_TWT_CMD_RESP_CONFIG = 7,
+	IFX_TWT_CMD_SPPS_ENAB = 8,
+	IFX_TWT_CMD_FEATURES = 9,
+	IFX_TWT_CMD_LAST
+};
+
+static const struct nla_policy
+ifx_vendor_attr_twt_param_policy[IFX_VENDOR_ATTR_TWT_PARAM_MAX + 1] = {
+	[IFX_VENDOR_ATTR_TWT_PARAM_UNSPEC] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_NEGO_TYPE] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_SETUP_CMD_TYPE] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_DIALOG_TOKEN] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME] = {.type = NLA_U64},
+	[IFX_VENDOR_ATTR_TWT_PARAM_WAKE_TIME_OFFSET] = {.type = NLA_U64},
+	[IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_EXPONENT] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_WAKE_INTVL_MANTISSA] = {.type = NLA_U16},
+	[IFX_VENDOR_ATTR_TWT_PARAM_REQUESTOR] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_TRIGGER] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_IMPLICIT] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_FLOW_TYPE] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_FLOW_ID] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_BCAST_TWT_ID] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_PROTECTION] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_CHANNEL] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_TWT_INFO_FRAME_DISABLED] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_MIN_WAKE_DURATION_UNIT] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_TEARDOWN_ALL_TWT] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAM_MAX] = {.type = NLA_U8},
+};
+
+static const struct nla_policy ifx_vendor_attr_twt_policy[IFX_VENDOR_ATTR_TWT_MAX + 1] = {
+	[IFX_VENDOR_ATTR_TWT_UNSPEC] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_OPER] = {.type = NLA_U8},
+	[IFX_VENDOR_ATTR_TWT_PARAMS] =
+		NLA_POLICY_NESTED(ifx_vendor_attr_twt_param_policy),
+	[IFX_VENDOR_ATTR_TWT_MAX] = {.type = NLA_U8},
+};
+
+struct ifx_twt {
+	u8 twt_oper;
+	enum ifx_twt_param_nego_type negotiation_type;
+	enum ifx_twt_oper_setup_cmd_type setup_cmd;
+	u8 dialog_token;
+	u64 twt;
+	u64 twt_offset;
+	u8 min_twt;
+	u8 exponent;
+	u16 mantissa;
+	u8 requestor;
+	u8 trigger;
+	u8 implicit;
+	u8 flow_type;
+	u8 flow_id;
+	u8 bcast_twt_id;
+	u8 protection;
+	u8 twt_channel;
+	u8 twt_info_frame_disabled;
+	u8 min_twt_unit;
+	u8 teardown_all_twt;
+};
+
+/*
+ * NOTES:
+ * ifx_twt_sdesc_t is used to support both broadcast TWT and individual TWT.
+ * Value in bit[0:2] in 'flow_id' field is interpreted differently:
+ * - flow id for individual TWT (when IFX_TWT_FLOW_FLAG_BROADCAST bit is NOT set
+ *   in 'flow_flags' field)
+ * - flow id as defined in Table 8-248l1 for broadcast TWT (when
+ *   IFX_TWT_FLOW_FLAG_BROADCAST bit is set)
+ * In latter case other bits could be used to differentiate different flows
+ * in order to support multiple broadcast TWTs with the same flow id.
+ */
+
+/* TWT Setup descriptor */
+typedef struct ifx_twt_sdesc {
+	/* Setup Command. */
+	u8 setup_cmd;		/* See TWT_SETUP_CMD_XXXX in 802.11ah.h */
+	u8 flow_flags;		/* Flow attributes. See WL_TWT_FLOW_FLAG_XXXX below */
+	u8 flow_id;		/* must be between 0 and 7. Set 0xFF for auto assignment */
+	u8 wake_type;	/* See WL_TWT_TIME_TYPE_XXXX below */
+	u32 wake_time_h;	/* target wake time - BSS TSF (us) */
+	u32 wake_time_l;
+	u32 wake_dur;	/* target wake duration in unit of microseconds */
+	u32 wake_int;	/* target wake interval */
+	u32 btwt_persistence;	/* Broadcast TWT Persistence */
+	u32 wake_int_max;	/* max wake interval(uS) for TWT */
+	u8 duty_cycle_min;	/* min duty cycle for TWT(Percentage) */
+	u8 pad;
+	u8 bid;		/* must be between 0 and 31. Set 0xFF for auto assignment */
+	u8 channel;		/* Twt channel - Not used for now */
+	u8 negotiation_type;	/* Negotiation Type: See macros TWT_NEGO_TYPE_X */
+	u8 frame_recomm;	/* frame recommendation for broadcast TWTs - Not used for now	 */
+} ifx_twt_sdesc_t;
+
+/* twt teardown descriptor */
+typedef struct ifx_twt_teardesc {
+	u8 negotiation_type;
+	u8 flow_id;		/* must be between 0 and 7 */
+	u8 bid;		/* must be between 0 and 31 */
+	u8 alltwt;		/* all twt teardown - 0 or 1 */
+} ifx_twt_teardesc_t;
+
+/* HE TWT Setup command */
+typedef struct ifx_twt_setup {
+	/* structure control */
+	u16 version;	/* structure version */
+	u16 length;	/* data length (starting after this field) */
+	/* peer address */
+	struct ether_addr peer;	/* leave it all 0s' for AP */
+	u8 pad[2];
+	/* setup descriptor */
+	ifx_twt_sdesc_t desc;
+} ifx_twt_setup_t;
+
+/* HE TWT Teardown command */
+typedef struct ifx_twt_teardown {
+	/* structure control */
+	u16 version;	/* structure version */
+	u16 length;	/* data length (starting after this field) */
+	/* peer address */
+	struct ether_addr peer;	/* leave it all 0s' for AP */
+	ifx_twt_teardesc_t teardesc;	/* Teardown descriptor */
+} ifx_twt_teardown_t;
+
+int ifx_cfg80211_vndr_cmds_twt(struct wiphy *wiphy, 
+	struct wireless_dev *wdev, const void  *data, int len);
+
 #endif /* IFX_VENDOR_H */
 
-- 
2.25.1

