From edbe0e75f5ed8eb006cc6c187f6ddd0f6f9dd86a Mon Sep 17 00:00:00 2001
From: JasonHuang <Jason.Huang2@infineon.com>
Date: Mon, 29 Jan 2024 23:38:13 -0600
Subject: [PATCH 242/301] non-upstream: check and set default fcmode of the
 chip

This request came from Amazon facing some t-put issue. Default set
fcmode=2 and then clear fcmode if chip not support proptxstatus. We
can read current fcmode from /sys/kernel/debug/ieee80211/phy0/parameter

Signed-off-by: JasonHuang <Jason.Huang2@infineon.com>
---
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 6c7e63cd4..582957f5c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -107,6 +107,7 @@ struct brcmf_bus_ops {
 	void (*debugfs_create)(struct device *dev);
 	int (*reset)(struct device *dev);
 	void (*remove)(struct device *dev);
+	int (*set_fcmode)(struct device *dev);
 };
 
 
@@ -286,6 +287,15 @@ static inline void brcmf_bus_remove(struct brcmf_bus *bus)
 	bus->ops->remove(bus->dev);
 }
 
+static inline
+int brcmf_bus_set_fcmode(struct brcmf_bus *bus)
+{
+	if (!bus->ops->set_fcmode)
+		return -EOPNOTSUPP;
+
+	return bus->ops->set_fcmode(bus->dev);
+}
+
 /*
  * interface functions from common layer
  */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 61cf90af1..ab4a8d4df 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -26,6 +26,7 @@
 #include <linux/reboot.h>
 #include <linux/notifier.h>
 #include "pcie.h"
+#include "sdio.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
@@ -61,7 +62,7 @@ module_param_string(alternative_fw_path, brcmf_firmware_path,
 		    BRCMF_FW_ALTPATH_LEN, 0400);
 MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
 
-static int brcmf_fcmode;
+static int brcmf_fcmode = 2;
 module_param_named(fcmode, brcmf_fcmode, int, 0);
 MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 4b8d08977..fd7e017c6 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -32,6 +32,7 @@
 #include "pcie.h"
 #include "common.h"
 #include "twt.h"
+#include "sdio.h"
 
 #define MAX_WAIT_FOR_8021X_TX			msecs_to_jiffies(950)
 
@@ -1585,6 +1586,10 @@ static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops)
 		goto fail;
 
 	brcmf_feat_attach(drvr);
+	ret = brcmf_bus_set_fcmode(bus_if);
+	/* Set fcmode = 0 for PCIe/USB */
+	if (ret < 0)
+		drvr->settings->fcmode = 0;
 
 	ret = brcmf_proto_init_done(drvr);
 	if (ret < 0)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 59bd0364c..b3d7b7ecd 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -52,6 +52,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
 	{ BRCMF_FEAT_GCMP, "gcmp" },
 	{ BRCMF_FEAT_OFFLOADS, "offloads" },
 	{ BRCMF_FEAT_ULP, "ulp" },
+	{ BRCMF_FEAT_PROPTXSTATUS, "proptxstatus" },
 };
 
 #ifdef DEBUG
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index 8ebe07819..112e035f9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -74,7 +74,8 @@
 	BRCMF_FEAT_DEF(GCMP) \
 	BRCMF_FEAT_DEF(TWT) \
 	BRCMF_FEAT_DEF(OFFLOADS) \
-	BRCMF_FEAT_DEF(ULP)
+	BRCMF_FEAT_DEF(ULP) \
+	BRCMF_FEAT_DEF(PROPTXSTATUS)
 
 /*
  * Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index d2a4e3625..8bf12d302 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -4679,6 +4679,7 @@ static int brcmf_sdio_bus_reset(struct device *dev)
 	return 0;
 }
 
+
 static void brcmf_sdio_bus_remove(struct device *dev)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -4688,6 +4689,20 @@ static void brcmf_sdio_bus_remove(struct device *dev)
 	device_release_driver(&sdiod->func1->dev);
 }
 
+static int brcmf_sdio_bus_set_fcmode(struct device *dev)
+{
+	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+
+	if (!brcmf_feat_is_enabled(bus_if->drvr->iflist[0], BRCMF_FEAT_PROPTXSTATUS)) {
+		bus_if->drvr->settings->fcmode = 0;
+		sdiodev->settings->fcmode = bus_if->drvr->settings->fcmode;
+		brcmf_dbg(INFO, "Set fcmode = %d\n", sdiodev->settings->fcmode);
+	}
+
+	return sdiodev->settings->fcmode;
+}
+
 static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.stop = brcmf_sdio_bus_stop,
 	.preinit = brcmf_sdio_bus_preinit,
@@ -4702,6 +4717,7 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = {
 	.debugfs_create = brcmf_sdio_debugfs_create,
 	.reset = brcmf_sdio_bus_reset,
 	.remove = brcmf_sdio_bus_remove,
+	.set_fcmode = brcmf_sdio_bus_set_fcmode
 };
 
 #define BRCMF_SDIO_FW_CODE	0
