From 4472facd181407d0e2e3d9c5d36e31e378f6468b Mon Sep 17 00:00:00 2001 From: Gokul Sivakumar Date: Thu, 7 Sep 2023 14:47:24 -0500 Subject: [PATCH 181/296] brcmfmac: TWT: Handle timeout of Setup and Teardown events expected from FW In case if the TWT AP did not response to the TWT Setup solicit from this device, need to cleanup the session entry from the list after a timeout. Introduce an aperiodic stale TWT session entry cleanup job using kernel timer. Schedule this cleanup job to fire after 3000ms from sending a TWT Setup or Teardown cmd to Firmware. Signed-off-by: Gokul Sivakumar --- .../broadcom/brcm80211/brcmfmac/core.c | 6 ++ .../broadcom/brcm80211/brcmfmac/core.h | 1 + .../broadcom/brcm80211/brcmfmac/twt.c | 65 +++++++++++++++++++ .../broadcom/brcm80211/brcmfmac/twt.h | 11 ++++ 4 files changed, 83 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 5d82153211b9..f20c3953fd74 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1210,6 +1210,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx, spin_lock_init(&ifp->twt_sess_list_lock); /* Initialize TWT Session list */ INIT_LIST_HEAD(&ifp->twt_sess_list); + /* Setup the aperiodic TWT Session cleanup activity */ + timer_setup(&ifp->twt_evt_timeout, brcmf_twt_event_timeout_handler, 0); if (mac_addr != NULL) memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); @@ -1235,6 +1237,10 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx, ifp->ifidx); ifidx = ifp->ifidx; + /* Stop the aperiodic TWT Session cleanup activity */ + if (timer_pending(&ifp->twt_evt_timeout)) + del_timer_sync(&ifp->twt_evt_timeout); + if (ifp->ndev) { if (bsscfgidx == 0) { if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 373e0418809e..fda8af9722d0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -213,6 +213,7 @@ struct brcmf_if { spinlock_t sta_list_lock; struct list_head twt_sess_list; /* dll of TWT sessions */ spinlock_t twt_sess_list_lock; + struct timer_list twt_evt_timeout; /* TWT event timeout */ bool fmac_pkt_fwd_en; }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c index a477f56d05f5..04e823eacb6b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c @@ -492,6 +492,66 @@ brcmf_twt_add_session(struct brcmf_if *ifp, const u8 *peer_addr, return ret; } +/** + * brcmf_twt_event_timeout_handler - Iterate the session list and handle stale + * TWT session entries which are failed to move to next state in FSM. + * + * @t: timer instance. + */ +void brcmf_twt_event_timeout_handler(struct timer_list *t) +{ + struct brcmf_if *ifp = from_timer(ifp, t, twt_evt_timeout); + struct brcmf_twt_session *twt_sess = NULL, *next = NULL; + unsigned long curr_ts = jiffies; + s32 ret = 0; + + list_for_each_entry_safe(twt_sess, next, &ifp->twt_sess_list, list) { + /* For this session entry, Skip if the time since the TWT cmd sent to the + * Firmware does not exceed the Event timeout configured. + */ + if (time_after(twt_sess->oper_start_ts + BRCMF_TWT_EVENT_TIMEOUT, curr_ts)) + continue; + + switch (twt_sess->state) { + case BRCMF_TWT_SESS_STATE_SETUP_INPROGRESS: + ret = brcmf_twt_update_session_state(ifp, twt_sess, + BRCMF_TWT_SESS_STATE_SETUP_INCOMPLETE); + if (ret) { + brcmf_err("TWT: Failed to update session(%u) with state(%s)", + twt_sess->twt_params.flow_id, + brcmf_twt_session_state_str[BRCMF_TWT_SESS_STATE_SETUP_INCOMPLETE]); + continue; + } + + break; + case BRCMF_TWT_SESS_STATE_TEARDOWN_INPROGRESS: + ret = brcmf_twt_update_session_state(ifp, twt_sess, + BRCMF_TWT_SESS_STATE_TEARDOWN_INCOMPLETE); + if (ret) { + brcmf_err("TWT: Failed to update session(%u) with state(%s)", + twt_sess->twt_params.flow_id, + brcmf_twt_session_state_str[BRCMF_TWT_SESS_STATE_TEARDOWN_INCOMPLETE]); + continue; + } + + break; + default: + continue; + } + + ret = brcmf_twt_del_session(ifp, twt_sess); + if (ret) { + brcmf_err("TWT: Failed to Delete session(%u) from list", + twt_sess->twt_params.flow_id); + break; + } + + brcmf_dbg(TWT, "TWT: Cleared stale session(%u) with peer %pM, state(%s)", + twt_sess->twt_params.flow_id, twt_sess->peer_addr.octet, + brcmf_twt_session_state_str[twt_sess->state]); + } +} + /** * brcmf_twt_setup_event_handler() - Handle the TWT Setup Event notification from Firmware. * @@ -935,6 +995,8 @@ brcmf_twt_setup_oper_handler(struct brcmf_if *ifp, struct brcmf_twt_params twt_p goto exit; } + /* Schedule the Cleanup timer to handle Setup Completion timeout */ + mod_timer(&ifp->twt_evt_timeout, jiffies + BRCMF_TWT_EVENT_TIMEOUT); brcmf_dbg(TWT, "TWT: Setup REQ: Session Setup In Progress\n" "Dialog Token : %u\n" @@ -1067,6 +1129,9 @@ brcmf_twt_teardown_oper_handler(struct brcmf_if *ifp, struct brcmf_twt_params tw } } + /* Schedule the Cleanup timer to handle Teardown Completion timeout */ + mod_timer(&ifp->twt_evt_timeout, jiffies + BRCMF_TWT_EVENT_TIMEOUT); + brcmf_dbg(TWT, "TWT: Teardown REQ: Session Teardown In Progress\n" "Flow ID : %u\n" "Broadcast TWT ID : %u\n" diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h index f04696d86163..a8c94d9a16d4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h @@ -32,6 +32,8 @@ #ifndef BRCMF_TWT_H #define BRCMF_TWT_H +#include +#include #include "vendor_ifx.h" #include "core.h" @@ -40,6 +42,7 @@ /* Min TWT Unit in TUs */ #define WAKE_DUR_UNIT_TU 1024 +#define BRCMF_TWT_EVENT_TIMEOUT msecs_to_jiffies(3000) /** * enum brcmf_twt_cmd - TWT iovar subcmds handled by firmware TWT module * @@ -166,6 +169,7 @@ struct brcmf_twt_params { * @peer: TWT peer address. * @state: TWT session state, refer enum brcmf_twt_session_state. * @twt_params: TWT session parameters. + * @oper_req_ts: TWT session operation (setup, teardown, etc..) start timestamp. * @list: linked list. */ struct brcmf_twt_session { @@ -174,6 +178,7 @@ struct brcmf_twt_session { struct ether_addr peer_addr; enum brcmf_twt_session_state state; struct brcmf_twt_params twt_params; + unsigned long oper_start_ts; struct list_head list; }; @@ -325,6 +330,12 @@ void brcmf_twt_debugfs_create(struct brcmf_pub *drvr); */ s32 brcmf_twt_cleanup_sessions(struct brcmf_if *ifp); +/** + * brcmf_twt_event_timeout_handler - Iterate the session list and handle stale + * TWT session entries which are failed to move to next state in FSM. + */ +void brcmf_twt_event_timeout_handler(struct timer_list *t); + /** * brcmf_notify_twt_event() - Handle the TWT Event notifications from Firmware. * -- 2.25.1