From 14bb318ac8b8fd1e38248ec75984236065bc8782 Mon Sep 17 00:00:00 2001 From: Ian Lin 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 --- .../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 +#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 + /* 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