From ced3890decd68f90b38b0743129579b61d811747 Mon Sep 17 00:00:00 2001
From: Carter Chen <carter.chen@infineon.com>
Date: Mon, 27 Mar 2023 21:43:26 -0500
Subject: [PATCH 149/296] non-upstream: sdio t-put tuning

verifying on SDIO In-Band interrupt only as of present

add module parameter "sdio_in_isr=1" to enable it.

1.) enabling skb_orphan on tx path
2.) handling sdio_dpc in isr and using trylock to protect.
    if it cannot acquire the mutex, enqueu to work_queue as is.
3.) dataworker also tries to acquire mutex before execute sdio_dpc
    if it cannot acquire the mutex, do nothing this time.
    let the parallel task to handle it.

Fixes: CYW55560A1-1343

Signed-off-by: Carter Chen <carter.chen@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/cfg80211.c    |  2 +-
 .../broadcom/brcm80211/brcmfmac/common.c      |  5 +
 .../broadcom/brcm80211/brcmfmac/common.h      |  2 +
 .../broadcom/brcm80211/brcmfmac/feature.c     |  6 ++
 .../broadcom/brcm80211/brcmfmac/feature.h     |  9 ++
 .../broadcom/brcm80211/brcmfmac/sdio.c        | 94 ++++++++++++++-----
 6 files changed, 94 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index f30b836fb772..fe426fb91bd9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -9271,7 +9271,7 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
 		if (bandlist[i] == cpu_to_le32(WLC_BAND_6G) &&
 		    brcmf_feat_is_6ghz_enabled(ifp)) {
 			band = kmemdup(&__wl_band_6ghz, sizeof(__wl_band_6ghz),
-					   GFP_KERNEL);
+					GFP_KERNEL);
 			if (!band)
 				return -ENOMEM;
 
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index 223263d902c5..45234a07d848 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -96,6 +96,10 @@ static int brcmf_disable_6ghz;
 module_param_named(disable_6ghz, brcmf_disable_6ghz, int, 0400);
 MODULE_PARM_DESC(disable_6ghz, "Disable 6GHz Operation");
 
+static int brcmf_sdio_in_isr;
+module_param_named(sdio_in_isr, brcmf_sdio_in_isr, int, 0400);
+MODULE_PARM_DESC(sdio_in_isr, "Handle SDIO DPC in ISR");
+
 static struct brcmfmac_platform_data *brcmfmac_pdata;
 struct brcmf_mp_global_t brcmf_mp_global;
 
@@ -617,6 +621,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
 #endif
 	settings->fw_ap_select = !!brcmf_fw_ap_select;
 	settings->disable_6ghz = !!brcmf_disable_6ghz;
+	settings->sdio_in_isr = !!brcmf_sdio_in_isr;
 
 	if (bus_type == BRCMF_BUSTYPE_SDIO)
 		settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
index 9246c105242e..559e0193f463 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
@@ -43,6 +43,7 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
  * @trivial_ccode_map: Assume firmware uses ISO3166 country codes with rev 0
  * @fw_ap_select: Allow FW to select AP.
  * @disable_6ghz: Disable 6GHz operation
+ * @sdio_in_isr: Handle SDIO DPC in ISR.
  * @country_codes: If available, pointer to struct for translating country codes
  * @bus: Bus specific platform data. Only SDIO at the mmoment.
  */
@@ -58,6 +59,7 @@ struct brcmf_mp_device {
 	bool		trivial_ccode_map;
 	bool		fw_ap_select;
 	bool		disable_6ghz;
+	bool		sdio_in_isr;
 	struct brcmfmac_pd_cc *country_codes;
 	const char	*board_type;
 	unsigned char	mac[ETH_ALEN];
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 9776ceb81457..fdda06e042f2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -387,3 +387,9 @@ bool brcmf_feat_is_6ghz_enabled(struct brcmf_if *ifp)
 {
 	return (!ifp->drvr->settings->disable_6ghz);
 }
+
+bool brcmf_feat_sdio_in_isr(struct brcmf_if *ifp)
+{
+	return ifp->drvr->settings->sdio_in_isr;
+}
+
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index 9922d3b7f9c3..1d2be55e502f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -141,4 +141,13 @@ bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
  */
 bool brcmf_feat_is_6ghz_enabled(struct brcmf_if *ifp);
 
+/**
+ * brcmf_feat_sdio_in_isr() - handle SDIO DPC handler in ISR
+ *
+ * @ifp: interface instance.
+ *
+ * Return: true if handle SDIO DPC in ISR is enabled; otherwise false.
+ */
+bool brcmf_feat_sdio_in_isr(struct brcmf_if *ifp);
+
 #endif /* _BRCMF_FEATURE_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
index b5e7e0ec36a7..0be1d60b5eb9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -40,6 +40,7 @@
 #include "fwil.h"
 #include "bt_shared_sdio.h"
 #include "trxhdr.h"
+#include "feature.h"
 
 #define DCMD_RESP_TIMEOUT	msecs_to_jiffies(2500)
 #define CTL_DONE_TIMEOUT	msecs_to_jiffies(2500)
@@ -549,6 +550,7 @@ struct brcmf_sdio {
 	bool txglom;		/* host tx glomming enable flag */
 	u16 head_align;		/* buffer pointer alignment */
 	u16 sgentry_align;	/* scatter-gather buffer alignment */
+	struct mutex sdsem;
 };
 
 /* clkstate */
@@ -2171,7 +2173,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 static void
 brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
 {
-	wake_up_interruptible(&bus->ctrl_wait);
+	wake_up(&bus->ctrl_wait);
 	return;
 }
 
@@ -2452,9 +2454,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
 					      &prec_out);
 			if (pkt == NULL)
 				break;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
 			skb_orphan(pkt);
-#endif
 			__skb_queue_tail(&pktq, pkt);
 		}
 		spin_unlock_bh(&bus->txq_lock);
@@ -3241,8 +3241,9 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 	bus->ctrl_frame_stat = true;
 
 	brcmf_sdio_trigger_dpc(bus);
-	wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
-					 CTL_DONE_TIMEOUT);
+	wait_event_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
+			   CTL_DONE_TIMEOUT);
+
 	ret = 0;
 	if (bus->ctrl_frame_stat) {
 		sdio_claim_host(bus->sdiodev->func1);
@@ -3975,14 +3976,15 @@ static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
 
 void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
 {
-	if (!bus->dpc_triggered) {
-		bus->dpc_triggered = true;
-		queue_work(bus->brcmf_wq, &bus->datawork);
-	}
+	bus->dpc_triggered = true;
+	queue_work(bus->brcmf_wq, &bus->datawork);
 }
 
 void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr)
 {
+	struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
+	struct brcmf_if *ifp = bus_if->drvr->iflist[0];
+
 	brcmf_dbg(TRACE, "Enter\n");
 
 	if (!bus) {
@@ -4003,8 +4005,26 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus, bool in_isr)
 	if (!bus->intr)
 		brcmf_err("isr w/o interrupt configured!\n");
 
-	bus->dpc_triggered = true;
-	queue_work(bus->brcmf_wq, &bus->datawork);
+	if (brcmf_feat_sdio_in_isr(ifp)) {
+		if (!mutex_trylock(&bus->sdsem)) {
+			bus->dpc_triggered = true;
+			queue_work(bus->brcmf_wq, &bus->datawork);
+		} else {
+			bus->dpc_triggered = true;
+
+			/* make sure dpc_triggered is true */
+			wmb();
+			while (READ_ONCE(bus->dpc_triggered)) {
+				bus->dpc_triggered = false;
+				brcmf_sdio_dpc(bus);
+				bus->idlecount = 0;
+			}
+			mutex_unlock(&bus->sdsem);
+		}
+	} else {
+		bus->dpc_triggered = true;
+		queue_work(bus->brcmf_wq, &bus->datawork);
+	}
 }
 
 static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
@@ -4097,20 +4117,46 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
 {
 	struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
 					      datawork);
+	struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
+	struct brcmf_if *ifp = bus_if->drvr->iflist[0];
 
-	bus->dpc_running = true;
-	wmb();
-	while (READ_ONCE(bus->dpc_triggered)) {
-		bus->dpc_triggered = false;
-		brcmf_sdio_dpc(bus);
-		bus->idlecount = 0;
-	}
-	bus->dpc_running = false;
-	if (brcmf_sdiod_freezing(bus->sdiodev)) {
-		brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
-		brcmf_sdiod_try_freeze(bus->sdiodev);
-		brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
+	if (brcmf_feat_sdio_in_isr(ifp)) {
+		if (mutex_trylock(&bus->sdsem)) {
+			bus->dpc_running = true;
+
+			/* make sure dpc_running is true */
+			wmb();
+			while (READ_ONCE(bus->dpc_triggered)) {
+				bus->dpc_triggered = false;
+				brcmf_sdio_dpc(bus);
+				bus->idlecount = 0;
+			}
+			mutex_unlock(&bus->sdsem);
+			bus->dpc_running = false;
+			if (brcmf_sdiod_freezing(bus->sdiodev)) {
+				brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
+				brcmf_sdiod_try_freeze(bus->sdiodev);
+				brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
+			}
+		}
+	} else {
+		bus->dpc_running = true;
+
+		/* make sure dpc_running is true */
+		wmb();
+		while (READ_ONCE(bus->dpc_triggered)) {
+			bus->dpc_triggered = false;
+			brcmf_sdio_dpc(bus);
+			bus->idlecount = 0;
+		}
+		bus->dpc_running = false;
+		if (brcmf_sdiod_freezing(bus->sdiodev)) {
+			brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DOWN);
+			brcmf_sdiod_try_freeze(bus->sdiodev);
+			brcmf_sdiod_change_state(bus->sdiodev, BRCMF_SDIOD_DATA);
+		}
 	}
+	return;
 }
 
 static void
@@ -4928,6 +4974,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 	spin_lock_init(&bus->txq_lock);
 	init_waitqueue_head(&bus->ctrl_wait);
 	init_waitqueue_head(&bus->dcmd_resp_wait);
+	/* Initialize thread based operation and lock */
+	mutex_init(&bus->sdsem);
 
 	/* Set up the watchdog timer */
 	timer_setup(&bus->timer, brcmf_sdio_watchdog, 0);
-- 
2.25.1

