From d21f313283603bea73a06f7df8c2a0f7b0e4ab45 Mon Sep 17 00:00:00 2001
From: JasonHuang <Jason.Huang2@infineon.com>
Date: Wed, 27 Dec 2023 03:49:19 -0600
Subject: [PATCH 204/296] brcmfmac: PCIe RX throughput improvement

Observed RX Tput lower than TX around 100Mbps and the Tput peak-peak
amplitude is > 100Mbps. To improve RX Tput, we create the workqueue
for RX data. Adding the WQ_HIGHPRI flag would place the work items
in a high priority workqueue.

Signed-off-by: JasonHuang <Jason.Huang2@infineon.com>
---
 .../broadcom/brcm80211/brcmfmac/core.c        |  2 -
 .../broadcom/brcm80211/brcmfmac/msgbuf.c      | 53 +++++++++++++++++--
 2 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index a227134ee890..5f2bcbad7b6f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -663,8 +663,6 @@ void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 	skb_reset_mac_header(skb);
 	skb->pkt_type = PACKET_OTHERHOST;
 	skb->protocol = htons(ETH_P_802_2);
-
-	brcmf_netif_rx(ifp, skb);
 }
 
 static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index ed23f8583b7c..904af7899811 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -290,6 +290,9 @@ struct brcmf_msgbuf {
 	struct work_struct flowring_work;
 	spinlock_t flowring_work_lock;
 	struct list_head work_queue;
+	struct workqueue_struct *rx_wq;
+	struct work_struct rx_work;
+	struct sk_buff_head rx_data_q;
 };
 
 struct brcmf_msgbuf_pktid {
@@ -816,6 +819,17 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
 	brcmf_commonring_unlock(commonring);
 }
 
+static void brcmf_msgbuf_rx(struct brcmf_msgbuf *msgbuf)
+{
+	struct sk_buff *skb;
+	struct brcmf_if *ifp;
+
+	while ((skb = skb_dequeue(&msgbuf->rx_data_q))) {
+		ifp = netdev_priv(skb->dev);
+		if (!ifp)
+			brcmf_netif_rx(ifp, skb);
+	}
+}
 
 static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)
 {
@@ -829,6 +843,13 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)
 	}
 }
 
+static void brcmf_msgbuf_rx_worker(struct work_struct *worker)
+{
+	struct brcmf_msgbuf *msgbuf;
+
+	msgbuf = container_of(worker, struct brcmf_msgbuf, rx_work);
+	brcmf_msgbuf_rx(msgbuf);
+}
 
 static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,
 					bool force)
@@ -844,6 +865,13 @@ static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,
 	return 0;
 }
 
+static int brcmf_msgbuf_schedule_rxdata(struct brcmf_msgbuf *msgbuf, bool force)
+{
+	if (force)
+		queue_work(msgbuf->rx_wq, &msgbuf->rx_work);
+
+	return 0;
+}
 
 static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
 				      struct sk_buff *skb)
@@ -1234,7 +1262,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 		}
 
 		brcmf_netif_mon_rx(ifp, skb);
-		return;
+		goto queue;
 	}
 
 	ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
@@ -1273,8 +1301,10 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 			}
 		}
 	}
+	skb->dev = ifp->ndev;
 	skb->protocol = eth_type_trans(skb, ifp->ndev);
-	brcmf_netif_rx(ifp, skb);
+queue:
+	skb_queue_tail(&msgbuf->rx_data_q, skb);
 }
 
 static void brcmf_msgbuf_process_gen_status(struct brcmf_msgbuf *msgbuf,
@@ -1474,6 +1504,8 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
 
 	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
 	brcmf_msgbuf_process_rx(msgbuf, buf);
+	/* To improve RX throughput, put rxdata into the workqueue only. */
+	brcmf_msgbuf_schedule_rxdata(msgbuf, true);
 	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE];
 	brcmf_msgbuf_process_rx(msgbuf, buf);
 	buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE];
@@ -1639,12 +1671,20 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
 	if (!msgbuf)
 		goto fail;
 
-	msgbuf->txflow_wq = create_singlethread_workqueue("msgbuf_txflow");
+	msgbuf->txflow_wq = alloc_workqueue("msgbuf_txflow", WQ_HIGHPRI |
+				    WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
 	if (msgbuf->txflow_wq == NULL) {
 		bphy_err(drvr, "workqueue creation failed\n");
 		goto fail;
 	}
 	INIT_WORK(&msgbuf->txflow_work, brcmf_msgbuf_txflow_worker);
+	msgbuf->rx_wq = alloc_workqueue("msgbuf_rx", WQ_HIGHPRI |
+				    WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
+	if (!msgbuf->rx_wq) {
+		bphy_err(drvr, "RX workqueue creation failed\n");
+		goto fail;
+	}
+	INIT_WORK(&msgbuf->rx_work, brcmf_msgbuf_rx_worker);
 	count = BITS_TO_LONGS(if_msgbuf->max_flowrings);
 	count = count * sizeof(unsigned long);
 	msgbuf->flow_map = kzalloc(count, GFP_KERNEL);
@@ -1709,7 +1749,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
 	if (!msgbuf->flow)
 		goto fail;
 
-
+	skb_queue_head_init(&msgbuf->rx_data_q);
 	brcmf_dbg(MSGBUF, "Feeding buffers, rx data %d, rx event %d, rx ioctl resp %d\n",
 		  msgbuf->max_rxbufpost, msgbuf->max_eventbuf,
 		  msgbuf->max_ioctlrespbuf);
@@ -1744,6 +1784,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
 					  msgbuf->ioctbuf_handle);
 		if (msgbuf->txflow_wq)
 			destroy_workqueue(msgbuf->txflow_wq);
+		if (msgbuf->rx_wq)
+			destroy_workqueue(msgbuf->rx_wq);
 		kfree(msgbuf);
 	}
 	return -ENOMEM;
@@ -1771,6 +1813,9 @@ void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr)
 		if (msgbuf->txflow_wq)
 			destroy_workqueue(msgbuf->txflow_wq);
 
+		if (msgbuf->rx_wq)
+			destroy_workqueue(msgbuf->rx_wq);
+
 		brcmf_flowring_detach(msgbuf->flow);
 		dma_free_coherent(drvr->bus_if->dev,
 				  BRCMF_TX_IOCTL_MAX_MSG_SIZE,
-- 
2.25.1

