From d21f313283603bea73a06f7df8c2a0f7b0e4ab45 Mon Sep 17 00:00:00 2001 From: JasonHuang 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 --- .../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