The driver tried to keep as much CAN frames as possible submitted to the USB device (ESD_USB_MAX_TX_URBS). This has led to occasional "No free context" error messages in high load situations like with "cangen -g 0 -p 10 canX". This patch now calls netif_stop_queue() already if the number of active jobs reaches ESD_USB_TX_URBS_HI_WM which is < ESD_USB_MAX_TX_URBS. The netif_start_queue() is called in esd_usb_tx_done_msg() only if the number of active jobs is <= ESD_USB_TX_URBS_LO_WM. This change eliminates the occasional error messages and significantly reduces the number of calls to netif_start_queue() and netif_stop_queue(). The watermark limits have been chosen with the CAN-USB/Micro in mind to not to compromise its TX throughput. This device is running on USB 1.1 only with its 1ms USB polling cycle where a ESD_USB_TX_URBS_LO_WM value below 9 decreases the TX throughput. Fixes: 96d8e90382dc ("can: Add driver for esd CAN-USB/2 device") Signed-off-by: Stefan Mätje --- drivers/net/can/usb/esd_usb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 4ba6b6abd928..98ab7c836880 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -98,6 +98,8 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_RX_BUFFER_SIZE 1024 #define ESD_USB_MAX_RX_URBS 4 #define ESD_USB_MAX_TX_URBS 16 /* must be power of 2 */ +#define ESD_USB_TX_URBS_HI_WM ((15 * ESD_USB_MAX_TX_URBS) / 16) +#define ESD_USB_TX_URBS_LO_WM ((9 * ESD_USB_MAX_TX_URBS) / 16) #define ESD_USB_DRAIN_TIMEOUT_MS 100 /* Modes for CAN-USB/3, to be used for esd_usb_3_set_baudrate_msg_x.mode */ @@ -478,7 +480,8 @@ static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv, if (!netif_device_present(netdev)) return; - netif_wake_queue(netdev); + if (atomic_read(&priv->active_tx_jobs) <= ESD_USB_TX_URBS_LO_WM) + netif_wake_queue(netdev); } static void esd_usb_read_bulk_callback(struct urb *urb) @@ -987,7 +990,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, context->priv = priv; context->echo_index = i; - /* hnd must not be 0 - MSB is stripped in txdone handling */ + /* hnd must not be 0 - MSB is stripped in TX done handling */ msg->tx.hnd = BIT(31) | i; /* returned in TX done message */ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf, @@ -1002,8 +1005,8 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, atomic_inc(&priv->active_tx_jobs); - /* Slow down tx path */ - if (atomic_read(&priv->active_tx_jobs) >= ESD_USB_MAX_TX_URBS) + /* Slow down TX path */ + if (atomic_read(&priv->active_tx_jobs) >= ESD_USB_TX_URBS_HI_WM) netif_stop_queue(netdev); err = usb_submit_urb(urb, GFP_ATOMIC); -- 2.34.1