]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/usb/usbnet.c
USBNET: increase max rx/tx qlen for improving USB3 thoughtput
[karo-tx-linux.git] / drivers / net / usb / usbnet.c
index 06ee82f557d45ba31b4847c187f57771ae2c73d2..e4811d7b5af1cb19aad389f231781cede61c3f81 100644 (file)
  * For high speed, each frame comfortably fits almost 36 max size
  * Ethernet packets (so queues should be bigger).
  *
- * REVISIT qlens should be members of 'struct usbnet'; the goal is to
- * let the USB host controller be busy for 5msec or more before an irq
- * is required, under load.  Jumbograms change the equation.
+ * The goal is to let the USB host controller be busy for 5msec or
+ * more before an irq is required, under load.  Jumbograms change
+ * the equation.
  */
-#define RX_MAX_QUEUE_MEMORY (60 * 1518)
-#define        RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
-                       (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
-#define        TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
-                       (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
+#define        MAX_QUEUE_MEMORY        (60 * 1518)
+#define        RX_QLEN(dev)            ((dev)->rx_qlen)
+#define        TX_QLEN(dev)            ((dev)->tx_qlen)
 
 // reawaken network queue this soon after stopping; else watchdog barks
 #define TX_TIMEOUT_JIFFIES     (5*HZ)
@@ -347,6 +345,31 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(usbnet_skb_return);
 
+/* must be called if hard_mtu or rx_urb_size changed */
+void usbnet_update_max_qlen(struct usbnet *dev)
+{
+       enum usb_device_speed speed = dev->udev->speed;
+
+       switch (speed) {
+       case USB_SPEED_HIGH:
+               dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size;
+               dev->tx_qlen = MAX_QUEUE_MEMORY / dev->hard_mtu;
+               break;
+       case USB_SPEED_SUPER:
+               /*
+                * Not take default 5ms qlen for super speed HC to
+                * save memory, and iperf tests show 2.5ms qlen can
+                * work well
+                */
+               dev->rx_qlen = 5 * MAX_QUEUE_MEMORY / dev->rx_urb_size;
+               dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu;
+               break;
+       default:
+               dev->rx_qlen = dev->tx_qlen = 4;
+       }
+}
+EXPORT_SYMBOL_GPL(usbnet_update_max_qlen);
+
 \f
 /*-------------------------------------------------------------------------
  *
@@ -375,6 +398,9 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu)
                        usbnet_unlink_rx_urbs(dev);
        }
 
+       /* max qlen depend on hard_mtu and rx_urb_size */
+       usbnet_update_max_qlen(dev);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_change_mtu);
@@ -843,6 +869,9 @@ int usbnet_open (struct net_device *net)
                goto done;
        }
 
+       /* hard_mtu or rx_urb_size may change in reset() */
+       usbnet_update_max_qlen(dev);
+
        // insist peer be connected
        if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
                netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval);
@@ -927,6 +956,9 @@ int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
        if (dev->driver_info->link_reset)
                dev->driver_info->link_reset(dev);
 
+       /* hard_mtu or rx_urb_size may change in link_reset() */
+       usbnet_update_max_qlen(dev);
+
        return retval;
 
 }
@@ -1020,6 +1052,9 @@ static void __handle_link_change(struct usbnet *dev)
                tasklet_schedule(&dev->bh);
        }
 
+       /* hard_mtu or rx_urb_size may change during link change */
+       usbnet_update_max_qlen(dev);
+
        clear_bit(EVENT_LINK_CHANGE, &dev->flags);
 }
 
@@ -1599,6 +1634,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        if ((dev->driver_info->flags & FLAG_WWAN) != 0)
                SET_NETDEV_DEVTYPE(net, &wwan_type);
 
+       /* initialize max rx_qlen and tx_qlen */
+       usbnet_update_max_qlen(dev);
+
        status = register_netdev (net);
        if (status)
                goto out4;