From 6da027eb3af592f5ad3c18b8de8918cb56e0420a Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Sun, 13 Nov 2022 19:40:39 +0530 Subject: [PATCH] net: usbnet: Add mechanism to throttle usb0 RX traffic in USB SS ECM traffic is non-aggregated which makes it send huge number of packets in high throughput usecases. This causes the CPU to dedicate majority of the cycles to ISR context and the softIRQ contexts stay suspended. The rx_complete (hardIRQ) keeps adding SKBs to the 'done' list. The usbnet_bh (tasklet) is supposed to dequeue SKBs from 'done' list and provide them to NW stack so that they can be consumed. Because of the above issue, the 'done' list keeps increasing and the system eventually runs out of memory. When the WD_pet task also does not get a chance to run because of hardIRQ storm, WD bite is also observed. Introduce a mechanism to balance the time between hardIRQ and softIRQ contexts. Add module parameter 'usb0_rx_skb_threshold' to stop the submission of URBs to HW from the ISR. This will allow the usbnet_bh to run and consume SKBs, thereby avoiding the OOM scenario and the WD_pet task also gets a chance to pet the WD. The default value of this threshold is 500, which can be changed runtime to suit the requirements according to CPU load. Since in the failing case, ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet adapters are being used, throttle handling has been added in that driver. Usage: echo > /sys/module/usbnet/parameters/usb0_rx_skb_threshold Change-Id: I4667f0ad67d5605b132a0e6062be27e01ef75a08 Signed-off-by: Ajay Agarwal Signed-off-by: Krishna Kurapati --- drivers/net/usb/ax88179_178a.c | 16 ++++++++-------- drivers/net/usb/usbnet.c | 14 +++++++++++--- include/linux/usb/usbnet.h | 1 + 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index dd5cff14f214..f8dbe908d4c5 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1698,7 +1698,7 @@ static const struct driver_info ax88179_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1711,7 +1711,7 @@ static const struct driver_info ax88178a_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1724,7 +1724,7 @@ static const struct driver_info cypress_GX3_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1737,7 +1737,7 @@ static const struct driver_info dlink_dub1312_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1750,7 +1750,7 @@ static const struct driver_info sitecom_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1763,7 +1763,7 @@ static const struct driver_info samsung_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1776,7 +1776,7 @@ static const struct driver_info lenovo_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; @@ -1789,7 +1789,7 @@ static const struct driver_info belkin_info = { .link_reset = ax88179_link_reset, .reset = ax88179_reset, .stop = ax88179_stop, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_SEND_ZLP | FLAG_THROTTLE_RX, .rx_fixup = ax88179_rx_fixup, .tx_fixup = ax88179_tx_fixup, }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index af3a3ccf2e3c..c3ca4b7b501f 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -75,6 +75,10 @@ static int msg_level = -1; module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Override default message level"); +static int usb0_rx_skb_threshold = 500; +module_param(usb0_rx_skb_threshold, int, 0644); +MODULE_PARM_DESC(usb0_rx_skb_threshold, "Throttle rx traffic in USB3"); + /*-------------------------------------------------------------------------*/ /* handles CDC Ethernet and many other network "bulk data" interfaces */ @@ -654,9 +658,13 @@ block: if (netif_running (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags) && state != unlink_start) { - rx_submit (dev, urb, GFP_ATOMIC); - usb_mark_last_busy(dev->udev); - return; + if ((!(dev->driver_info->flags & FLAG_THROTTLE_RX)) || + ((dev->driver_info->flags & FLAG_THROTTLE_RX) && + (dev->done.qlen < usb0_rx_skb_threshold))) { + rx_submit(dev, urb, GFP_ATOMIC); + usb_mark_last_busy(dev->udev); + return; + } } usb_free_urb (urb); } diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index a90e2a9dfdd3..73f5f58d6e72 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -129,6 +129,7 @@ struct driver_info { #define FLAG_MULTI_PACKET 0x2000 #define FLAG_RX_ASSEMBLE 0x4000 /* rx packets may span >1 frames */ #define FLAG_NOARP 0x8000 /* device can't do ARP */ +#define FLAG_THROTTLE_RX 0x10000 /* Throttle RX traffic in USB SS */ /* init device ... can sleep, or cause probe() failure */ int (*bind)(struct usbnet *, struct usb_interface *);