From e2fafbf401d175b9b0f67588e7f0f8b2f16dbcd5 Mon Sep 17 00:00:00 2001
From: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
Date: Fri, 19 May 2023 00:28:48 -0500
Subject: [PATCH] brcmfmac: TWT: create a debugfs file to expose the TWT stats
 to userspace

Create a debugfs file "twt_stats" with support for file read operation to
let the userspace access the TWT session info along with the respective
TWT session parameters like Target Wake Time, Wake Duration, Wake Interval,
etc.

Skip the attempt to print the TWT session info either if the Firmware does
not support TWT or if the TWT session list is empty in an interface.

 $ cat /sys/kernel/debug/ieee80211/phy0/twt_stats
 ifname: wlan0, ifidx: 0, bsscfgidx: 0
         iTWT Session, Flow ID: 0
                 Session state       : Setup complete
                 TWT peer            : 00:00:00:00:00:00
                 Target Wake Time    : 2399607488 uS
                 Wake Duration       : 20480 uS
                 Wake Interval       : 307200 uS
                 Dialog_token        : 1
                 Session type        : Implicit, Trigger based, Announced

         iTWT Session, Flow ID: 1
                 Session state       : Setup complete
                 TWT peer            : 00:00:00:00:00:00
                 Target Wake Time    : 2433133585 uS
                 Wake Duration       : 20480 uS
                 Wake Interval       : 64000 uS
                 Dialog_token        : 2
                 Session type        : Implicit, Non-Trigger based, Un-Announced

Signed-off-by: Gokul Sivakumar <gokulkumar.sivakumar@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/core.c        |  1 +
 .../broadcom/brcm80211/brcmfmac/twt.c         | 85 +++++++++++++++++++
 .../broadcom/brcm80211/brcmfmac/twt.h         |  7 ++
 3 files changed, 93 insertions(+)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 7d62a59a8..63d99e870 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1601,6 +1601,7 @@ static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
 	brcmf_feat_debugfs_create(drvr);
 	brcmf_proto_debugfs_create(drvr);
 	brcmf_bus_debugfs_create(bus_if);
+	brcmf_twt_debugfs_create(drvr);
 
 	return 0;
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
index 546bbfe7f..46080c6a0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
@@ -143,6 +143,91 @@ brcmf_twt_float_to_u32(u8 exponent, u16 mantissa)
 	return (u32)mantissa << exponent;
 }
 
+/**
+ * brcmf_twt_stats_read() - Read the contents of the debugfs file "twt_stats".
+ *
+ * @seq: sequence for debugfs entry.
+ * @data: raw data pointer.
+ *
+ * return: 0.
+ */
+static int
+brcmf_twt_stats_read(struct seq_file *seq, void *data)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
+	struct brcmf_pub *drvr = bus_if->drvr;
+	int i;
+
+	/* Return if the if TWT is not supported by Firmware */
+	if (!(drvr->feat_flags & BIT(BRCMF_FEAT_TWT)))
+		return 0;
+
+	/* Iterate the interface list in struct brcmf_pub */
+	for (i = 0; i < BRCMF_MAX_IFS; i++) {
+		struct brcmf_if *ifp = drvr->iflist[i];
+		struct brcmf_twt_session *twt_sess;
+
+		/* Skip interface if TWT session list in struct brcmf_if is empty */
+		if (!ifp || list_empty(&ifp->twt_sess_list))
+			continue;
+
+		seq_printf(seq, "ifname: %s, ifidx: %u, bsscfgidx: %d\n",
+			   ifp->ndev ? ifp->ndev->name : "<no-ndev>" ,
+			   ifp->ifidx, ifp->bsscfgidx);
+
+		/* Iterate the TWT session list in struct brcmf_if */
+		list_for_each_entry(twt_sess, &ifp->twt_sess_list, list) {
+			struct brcmf_twt_params *twt_params;
+			u32 wake_dur, wake_int;
+
+			twt_params = &twt_sess->twt_params;
+
+			wake_dur = brcmf_twt_min_twt_to_wake_dur(twt_params->min_twt,
+								 twt_params->min_twt_unit);
+			wake_int = brcmf_twt_float_to_u32(twt_params->exponent,
+							  twt_params->mantissa);
+
+			if (twt_params->negotiation_type == IFX_TWT_PARAM_NEGO_TYPE_ITWT)
+				seq_printf(seq, "\tiTWT Session, Flow ID: %u\n",
+					   twt_params->flow_id);
+			else if (twt_params->negotiation_type == IFX_TWT_PARAM_NEGO_TYPE_BTWT)
+				seq_printf(seq, "\tbTWT Session, Bcast TWT ID: %u\n",
+					   twt_params->bcast_twt_id);
+			else
+				continue;
+
+			seq_printf(seq, "\t\tSession state       : %s\n",
+				   brcmf_twt_session_state_str[twt_sess->state]);
+			seq_printf(seq, "\t\tTWT peer            : %pM\n",
+				   twt_sess->peer_addr.octet);
+			seq_printf(seq, "\t\tTarget Wake Time    : %llu uS\n",
+				   twt_params->twt);
+			seq_printf(seq, "\t\tWake Duration       : %u uS\n",
+				   wake_dur);
+			seq_printf(seq, "\t\tWake Interval       : %u uS\n",
+				   wake_int);
+			seq_printf(seq, "\t\tDialog_token        : %u\n",
+				   twt_params->dialog_token);
+			seq_printf(seq, "\t\tSession type        : %s, %s, %s\n\n",
+				   twt_params->implicit ? "Implicit" : "Explicit",
+				   twt_params->trigger ? "Trigger based" : "Non-Trigger based",
+				   twt_params->flow_type ? "Un-Announced" : "Announced");
+		}
+	}
+	return 0;
+}
+
+/**
+ * brcmf_twt_debugfs_create() - create debugfs entries.
+ *
+ * @drvr: driver instance.
+ */
+void
+brcmf_twt_debugfs_create(struct brcmf_pub *drvr)
+{
+	brcmf_debugfs_add_entry(drvr, "twt_stats", brcmf_twt_stats_read);
+}
+
 /**
  * brcmf_twt_cleanup_sessions - Cleanup the TWT sessions from the driver list.
  *
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h
index 3dc81d414..0208aed50 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.h
@@ -304,6 +304,13 @@ struct brcmf_twt_teardown_oper {
 	struct brcmf_twt_teardesc teardesc;
 };
 
+/**
+ * brcmf_twt_debugfs_create() - create debugfs entries.
+ *
+ * @drvr: driver instance.
+ */
+void brcmf_twt_debugfs_create(struct brcmf_pub *drvr);
+
 /**
  * brcmf_twt_cleanup_sessions - Cleanup the TWT sessions from the driver list.
  *
-- 
2.39.5 (Apple Git-154)

