From patchwork Fri Jul 16 15:04:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382395 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05EEAC07E95 for ; Fri, 16 Jul 2021 15:04:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D693A60FF3 for ; Fri, 16 Jul 2021 15:04:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240584AbhGPPH2 (ORCPT ); Fri, 16 Jul 2021 11:07:28 -0400 Received: from mail.kernel.org ([198.145.29.99]:46616 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240066AbhGPPH2 (ORCPT ); Fri, 16 Jul 2021 11:07:28 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id A8C6A613BB; Fri, 16 Jul 2021 15:04:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447873; bh=to/GTuNdPYZGFsWyeqqcFW9/JkNAWYj8Ax7EsYA6g/U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UBVWYyjoibCj1xYowSFBIg9g2Yp/rBRsrlbyK93MOQf2Bg8yHH2jAHBOBi7aaVAfF EEvYje0YI33//SyS9kJX5lV9lFXp2XF8SfwgNCxVDfBlGWAxAwsg56KmAVXBf/HzNO zxRf9hBaXIfZ+GOecA6L7hnba57km+92Lj2MElEseVVemykr1lI57wnPoO3GcJv5RF l/e0LQbRtMeBK0aXfsYN7OPfIRWVRXCH3XzOS6qSo/8mLXE3HL/fIegPRJ8QQSwoYY KJOeTlEb5jmquR8//xnrnswPAKduxBq0kLHcZwZoG4pc31DgVrgM6QuX80xBPiHM9L m9+7bUCgXAt/g== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 1/7] mac80211: add twt ie in ieee80211_mgmt structure Date: Fri, 16 Jul 2021 17:04:00 +0200 Message-Id: <9d724d46c893268560d744a46de62dd026112d15.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Introduce TWT definitions and TWT Information element structure in ieee80211.h Signed-off-by: Lorenzo Bianconi --- include/linux/ieee80211.h | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 2967437f1b11..29afa2b74bae 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1088,6 +1088,53 @@ struct ieee80211_ext { } u; } __packed __aligned(2); +#define IEEE80211_TWT_CONTROL_NDP BIT(0) +#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1) +#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(2) +#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4) +#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5) + +#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0) +#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1) +#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4) +#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5) +#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6) +#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7) +#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10) +#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15) + +enum ieee80211_twt_setup_cmd { + TWT_SETUP_CMD_REQUEST, + TWT_SETUP_CMD_SUGGEST, + TWT_SETUP_CMD_DEMAND, + TWT_SETUP_CMD_GROUPING, + TWT_SETUP_CMD_ACCEPT, + TWT_SETUP_CMD_ALTERNATE, + TWT_SETUP_CMD_DICTATE, + TWT_SETUP_CMD_REJECT, +}; + +struct ieee80211_twt_params { + u8 control; + __le16 req_type; + __le64 twt; + u8 min_twt_dur; + __le16 mantissa; + u8 channel; +} __packed; + +struct ieee80211_twt_setup { + u8 dialog_token; + u8 element_id; + u8 length; + u8 params[0]; +} __packed; + +#define IEEE80211_TWT_IND_SETUP_SIZE \ + (IEEE80211_MIN_ACTION_SIZE + 1 + \ + sizeof(struct ieee80211_twt_setup) + \ + sizeof(struct ieee80211_twt_params)) + struct ieee80211_mgmt { __le16 frame_control; __le16 duration; @@ -1252,6 +1299,10 @@ struct ieee80211_mgmt { __le16 toa_error; u8 variable[0]; } __packed ftm; + struct { + u8 action_code; + u8 variable[0]; + } __packed s1g; } u; } __packed action; } u; @@ -2879,6 +2930,7 @@ enum ieee80211_eid { WLAN_EID_AID_RESPONSE = 211, WLAN_EID_S1G_BCN_COMPAT = 213, WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214, + WLAN_EID_S1G_TWT = 216, WLAN_EID_S1G_CAPABILITIES = 217, WLAN_EID_VENDOR_SPECIFIC = 221, WLAN_EID_QOS_PARAMETER = 222, @@ -2947,6 +2999,7 @@ enum ieee80211_category { WLAN_CATEGORY_FST = 18, WLAN_CATEGORY_UNPROT_DMG = 20, WLAN_CATEGORY_VHT = 21, + WLAN_CATEGORY_S1G = 22, WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, WLAN_CATEGORY_VENDOR_SPECIFIC = 127, }; @@ -3020,6 +3073,20 @@ enum ieee80211_key_len { WLAN_KEY_LEN_BIP_GMAC_256 = 32, }; +enum ieee80211_s1g_actioncode { + WLAN_S1G_AID_SWITCH_REQUEST, + WLAN_S1G_AID_SWITCH_RESPONSE, + WLAN_S1G_SYNC_CONTROL, + WLAN_S1G_STA_INFO_ANNOUNCE, + WLAN_S1G_EDCA_PARAM_SET, + WLAN_S1G_EL_OPERATION, + WLAN_S1G_TWT_SETUP, + WLAN_S1G_TWT_TEARDOWN, + WLAN_S1G_SECT_GROUP_ID_LIST, + WLAN_S1G_SECT_ID_FEEDBACK, + WLAN_S1G_TWT_INFORMATION = 11, +}; + #define IEEE80211_WEP_IV_LEN 4 #define IEEE80211_WEP_ICV_LEN 4 #define IEEE80211_CCMP_HDR_LEN 8 From patchwork Fri Jul 16 15:04:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382397 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9EA16C636CA for ; Fri, 16 Jul 2021 15:04:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7F7A960FF3 for ; Fri, 16 Jul 2021 15:04:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240635AbhGPPHb (ORCPT ); Fri, 16 Jul 2021 11:07:31 -0400 Received: from mail.kernel.org ([198.145.29.99]:46646 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240645AbhGPPHb (ORCPT ); Fri, 16 Jul 2021 11:07:31 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 161B3613CF; Fri, 16 Jul 2021 15:04:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447876; bh=+oRoMlZupxSXsPxBADGfONvU0iOMjqE4DR1w2Z9J5fg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CN4Ey2jiJvK9NBQ29+6wdzDlu808z39CAETBqh8Y12nwwqq1DjM6fxqjfakYOg4lC pbD9RMnqKiNeigK2hGOBPj7cfAG9FxMZDNE3sQ1+W4t8TMa9yPUXEhyywlYrTZmka0 eFyKV1uPucbrFX42v1U3yocm8aM2g9YgaQedoxXii135GQI3iAI0/RTstS2bGpOtRE HLrW9ElXIWbAnbUYpxpAcpXvdNaQyLrnDFvdDYbDHHS7ScASuzWxpoa/9QzgarQTUB 4a25euqHKZlqXIpusB1MIE3jPpZ/kaUoguCT9K/YxaKwN/BHPXlu0bhoUvQ9aKxOax nUHpM89zS6rIQ== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 2/7] mac80211: introduce individual TWT support in AP mode. Date: Fri, 16 Jul 2021 17:04:01 +0200 Message-Id: <31389d3256d05dd6fae7fbeb13bc5c0ceb653096.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Introduce TWT action frames parsing support to mac80211. Currently just individual TWT agreement are support in AP mode. Whenever the AP receives a TWT action frame from an associated client, after performing sanity checks, it will notify the underlay driver with requested parameters in order to check if they are supported and if there is enough room for a new agreement. The hw is expected to set agreement result and report it to mac80211. The two following drv callbacks have been added to mac80211: - add_twt_setup (mandatory) - twt_teardown_request (optional) mac80211 will send an action frame reply according to the result reported by the driver/fw. Signed-off-by: Lorenzo Bianconi --- include/net/mac80211.h | 13 +++ net/mac80211/driver-ops.h | 24 +++++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/iface.c | 10 ++ net/mac80211/rx.c | 54 +++++++++++ net/mac80211/s1g.c | 183 +++++++++++++++++++++++++++++++++++++ net/mac80211/status.c | 30 +++++- 7 files changed, 316 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e89530d0d9c6..bd98d3257f2a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3898,6 +3898,13 @@ enum ieee80211_reconfig_type { * @set_sar_specs: Update the SAR (TX power) settings. * @sta_set_decap_offload: Called to notify the driver when a station is allowed * to use rx decapsulation offload + * @add_twt_setup: Update hw with TWT agreement parameters received from the peer. + * This callback allows the hw to check if requested parameters + * are supported and if there is enough room for a new agreement. + * The hw is expected to set agreement result in the req_type field of + * agrt_resp structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, @@ -4218,6 +4225,12 @@ struct ieee80211_ops { void (*sta_set_decap_offload)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled); + int (*add_twt_setup)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_params *agrt_req, + struct ieee80211_twt_params *agrt_resp); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); }; /** diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 604ca59937f0..79dc83d61c19 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -1429,4 +1429,28 @@ static inline void drv_sta_set_decap_offload(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_add_twt_setup(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + struct ieee80211_twt_params *agrt_req, + struct ieee80211_twt_params *agrt_resp) +{ + might_sleep(); + check_sdata_in_driver(sdata); + + return local->ops->add_twt_setup(&local->hw, sta, agrt_req, agrt_resp); +} + +static inline void drv_twt_teardown_request(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + u8 flowid) +{ + might_sleep(); + check_sdata_in_driver(sdata); + + if (local->ops->twt_teardown_request) + local->ops->twt_teardown_request(&local->hw, sta, flowid); +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 648696b49f89..c0f6fe6d38e1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1912,6 +1912,9 @@ ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, /* S1G */ void ieee80211_s1g_sta_rate_init(struct sta_info *sta); +bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb); +int ieee80211_s1g_h_twt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb); /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 137fa4c50e07..b05cec75a733 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1396,6 +1396,16 @@ static void ieee80211_iface_work(struct work_struct *work) WARN_ON(1); break; } + } else if (ieee80211_is_action(mgmt->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_S1G) { + switch (mgmt->u.action.u.s1g.action_code) { + case WLAN_S1G_TWT_TEARDOWN: + case WLAN_S1G_TWT_SETUP: + ieee80211_s1g_h_twt(sdata, skb); + break; + default: + break; + } } else if (ieee80211_is_ext(mgmt->frame_control)) { if (sdata->vif.type == NL80211_IFTYPE_STATION) ieee80211_sta_rx_queued_ext(sdata, skb); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index af0ef456eb0f..683ec5e4182a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3198,6 +3198,50 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) return RX_CONTINUE; } +static ieee80211_rx_result debug_noinline +ieee80211_rx_h_twt(struct ieee80211_rx_data *rx) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data; + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); + struct ieee80211_sub_if_data *sdata = rx->sdata; + const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_supported_band *sband; + + /* TWT actions are only supported in AP for the moment */ + if (sdata->vif.type != NL80211_IFTYPE_AP) + return RX_CONTINUE; + + sband = rx->local->hw.wiphy->bands[status->band]; + iftd = ieee80211_get_sband_iftype_data(sband, sdata->vif.type); + if (!iftd) + return RX_CONTINUE; + + if (!rx->local->ops->add_twt_setup) + return RX_CONTINUE; + + if (!(iftd->he_cap.he_cap_elem.mac_cap_info[0] & + IEEE80211_HE_MAC_CAP0_TWT_RES)) + return RX_CONTINUE; + + if (!rx->sta) + return RX_CONTINUE; + + switch (mgmt->u.action.u.s1g.action_code) { + case WLAN_S1G_TWT_SETUP: + if (rx->skb->len < IEEE80211_TWT_IND_SETUP_SIZE) + break; + return RX_QUEUED; + case WLAN_S1G_TWT_TEARDOWN: + if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2) + break; + return RX_QUEUED; + default: + break; + } + + return RX_CONTINUE; +} + static ieee80211_rx_result debug_noinline ieee80211_rx_h_action(struct ieee80211_rx_data *rx) { @@ -3477,6 +3521,16 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) !mesh_path_sel_is_hwmp(sdata)) break; goto queue; + case WLAN_CATEGORY_S1G: + switch (mgmt->u.action.u.s1g.action_code) { + case WLAN_S1G_TWT_SETUP: + case WLAN_S1G_TWT_TEARDOWN: + if (ieee80211_rx_h_twt(rx) != RX_CONTINUE) + goto queue; + default: + break; + } + break; } return RX_CONTINUE; diff --git a/net/mac80211/s1g.c b/net/mac80211/s1g.c index c33f332b049a..ce3a93776a1a 100644 --- a/net/mac80211/s1g.c +++ b/net/mac80211/s1g.c @@ -6,6 +6,7 @@ #include #include #include "ieee80211_i.h" +#include "driver-ops.h" void ieee80211_s1g_sta_rate_init(struct sta_info *sta) { @@ -14,3 +15,185 @@ void ieee80211_s1g_sta_rate_init(struct sta_info *sta) sta->rx_stats.last_rate = STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G); } + +bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + if (likely(!ieee80211_is_action(mgmt->frame_control))) + return false; + + if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G)) + return false; + + return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP; +} + +static int +ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, + const u8 *da, const u8 *bssid, u8 dialog_token, + struct ieee80211_twt_params *params) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_twt_setup *twt; + struct ieee80211_mgmt *mgmt; + struct sk_buff *skb; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + IEEE80211_TWT_IND_SETUP_SIZE); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = skb_put_zero(skb, IEEE80211_TWT_IND_SETUP_SIZE); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); + + mgmt->u.action.category = WLAN_CATEGORY_S1G; + mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP; + + twt = (struct ieee80211_twt_setup *)mgmt->u.action.u.s1g.variable; + twt->dialog_token = dialog_token; + twt->element_id = WLAN_EID_S1G_TWT; + twt->length = sizeof(struct ieee80211_twt_params); + + memcpy(twt->params, params, twt->length); + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_REQ_TX_STATUS; + ieee80211_tx_skb(sdata, skb); + + return 0; +} + +static int +ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata, + const u8 *da, const u8 *bssid, u8 flowid) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_mgmt *mgmt; + struct sk_buff *skb; + u8 *id; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + IEEE80211_MIN_ACTION_SIZE + 2); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); + + mgmt->u.action.category = WLAN_CATEGORY_S1G; + mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN; + id = (u8 *)mgmt->u.action.u.s1g.variable; + *id = flowid; + + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_REQ_TX_STATUS; + ieee80211_tx_skb(sdata, skb); + + return 0; +} + +static int +ieee80211_s1g_rx_h_twt_setup(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_twt_params *agrt_req, agrt_resp; + struct ieee80211_twt_setup *twt; + + twt = (struct ieee80211_twt_setup *)mgmt->u.action.u.s1g.variable; + if (twt->element_id != WLAN_EID_S1G_TWT) + return -EINVAL; + + agrt_req = (struct ieee80211_twt_params *)twt->params; + + /* broadcast TWT not supported yet */ + if (agrt_req->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) + return -EINVAL; + + drv_add_twt_setup(sdata->local, sdata, &sta->sta, agrt_req, + &agrt_resp); + + return ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, + twt->dialog_token, &agrt_resp); +} + +static int +ieee80211_s1g_status_twt_setup(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_twt_params *agrt_resp; + struct ieee80211_twt_setup *twt; + u8 flowid; + + if (info->flags & IEEE80211_TX_STAT_ACK) + return 0; /* nothing to do */ + + twt = (struct ieee80211_twt_setup *)mgmt->u.action.u.s1g.variable; + agrt_resp = (struct ieee80211_twt_params *)twt->params; + flowid = FIELD_GET(IEEE80211_TWT_REQTYPE_FLOWID, + le16_to_cpu(agrt_resp->req_type)); + + drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid); + + return ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, + sdata->vif.addr, flowid); +} + +static int +ieee80211_s1g_rx_h_twt_teardown(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + drv_twt_teardown_request(sdata->local, sdata, &sta->sta, + mgmt->u.action.u.s1g.variable[0]); + + return 0; +} + +int ieee80211_s1g_h_twt(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + const u8 *addr; + + mutex_lock(&local->sta_mtx); + + addr = skb->pkt_type == IEEE80211_TX_STATUS_MSG ? mgmt->da : mgmt->sa; + sta = sta_info_get_bss(sdata, addr); + if (!sta) + goto out; + + switch (mgmt->u.action.u.s1g.action_code) { + case WLAN_S1G_TWT_SETUP: + if (skb->pkt_type == IEEE80211_TX_STATUS_MSG) + ieee80211_s1g_status_twt_setup(sdata, sta, skb); + else + ieee80211_s1g_rx_h_twt_setup(sdata, sta, skb); + break; + case WLAN_S1G_TWT_TEARDOWN: + ieee80211_s1g_rx_h_twt_teardown(sdata, sta, skb); + break; + default: + break; + } + +out: + mutex_unlock(&local->sta_mtx); + return 0; +} diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 9baf185ee4c7..6fc37cf86eda 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -17,6 +17,29 @@ #include "led.h" #include "wme.h" +static struct sk_buff * +ieee80211_tx_queue_skb(struct ieee80211_hw *hw, + struct ieee80211_tx_status *status, + bool monitor) +{ + struct sk_buff *skb = status->skb; + struct sta_info *sta; + + if (!status->sta) + goto out; + + if (likely(!ieee80211_s1g_is_twt_setup(skb))) + goto out; + + sta = container_of(status->sta, struct sta_info, sta); + skb->pkt_type = IEEE80211_TX_STATUS_MSG; + skb_queue_tail(&sta->sdata->skb_queue, skb); + skb = monitor ? skb_clone(skb, GFP_ATOMIC) : NULL; + ieee80211_queue_work(hw, &sta->sdata->work); + +out: + return skb; +} void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb) @@ -1028,13 +1051,18 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, * with this test... */ if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) { - if (status->free_list) + skb = ieee80211_tx_queue_skb(hw, status, false); + if (skb && status->free_list) list_add_tail(&skb->list, status->free_list); else dev_kfree_skb(skb); return; } + skb = ieee80211_tx_queue_skb(hw, status, true); + if (!skb) + return; + /* send to monitor interfaces */ ieee80211_tx_monitor(local, skb, sband, retry_count, shift, send_to_cooked, status); From patchwork Fri Jul 16 15:04:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382399 X-Patchwork-Delegate: nbd@nbd.name Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D8D3C07E95 for ; Fri, 16 Jul 2021 15:04:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F7DC613F5 for ; Fri, 16 Jul 2021 15:04:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240667AbhGPPHd (ORCPT ); Fri, 16 Jul 2021 11:07:33 -0400 Received: from mail.kernel.org ([198.145.29.99]:46660 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240662AbhGPPHc (ORCPT ); Fri, 16 Jul 2021 11:07:32 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 0768A613BB; Fri, 16 Jul 2021 15:04:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447878; bh=+yusDybgvtZjiZ69LmYYLfIOL8jJA189Wo8a3SiajrU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=M09NljST+cYqGpOAgAnYqhCgcIwDPJOTI/A27xBqB90crQFdE4v2O9vq+5jeiSqNE 5c3yAtnBwEw/t/s2Y/lNIrrR2/w7Oa8+Ol2g2pS++rZGZEV5+WKa6dtDrMxWrFm+xP 2cZqbp9tyMquf6d7OHXtB9caLWkohuiLjU9A6O2LKyOdmxpoUn3EG6mzMpBiBBj37Q PdRMsSRQii81vD6vYgtH4GIE28AvZjQJbWtB28D7g+AfuhF39WoHgQyaqgpaBEjCN8 LKlBExq+rLlV8GQa5tDntG5sW11LOJqPC/JRJ9CoIeolYrEizvHZLDKqnGlxJCmEJ1 na1PKzWFjoMMw== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 3/7] mt76: mt7915: introduce __mt7915_get_tsf routine Date: Fri, 16 Jul 2021 17:04:02 +0200 Message-Id: <0fec698ce31e079a3567abeb710bf90c108db84c.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Introduce an unlocked verion of mt7915_get_tsf routine. This is a preliminary patch to add TWT support to mt7915. Signed-off-by: Lorenzo Bianconi --- .../net/wireless/mediatek/mt76/mt7915/main.c | 20 ++++++++++++++----- .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 48b5e2051bad..fa4fd04affd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -789,10 +789,8 @@ mt7915_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 -mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif) { - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool band = phy != &dev->phy; @@ -802,7 +800,7 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } tsf; u16 n; - mutex_lock(&dev->mt76.mutex); + lockdep_assert_held(&dev->mt76.mutex); n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; /* TSF software read */ @@ -811,9 +809,21 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); + return tsf.t64; +} + +static u64 +mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + u64 ret; + + mutex_lock(&dev->mt76.mutex); + ret = __mt7915_get_tsf(hw, mvif); mutex_unlock(&dev->mt76.mutex); - return tsf.t64; + return ret; } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index a6b5b300d415..068ef0f881b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -271,7 +271,7 @@ extern const struct ieee80211_ops mt7915_ops; extern const struct mt76_testmode_ops mt7915_testmode_ops; u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr); - +u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif); int mt7915_register_device(struct mt7915_dev *dev); void mt7915_unregister_device(struct mt7915_dev *dev); int mt7915_eeprom_init(struct mt7915_dev *dev); From patchwork Fri Jul 16 15:04:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382401 X-Patchwork-Delegate: nbd@nbd.name Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17042C12002 for ; Fri, 16 Jul 2021 15:04:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E8717613FB for ; Fri, 16 Jul 2021 15:04:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240672AbhGPPHi (ORCPT ); Fri, 16 Jul 2021 11:07:38 -0400 Received: from mail.kernel.org ([198.145.29.99]:46692 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240673AbhGPPHe (ORCPT ); Fri, 16 Jul 2021 11:07:34 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id DE907613CF; Fri, 16 Jul 2021 15:04:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447879; bh=33zyDZ6a/ygvaKYLVL5N2Kf6VXeQmdOfvCvfKnycAE8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lqCLdaRcWhFmRQSUE8WcVeBh9fnR9U/W8ptynDA7X9ZSxl6DIPWBGpCNJgv7gbyJQ gmZOsLBaPfw+ZZEsJAxim28iwEgD/vrlgMzRgn4rY34OTV9Rx4UarP2H5IDfoqFJ4p ZLzMKRSBGo2V682qGlNmFbVZFdB5QVjdwp31PuXxYV8hLO9+3cq+AQJkCW02sbYQ0W ckY2gOksLyNKU7hjV8wmQ6IWbEf2hUOdMLwYvZ1JsWrMs42m+iHGOmSIJLbxFKBHOl TScKKmUAZ71sMz+AIhq/0MMTC5PpghYxCfHLer322E+gZTxE+/P4S5dVQ23ehkYIih J5g0HyaFX5puw== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 4/7] mt76: mt7915: introduce mt7915_mcu_twt_agrt_update mcu command Date: Fri, 16 Jul 2021 17:04:03 +0200 Message-Id: <06007972db561e448364bb7720cf96d878f34137.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org This is a preliminary patch to add TWT support to mt7915 Signed-off-by: Lorenzo Bianconi --- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 50 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/mcu.h | 9 ++++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 19 +++++++ 3 files changed, 78 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f84c49969479..2266bc1c0de0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -3904,3 +3904,53 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, return ret; } + +#define TWT_AGRT_TRIGGER BIT(0) +#define TWT_AGRT_ANNOUNCE BIT(1) +#define TWT_AGRT_PROTECT BIT(2) + +int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, + struct mt7915_vif *mvif, + struct mt7915_twt_flow *flow, + int cmd) +{ + struct { + u8 tbl_idx; + u8 cmd; + u8 own_mac_idx; + u8 flowid; /* 0xff for group id */ + __le16 peer_id; /* specify the peer_id (msb=0) + * or group_id (msb=1) + */ + u8 duration; /* 256 us */ + u8 bss_idx; + __le64 start_tsf; + __le16 mantissa; + u8 exponent; + u8 is_ap; + u8 agrt_params; + u8 rsv[23]; + } __packed req = { + .tbl_idx = flow->id, + .cmd = cmd, + .own_mac_idx = mvif->omac_idx, + .flowid = flow->id, + .peer_id = cpu_to_le16(flow->wcid), + .duration = flow->duration, + .bss_idx = mvif->idx, + .start_tsf = cpu_to_le64(flow->tsf), + .mantissa = flow->mantissa, + .exponent = flow->exp, + .is_ap = true, + }; + + if (flow->protection) + req.agrt_params |= TWT_AGRT_PROTECT; + if (!flow->flowtype) + req.agrt_params |= TWT_AGRT_ANNOUNCE; + if (flow->trigger) + req.agrt_params |= TWT_AGRT_TRIGGER; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE), + &req, sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index baa27dab0499..f4ba343b9413 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -276,6 +276,7 @@ enum { MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, + MCU_EXT_CMD_TWT_AGRT_UPDATE = 0x94, MCU_EXT_CMD_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_SET_RDD_TH = 0x9d, MCU_EXT_CMD_SET_SPR = 0xa8, @@ -284,6 +285,14 @@ enum { MCU_EXT_CMD_PHY_STAT_INFO = 0xad, }; +enum { + MCU_TWT_AGRT_ADD, + MCU_TWT_AGRT_MODIFY, + MCU_TWT_AGRT_DELETE, + MCU_TWT_AGRT_TEARDOWN, + MCU_TWT_AGRT_GET_TSF, +}; + enum { MCU_WA_PARAM_CMD_QUERY, MCU_WA_PARAM_CMD_SET, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 068ef0f881b8..ad97980275a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -67,6 +67,21 @@ struct mt7915_sta_key_conf { u8 key[16]; }; +struct mt7915_twt_flow { + struct list_head list; + u64 start_tsf; + u64 tsf; + u32 duration; + u16 wcid; + __le16 mantissa; + u8 exp; + u8 id; + u8 protection:1; + u8 flowtype:1; + u8 trigger:1; + u8 sched:1; +}; + struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ @@ -284,6 +299,10 @@ int mt7915_dma_init(struct mt7915_dev *dev); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_mcu_init(struct mt7915_dev *dev); +int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, + struct mt7915_vif *mvif, + struct mt7915_twt_flow *flow, + int cmd); int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool enable); int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, From patchwork Fri Jul 16 15:04:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382403 X-Patchwork-Delegate: nbd@nbd.name Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 75600C07E95 for ; Fri, 16 Jul 2021 15:04:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 54333613CF for ; Fri, 16 Jul 2021 15:04:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240662AbhGPPHk (ORCPT ); Fri, 16 Jul 2021 11:07:40 -0400 Received: from mail.kernel.org ([198.145.29.99]:46708 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240673AbhGPPHi (ORCPT ); Fri, 16 Jul 2021 11:07:38 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CAE82613BB; Fri, 16 Jul 2021 15:04:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447881; bh=EoySSkDS9o+TR2CqVv1NrHYkkgGolJO9iovF39yGRsA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WuWxj8oXrLLHQOtvYLWZEjrFHyBK1Q+RbDQlxr5tFtmY2Z4eTJ+Wh/u4CI5sdQ+IM yfbdUzTWA6iHeTFLCSTdvHF3udiib5s0QHdpeLi1de+xfmLj9RWtzCwwnKwd+lyez0 wh3cNI91x0/LDme/EAjSggpa5cMn5OSt3GtvKjHhes0AZvNwgABc0VZWDFDu5Se2Fz zQWVf+mg1dpYumcRcoAmUtwCIylFG2ogKg62L0BvzgLi34vIhjKFlH7emIUWJoWvwq CNtF9mY2Nzt1c8TFKyW+GOuAaxYc9TChEjyz2Fjp7mYkz6dM4i1UTXgdUwC3V6b9ty yA+N9daDagYPw== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 5/7] mt76: mt7915: introduce mt7915_mac_add_twt_setup routine Date: Fri, 16 Jul 2021 17:04:04 +0200 Message-Id: <8c3d7b5992dbed2f622c9a74d26f3bcc67f3ce36.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Introduce individual TWT support to mt7915 in AP mode. Implement the two following mac80211 callbacks: - add_twt_setup - twt_teardown_request Signed-off-by: Lorenzo Bianconi --- .../net/wireless/mediatek/mt76/mt7915/init.c | 1 + .../net/wireless/mediatek/mt76/mt7915/mac.c | 193 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7915/main.c | 19 ++ .../wireless/mediatek/mt76/mt7915/mt7915.h | 18 ++ 4 files changed, 231 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 906dacef5bdf..3ed48542e122 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -790,6 +790,7 @@ int mt7915_register_device(struct mt7915_dev *dev) INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work); INIT_LIST_HEAD(&dev->sta_rc_list); INIT_LIST_HEAD(&dev->sta_poll_list); + INIT_LIST_HEAD(&dev->twt_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 3d5899e81f5b..429950ec7e77 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -6,6 +6,7 @@ #include "mt7915.h" #include "../dma.h" #include "mac.h" +#include "mcu.h" #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) @@ -2089,3 +2090,195 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) mt7915_dfs_stop_radar_detector(phy); return 0; } + +static int +mt7915_mac_twt_duration_align(int duration) +{ + return duration << 8; +} + +static u64 +mt7915_mac_twt_sched_list_add(struct mt7915_dev *dev, + struct mt7915_twt_flow *flow) +{ + struct mt7915_twt_flow *iter, *iter_next; + u32 duration = flow->duration << 8; + u64 start_tsf; + + iter = list_first_entry_or_null(&dev->twt_list, + struct mt7915_twt_flow, list); + if (!iter || !iter->sched || iter->start_tsf > duration) { + /* add flow as first entry in the list */ + list_add(&flow->list, &dev->twt_list); + return 0; + } + + list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) { + start_tsf = iter->start_tsf + + mt7915_mac_twt_duration_align(iter->duration); + if (list_is_last(&iter->list, &dev->twt_list)) + break; + + if (!iter_next->sched || + iter_next->start_tsf > start_tsf + duration) { + list_add(&flow->list, &iter->list); + goto out; + } + } + + /* add flow as last entry in the list */ + list_add_tail(&flow->list, &dev->twt_list); +out: + return start_tsf; +} + +static int mt7915_mac_check_twt_req(struct ieee80211_twt_params *req) +{ + u64 interval, duration = req->min_twt_dur << 8; + u16 mantissa = le16_to_cpu(req->mantissa); + u8 exp; + + /* only individual agreement supported */ + if (req->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) + return -EOPNOTSUPP; + + /* only 256us unit supported */ + if (req->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) + return -EOPNOTSUPP; + + if (!req->channel) + return -EOPNOTSUPP; + + /* explicit agreement not supported */ + if (!(req->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT))) + return -EOPNOTSUPP; + + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, + le16_to_cpu(req->req_type)); + + interval = (u64)mantissa << exp; + if (interval < duration) + return -EOPNOTSUPP; + + return 0; +} + +int mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_params *agrt_req, + struct ieee80211_twt_params *agrt_resp) +{ + enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + u16 req_type, mantissa = le16_to_cpu(agrt_req->mantissa); + enum ieee80211_twt_setup_cmd sta_setup_cmd; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_twt_flow *flow; + int flowid, err = -EINVAL; + u8 exp; + + /* init common fields */ + memset(agrt_resp, 0, sizeof(*agrt_resp)); + agrt_resp->control |= + (agrt_req->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | + (agrt_req->control & IEEE80211_TWT_CONTROL_RX_DISABLED); + + req_type = le16_to_cpu(agrt_req->req_type) & + ~IEEE80211_TWT_REQTYPE_REQUEST; + + agrt_resp->twt = agrt_req->twt; + agrt_resp->min_twt_dur = agrt_req->min_twt_dur; + agrt_resp->mantissa = agrt_req->mantissa; + agrt_resp->channel = agrt_req->channel; + + err = mt7915_mac_check_twt_req(agrt_req); + if (err) + goto out; + + mutex_lock(&dev->mt76.mutex); + + if (dev->n_twt_agrt == MT7915_MAX_TWT_AGRT) + goto unlock; + + if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) + goto unlock; + + flowid = ffs(~msta->twt.flowid_mask) - 1; + + req_type &= ~IEEE80211_TWT_REQTYPE_FLOWID; + req_type |= FIELD_PREP(IEEE80211_TWT_REQTYPE_FLOWID, flowid); + + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, + le16_to_cpu(agrt_req->req_type)); + sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, + le16_to_cpu(agrt_req->req_type)); + + flow = &msta->twt.flow[flowid]; + memset(flow, 0, sizeof(*flow)); + INIT_LIST_HEAD(&flow->list); + flow->wcid = msta->wcid.idx; + flow->id = flowid; + flow->duration = agrt_req->min_twt_dur; + flow->mantissa = agrt_req->mantissa; + flow->exp = exp; + flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION); + flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE); + flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER); + + if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST || + sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) { + u64 flow_tsf, curr_tsf, interval = (u64)mantissa << exp; + + flow->sched = true; + flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow); + curr_tsf = __mt7915_get_tsf(hw, msta->vif); + flow_tsf = curr_tsf + interval - + (curr_tsf - flow->start_tsf) % interval; + agrt_resp->twt = cpu_to_le64(flow_tsf); + } else { + list_add_tail(&flow->list, &dev->twt_list); + } + flow->tsf = le64_to_cpu(agrt_resp->twt); + + err = mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, + MCU_TWT_AGRT_ADD); + if (err) + goto unlock; + + setup_cmd = TWT_SETUP_CMD_ACCEPT; + msta->twt.flowid_mask |= BIT(flowid); + dev->n_twt_agrt++; + +unlock: + mutex_unlock(&dev->mt76.mutex); +out: + req_type &= ~IEEE80211_TWT_REQTYPE_SETUP_CMD; + req_type |= FIELD_PREP(IEEE80211_TWT_REQTYPE_SETUP_CMD, setup_cmd); + agrt_resp->req_type = cpu_to_le16(req_type); + + return err; +} + +void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, + struct mt7915_sta *msta, + u8 flowid) +{ + struct mt7915_twt_flow *flow; + + lockdep_assert_held(&dev->mt76.mutex); + + if (flowid >= ARRAY_SIZE(msta->twt.flow)) + return; + + if (!(msta->twt.flowid_mask & BIT(flowid))) + return; + + flow = &msta->twt.flow[flowid]; + if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, + MCU_TWT_AGRT_DELETE)) + return; + + list_del_init(&flow->list); + msta->twt.flowid_mask &= ~BIT(flowid); + dev->n_twt_agrt--; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index fa4fd04affd8..c8492ce3be07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -640,6 +640,7 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + int i; mt7915_mcu_add_sta_adv(dev, vif, sta, false); mt7915_mcu_add_sta(dev, vif, sta, false); @@ -647,6 +648,9 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7915_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); + spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); @@ -1038,6 +1042,19 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, mt7915_mcu_sta_update_hdr_trans(dev, vif, sta); } +static void +mt7915_twt_teardown_request(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 flowid) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mac_twt_teardown_flow(dev, msta, flowid); + mutex_unlock(&dev->mt76.mutex); +} + const struct ieee80211_ops mt7915_ops = { .tx = mt7915_tx, .start = mt7915_start, @@ -1073,6 +1090,8 @@ const struct ieee80211_ops mt7915_ops = { .sta_statistics = mt7915_sta_statistics, .sta_set_4addr = mt7915_sta_set_4addr, .sta_set_decap_offload = mt7915_sta_set_decap_offload, + .add_twt_setup = mt7915_mac_add_twt_setup, + .twt_teardown_request = mt7915_twt_teardown_request, CFG80211_TESTMODE_CMD(mt76_testmode_cmd) CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_MAC80211_DEBUGFS diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index ad97980275a3..492269564709 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -41,6 +41,9 @@ #define MT7915_SKU_RATE_NUM 161 +#define MT7915_MAX_TWT_AGRT 16 +#define MT7915_MAX_STA_TWT_AGRT 8 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -96,6 +99,11 @@ struct mt7915_sta { unsigned long ampdu_state; struct mt7915_sta_key_conf bip; + + struct { + u8 flowid_mask; + struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT]; + } twt; }; struct mt7915_vif { u16 idx; @@ -192,6 +200,7 @@ struct mt7915_dev { struct list_head sta_rc_list; struct list_head sta_poll_list; + struct list_head twt_list; spinlock_t sta_poll_lock; u32 hw_pattern; @@ -202,6 +211,8 @@ struct mt7915_dev { bool ibf; void *cal; + + u8 n_twt_agrt; }; enum { @@ -414,6 +425,13 @@ void mt7915_mac_work(struct work_struct *work); void mt7915_mac_reset_work(struct work_struct *work); void mt7915_mac_sta_rc_work(struct work_struct *work); int mt7915_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, int irq); +void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, + struct mt7915_sta *msta, + u8 flowid); +int mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + struct ieee80211_twt_params *agrt_req, + struct ieee80211_twt_params *agrt_resp); int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, From patchwork Fri Jul 16 15:04:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382405 X-Patchwork-Delegate: nbd@nbd.name Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A04CCC12002 for ; Fri, 16 Jul 2021 15:04:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 882C7613CF for ; Fri, 16 Jul 2021 15:04:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240711AbhGPPHl (ORCPT ); Fri, 16 Jul 2021 11:07:41 -0400 Received: from mail.kernel.org ([198.145.29.99]:46740 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240679AbhGPPHi (ORCPT ); Fri, 16 Jul 2021 11:07:38 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id AD96E613F8; Fri, 16 Jul 2021 15:04:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447883; bh=SUapj8ZVjbbatk6pcsbhVW0JvfRU1EqjO4QsSmmnqUI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Dy5fAMrfds+gW0UjpsB6rQjAzI/+1yHxxFkEJG48Jla4eniPdLtAJU0c4c3qozXB5 wVn3YJQEPLSW02Xu/HgKAMH7BGFfDpzF6NMpvm15uRweJRK3aHLg/AdH3FgAm6+cwM CL3/M78u3dmEXCQ9ecdT3PhM38x7kPluDbLy5DMsXVcCdOV12CothMLHE2fnuIZuWc PU5qoIJ13AjyeXQXWYjyBVaU1iD1STW5Kur7OSBJPa+pM5aGezxiLmsQugOGiwQ3Hd hEy9esRuizUoKrcUg2qc0KQQ1+9M8kSb9DnaFzs1F3YovzFin+Tun662InuolCt+Ey 6Wa5GPkZDKcAQ== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 6/7] mt76: mt7915: enable twt responder capability Date: Fri, 16 Jul 2021 17:04:05 +0200 Message-Id: <500dce1b7be47e90b2c1ba01cb1771d7dbf44b61.1626447537.git.lorenzo@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Enable TWT support in AP mode Signed-off-by: Lorenzo Bianconi --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 3ed48542e122..b554de8e7100 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -666,6 +666,8 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, switch (i) { case NL80211_IFTYPE_AP: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_RES; he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= From patchwork Fri Jul 16 15:04:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 12382407 X-Patchwork-Delegate: nbd@nbd.name Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A172C12002 for ; Fri, 16 Jul 2021 15:04:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DE8EC60FF3 for ; Fri, 16 Jul 2021 15:04:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240679AbhGPPHn (ORCPT ); Fri, 16 Jul 2021 11:07:43 -0400 Received: from mail.kernel.org ([198.145.29.99]:46766 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240693AbhGPPHk (ORCPT ); Fri, 16 Jul 2021 11:07:40 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 904EF60FF3; Fri, 16 Jul 2021 15:04:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1626447885; bh=1R+eoZXo/tV2qP8G6uWnQYKp77VeuWQ7hqp7ZJ54BPM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z/1m7cy92JMOQZ+Mgo5xBtnHW3eVnjSQewEPNSqeq1TsXcOxcmyHLpKsjZSv7g3F5 kPO9GPgc+pPk8kgXzBCVkWdtpcda34VsP1lCy7XZrzVp35/QCIQso/lhE9wuWToDKD DnWXFuehv81Mbp2myHthuSd5v9j0k1V/HlgOo986vEkNf8+18+vBOiu481lqSZpXm9 QrwlAp4M1E09MTXK9ByyhMKfiqhwJFkhJQPdVtTHZQUZQL3q96iTMcrRAkpk2m4+hm dhGyXdjFbLu1DLm0WDpfjrbv6/99EH4XL0VRB41HqqCV/bjMFkFfCO+Mbam1ySegmt sv+s8HUkBclyw== From: Lorenzo Bianconi To: linux-wireless@vger.kernel.org Cc: johannes@sipsolutions.net, nbd@nbd.name, ryder.lee@mediatek.com, lorenzo.bianconi@redhat.com Subject: [RFC mac80211-next 7/7] mt76: mt7915: add twt_stats knob in debugfs Date: Fri, 16 Jul 2021 17:04:06 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org Introduce twt_stats knob in debugfs in order to dump established agreements Signed-off-by: Lorenzo Bianconi --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 1a48b09d0cb7..5ed329f720d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -335,6 +335,32 @@ mt7915_read_rate_txpower(struct seq_file *s, void *data) return 0; } +static int +mt7915_twt_stats(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt7915_twt_flow *iter; + + rcu_read_lock(); + + seq_puts(s, " wcid | id | flags | exp | mantissa"); + seq_puts(s, " | duration | tsf |\n"); + list_for_each_entry_rcu(iter, &dev->twt_list, list) + seq_printf(s, + "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n", + iter->wcid, iter->id, + iter->sched ? 's' : 'u', + iter->protection ? 'p' : '-', + iter->trigger ? 't' : '-', + iter->flowtype ? '-' : 'a', + iter->exp, iter->mantissa, + iter->duration, iter->tsf); + + rcu_read_lock(); + + return 0; +} + int mt7915_init_debugfs(struct mt7915_dev *dev) { struct dentry *dir; @@ -352,6 +378,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("implicit_txbf", 0600, dir, dev, &fops_implicit_txbf); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, + mt7915_twt_stats); /* test knobs */ debugfs_create_file("radar_trigger", 0200, dir, dev, &fops_radar_trigger);