From 3a5ac8da3e5a9cfbccb48202e20577ef8f89fbde Mon Sep 17 00:00:00 2001
From: Carter Chen <carter.chen@infineon.com>
Date: Thu, 15 Aug 2024 03:38:31 -0500
Subject: [PATCH 292/296] non-upstream: rewrite feat_flag to preven the use of
 BIT MACRO overflow

while feat_flag is getting more and more,
the use of the MACRO "BIT" will hit its upper bound depends on platform.
to prevent this in the future.
changing the writing method of feat_flag.

the driver module parameter "feature_disable" is also rewrote
accordingly.
the new usage of this parameter is as below,

insmod brcmfmac.ko debug=0x100006 feature_disable=0xff,0x03

This would set the first byte to 0xff (all features in the first byte disabled)
and the second byte to 0x03 (first two features in the second byte disabled).


Signed-off-by: Carter Chen <carter.chen@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/common.c      |  19 ++-
 .../broadcom/brcm80211/brcmfmac/common.h      |   3 +-
 .../broadcom/brcm80211/brcmfmac/core.h        |   3 +-
 .../broadcom/brcm80211/brcmfmac/feature.c     | 117 ++++++------------
 .../broadcom/brcm80211/brcmfmac/twt.c         |   2 +-
 5 files changed, 53 insertions(+), 91 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index b7480c7817f5..89ffa19a5f78 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -53,9 +53,11 @@ static int brcmf_p2p_enable;
 module_param_named(p2pon, brcmf_p2p_enable, int, 0);
 MODULE_PARM_DESC(p2pon, "Enable legacy p2p management functionality");
 
-static int brcmf_feature_disable;
-module_param_named(feature_disable, brcmf_feature_disable, int, 0);
-MODULE_PARM_DESC(feature_disable, "Disable features");
+static u8 brcmf_feature_disable[BRCMF_MAX_FEATURE_BYTES] = {0};
+static int brcmf_feature_disable_size;
+module_param_array_named(feature_disable, brcmf_feature_disable, byte,
+			 &brcmf_feature_disable_size, 0644);
+MODULE_PARM_DESC(feature_disable, "Disable features (bitmap)");
 
 static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
 module_param_string(alternative_fw_path, brcmf_firmware_path,
@@ -768,7 +770,6 @@ int brcmf_debugfs_param_read(struct seq_file *s, void *data)
 	seq_printf(s, "%-20s: 0x%x\n", "debug", brcmf_msg_level);
 	seq_printf(s, "%-20s: %s\n", "alternative_fw_path", brcmf_firmware_path);
 	seq_printf(s, "%-20s: %d\n", "p2pon", !!brcmf_p2p_enable);
-	seq_printf(s, "%-20s: %d\n", "feature_disable", brcmf_feature_disable);
 	seq_printf(s, "%-20s: %d\n", "fcmode", bus_if->drvr->settings->fcmode);
 	seq_printf(s, "%-20s: %d\n", "roamoff", !!brcmf_roamoff);
 	seq_printf(s, "%-20s: %d\n", "iapp", !!brcmf_iapp_enable);
@@ -812,8 +813,14 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
 	brcmf_dbg(INFO, "alternative_fw_path: %s\n", brcmf_firmware_path);
 	settings->p2p_enable = !!brcmf_p2p_enable;
 	brcmf_dbg(INFO, "p2pon: %d\n", settings->p2p_enable);
-	settings->feature_disable = brcmf_feature_disable;
-	brcmf_dbg(INFO, "feature_disable: %d\n", settings->feature_disable);
+	memcpy(settings->feature_disable,
+	       brcmf_feature_disable,
+	       sizeof(brcmf_feature_disable));
+	brcmf_dbg(INFO, "feature_disable: ");
+	for (i = 0; i < BRCMF_MAX_FEATURE_BYTES; i++)
+		brcmf_dbg(INFO, "0x%x ", settings->feature_disable[i]);
+	brcmf_dbg(INFO, "\n");
+
 	settings->fcmode = brcmf_fcmode;
 	brcmf_dbg(INFO, "fcmode: %d\n", settings->fcmode);
 	settings->roamoff = brcmf_roamoff;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index f2fb78d7dddf..6994741b56c3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -68,9 +68,10 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
  * @idleclk_disable: SDIO bus clock output disable when bus is idle.
  * @idle_time_zero: Set idle interval to zero.
  */
+#define BRCMF_MAX_FEATURE_BYTES DIV_ROUND_UP(BRCMF_FEAT_LAST, 8)
 struct brcmf_mp_device {
 	bool		p2p_enable;
-	unsigned int	feature_disable;
+	unsigned char	feature_disable[BRCMF_MAX_FEATURE_BYTES];
 	int		fcmode;
 	unsigned int	roamoff;
 	bool		iapp;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index e75bb806a4ac..3cf64907a282 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -13,6 +13,7 @@
 #include <net/cfg80211.h>
 #include "fweh.h"
 #include "fwil_types.h"
+#include "feature.h"
 
 #if IS_MODULE(CONFIG_BRCMFMAC)
 #define BRCMF_EXPORT_SYMBOL_GPL(__sym)	EXPORT_SYMBOL_NS_GPL(__sym, BRCMFMAC)
@@ -135,7 +136,7 @@ struct brcmf_pub {
 	struct brcmf_ampdu_rx_reorder
 		*reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS];
 
-	u32 feat_flags;
+	u8 feat_flags[DIV_ROUND_UP(BRCMF_FEAT_LAST, 8)];
 	u32 chip_quirks;
 	int req_mpc;
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 43f7fe325878..db7078e9f1a3 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -74,14 +74,22 @@ static const char * const brcmf_quirk_names[] = {
 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
 {
 	struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
-	u32 feats = bus_if->drvr->feat_flags;
+	u8 feats[DIV_ROUND_UP(BRCMF_FEAT_LAST, 8)] = {0};
 	u32 quirks = bus_if->drvr->chip_quirks;
-	int id;
+	int id, i;
+	u8 size = BRCMF_FEAT_LAST / 8;
+
+	memcpy(feats, bus_if->drvr->feat_flags, sizeof(feats));
+
+	seq_puts(seq, "Features: ");
+	for (i = 0; i < size; i++)
+		seq_printf(seq, "%02x", feats[i]);
+	seq_puts(seq, "\n");
 
-	seq_printf(seq, "Features: %08x\n", feats);
 	for (id = 0; id < BRCMF_FEAT_LAST; id++)
-		if (feats & BIT(id))
+		if (feats[id / 8] & BIT(id % 8))
 			seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
+
 	seq_printf(seq, "\nQuirks:   %08x\n", quirks);
 	for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
 		if (quirks & BIT(id))
@@ -95,45 +103,6 @@ static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
 }
 #endif /* DEBUG */
 
-struct brcmf_feat_fwfeat {
-	const char * const fwid;
-	u32 feat_flags;
-};
-
-static const struct brcmf_feat_fwfeat brcmf_feat_fwfeat_map[] = {
-	/* brcmfmac43602-pcie.ap.bin from linux-firmware.git commit ea1178515b88 */
-	{ "01-6cb8e269", BIT(BRCMF_FEAT_MONITOR) },
-	/* brcmfmac4366b-pcie.bin from linux-firmware.git commit 52442afee990 */
-	{ "01-c47a91a4", BIT(BRCMF_FEAT_MONITOR) },
-	/* brcmfmac4366b-pcie.bin from linux-firmware.git commit 211de1679a68 */
-	{ "01-801fb449", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
-	/* brcmfmac4366c-pcie.bin from linux-firmware.git commit 211de1679a68 */
-	{ "01-d2cbb8fd", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
-};
-
-static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv)
-{
-	const struct brcmf_feat_fwfeat *e;
-	u32 feat_flags = 0;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(brcmf_feat_fwfeat_map); i++) {
-		e = &brcmf_feat_fwfeat_map[i];
-		if (!strcmp(e->fwid, drv->fwver)) {
-			feat_flags = e->feat_flags;
-			break;
-		}
-	}
-
-	if (!feat_flags)
-		return;
-
-	for (i = 0; i < BRCMF_FEAT_LAST; i++)
-		if (feat_flags & BIT(i))
-			brcmf_dbg(INFO, "enabling firmware feature: %s\n",
-				  brcmf_feat_names[i]);
-	drv->feat_flags |= feat_flags;
-}
 
 struct brcmf_feat_wlcfeat {
 	u16 min_ver_major;
@@ -149,10 +118,8 @@ static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = {
 static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv)
 {
 	struct brcmf_if *ifp = brcmf_get_ifp(drv, 0);
-	const struct brcmf_feat_wlcfeat *e;
 	struct brcmf_wlc_version_le ver;
-	u32 feat_flags = 0;
-	int i, err, major, minor;
+	int err, major, minor;
 
 	err = brcmf_fil_iovar_data_get(ifp, "wlc_ver", &ver, sizeof(ver));
 	if (err)
@@ -162,24 +129,6 @@ static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv)
 	minor = le16_to_cpu(ver.wlc_ver_minor);
 
 	brcmf_dbg(INFO, "WLC version: %d.%d\n", major, minor);
-
-	for (i = 0; i < ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) {
-		e = &brcmf_feat_wlcfeat_map[i];
-		if (major > e->min_ver_major ||
-		    (major == e->min_ver_major &&
-		     minor >= e->min_ver_minor)) {
-			feat_flags |= e->feat_flags;
-		}
-	}
-
-	if (!feat_flags)
-		return;
-
-	for (i = 0; i < BRCMF_FEAT_LAST; i++)
-		if (feat_flags & BIT(i))
-			brcmf_dbg(INFO, "enabling firmware feature: %s\n",
-				  brcmf_feat_names[i]);
-	drv->feat_flags |= feat_flags;
 }
 
 /**
@@ -201,7 +150,7 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
 	err = brcmf_fil_iovar_int_get(ifp, name, &data);
 	if (err != -BRCMF_FW_UNSUPPORTED) {
 		brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
-		ifp->drvr->feat_flags |= BIT(id);
+		ifp->drvr->feat_flags[id / 8] |= BIT(id % 8);
 	} else {
 		brcmf_dbg(TRACE, "%s feature check failed: %d\n",
 			  brcmf_feat_names[id], err);
@@ -222,7 +171,7 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
 	err = brcmf_fil_iovar_data_set(ifp, name, data, len);
 	if (err != -BRCMF_FW_UNSUPPORTED) {
 		brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
-		ifp->drvr->feat_flags |= BIT(id);
+		ifp->drvr->feat_flags[id / 8] |= BIT(id % 8);
 	} else {
 		brcmf_dbg(TRACE, "%s feature check failed: %d\n",
 			  brcmf_feat_names[id], err);
@@ -246,7 +195,7 @@ static void brcmf_feat_iovar_enab_get(struct brcmf_if *ifp,
 
 	if (!err) {
 		brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
-		ifp->drvr->feat_flags |= BIT(id);
+		ifp->drvr->feat_flags[id / 8] |= BIT(id % 8);
 	} else {
 		brcmf_dbg(TRACE, "%s feature check failed: %d\n",
 			  brcmf_feat_names[id], err);
@@ -276,7 +225,7 @@ static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
 			id = brcmf_fwcap_map[i].feature;
 			brcmf_dbg(INFO, "enabling feature: %s\n",
 				  brcmf_feat_names[id]);
-			ifp->drvr->feat_flags |= BIT(id);
+			ifp->drvr->feat_flags[id / 8] |= BIT(id % 8);
 		}
 	}
 }
@@ -324,6 +273,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
 	struct brcmf_gscan_config gscan_cfg;
 	u32 wowl_cap;
 	s32 err;
+	int i;
 
 	brcmf_feat_firmware_capabilities(ifp);
 	memset(&gscan_cfg, 0, sizeof(gscan_cfg));
@@ -340,20 +290,21 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
 	if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
 		err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
 		if (!err) {
-			ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
+			ifp->drvr->feat_flags[BRCMF_FEAT_WOWL_ARP_ND / 8] |=
+				BIT(BRCMF_FEAT_WOWL_ARP_ND % 8);
 			if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
-				ifp->drvr->feat_flags |=
-					BIT(BRCMF_FEAT_WOWL_ND);
+				ifp->drvr->feat_flags[BRCMF_FEAT_WOWL_ND / 8] |=
+					BIT(BRCMF_FEAT_WOWL_ND % 8);
 			if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
-				ifp->drvr->feat_flags |=
-					BIT(BRCMF_FEAT_WOWL_GTK);
+				ifp->drvr->feat_flags[BRCMF_FEAT_WOWL_GTK / 8] |=
+					BIT(BRCMF_FEAT_WOWL_GTK % 8);
 		}
 	}
 	/* MBSS does not work for all chips */
 	switch (drvr->bus_if->chip) {
 	case BRCM_CC_4330_CHIP_ID:
 	case BRCM_CC_43362_CHIP_ID:
-		ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
+		ifp->drvr->feat_flags[BRCMF_FEAT_MBSS / 8] &= ~BIT(BRCMF_FEAT_MBSS % 8);
 		break;
 	default:
 		break;
@@ -368,21 +319,23 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
 	err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
 				       sizeof(pfn_mac));
 	if (!err)
-		ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
+		ifp->drvr->feat_flags[BRCMF_FEAT_SCAN_RANDOM_MAC / 8] |=
+			BIT(BRCMF_FEAT_SCAN_RANDOM_MAC % 8);
 
 	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
 	brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver");
 	brcmf_feat_iovar_enab_get(ifp, BRCMF_FEAT_TWT, "twt", BRCMF_TWT_CMD_ENAB);
 
-	if (drvr->settings->feature_disable) {
-		brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
-			  ifp->drvr->feat_flags,
-			  drvr->settings->feature_disable);
-		ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
+	for (i = 0; i < BRCMF_MAX_FEATURE_BYTES; i++) {
+		if (drvr->settings->feature_disable[i]) {
+			brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
+				  ifp->drvr->feat_flags[i],
+				  drvr->settings->feature_disable[i]);
+			ifp->drvr->feat_flags[i] &= ~drvr->settings->feature_disable[i];
+		}
 	}
 
 	brcmf_feat_wlc_version_overrides(drvr);
-	brcmf_feat_firmware_overrides(drvr);
 
 	/* set chip related quirks */
 	switch (drvr->bus_if->chip) {
@@ -406,7 +359,7 @@ void brcmf_feat_debugfs_create(struct brcmf_pub *drvr)
 
 bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
 {
-	return (ifp->drvr->feat_flags & BIT(id));
+	return (ifp->drvr->feat_flags[id / 8] & BIT(id % 8));
 }
 
 bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
index cb2467b4a8a6..9bbf45c48107 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/twt.c
@@ -209,7 +209,7 @@ brcmf_twt_stats_read(struct seq_file *seq, void *data)
 	int i;
 
 	/* Return if the if TWT is not supported by Firmware */
-	if (!(drvr->feat_flags & BIT(BRCMF_FEAT_TWT)))
+	if (!(drvr->feat_flags[BRCMF_FEAT_TWT / 8] & BIT(BRCMF_FEAT_TWT % 8)))
 		return 0;
 
 	/* Iterate the interface list in struct brcmf_pub */
-- 
2.25.1

