@@ -153,11 +153,30 @@ static void qmimux_get_stats64(struct net_device *net,
}
}
+static int qmimux_change_mtu(struct net_device *net, int new_mtu)
+{
+ struct qmimux_priv *priv = netdev_priv(net);
+ struct net_device *real_dev = priv->real_dev;
+ struct usbnet *dev = netdev_priv(real_dev);
+
+ net->mtu = new_mtu;
+ if (dev->hard_mtu < new_mtu + sizeof(struct qmimux_hdr)) {
+ /* rx_urb_size is not in sync with hard_mtu and should
+ * be changed through qmi_wwan_change_mtu
+ */
+ dev->hard_mtu = new_mtu + sizeof(struct qmimux_hdr);
+ usbnet_update_max_qlen(dev);
+ }
+
+ return 0;
+}
+
static const struct net_device_ops qmimux_netdev_ops = {
.ndo_open = qmimux_open,
.ndo_stop = qmimux_stop,
.ndo_start_xmit = qmimux_start_xmit,
.ndo_get_stats64 = qmimux_get_stats64,
+ .ndo_change_mtu = qmimux_change_mtu,
};
static void qmimux_setup(struct net_device *dev)
@@ -322,6 +341,33 @@ static void qmimux_unregister_device(struct net_device *dev,
dev_put(real_dev);
}
+static int qmi_wwan_change_mtu(struct net_device *net, int new_mtu)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct qmi_wwan_state *info = (void *)&dev->data;
+
+ if (info->flags & QMI_WWAN_FLAG_MUX) {
+ int old_rx_urb_size = dev->rx_urb_size;
+
+ net->mtu = new_mtu;
+ dev->rx_urb_size = net->mtu;
+
+ if (dev->rx_urb_size > old_rx_urb_size) {
+ usbnet_pause_rx(dev);
+ usbnet_unlink_rx_urbs(dev);
+ usbnet_resume_rx(dev);
+ }
+ /* max qlen depend on hard_mtu and rx_urb_size: hard_mtu is used
+ * for tx_qlen and is set by qmimux_change_mtu
+ */
+ usbnet_update_max_qlen(dev);
+
+ return 0;
+ } else {
+ return usbnet_change_mtu(net, new_mtu);
+ }
+}
+
static void qmi_wwan_netdev_setup(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
@@ -345,7 +391,7 @@ static void qmi_wwan_netdev_setup(struct net_device *net)
}
/* recalculate buffers after changing hard_header_len */
- usbnet_change_mtu(net, net->mtu);
+ qmi_wwan_change_mtu(net, net->mtu);
}
static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf)
@@ -450,7 +496,19 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
ret = qmimux_register_device(dev->net, mux_id);
if (!ret) {
- info->flags |= QMI_WWAN_FLAG_MUX;
+ if (!(info->flags & QMI_WWAN_FLAG_MUX)) {
+ info->flags |= QMI_WWAN_FLAG_MUX;
+ /* Setting a default rx_urb_size for dealing with qmap
+ * downlink data aggregation: this should be good for
+ * most of the modems, but some could require a larger
+ * value to be set changing the MTU of the master
+ * interface
+ */
+ dev->rx_urb_size = 16384;
+ dev->hard_mtu =
+ ETH_DATA_LEN + sizeof(struct qmimux_hdr);
+ usbnet_update_max_qlen(dev);
+ }
ret = len;
}
err:
@@ -492,8 +550,14 @@ static ssize_t del_mux_store(struct device *d, struct device_attribute *attr, c
}
qmimux_unregister_device(del_dev, NULL);
- if (!qmimux_has_slaves(dev))
+ if (!qmimux_has_slaves(dev)) {
info->flags &= ~QMI_WWAN_FLAG_MUX;
+ /* Restore mtu to eth default */
+ dev->net->mtu = ETH_DATA_LEN;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ dev->rx_urb_size = dev->hard_mtu;
+ qmi_wwan_netdev_setup(dev->net);
+ }
ret = len;
err:
rtnl_unlock();
@@ -619,7 +683,7 @@ static const struct net_device_ops qmi_wwan_netdev_ops = {
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_change_mtu = qmi_wwan_change_mtu,
.ndo_get_stats64 = usbnet_get_stats64,
.ndo_set_mac_address = qmi_wwan_mac_addr,
.ndo_validate_addr = eth_validate_addr,
The patch introduces mtu change functions both for master and qmimux network interfaces in order to properly deal with downlink aggregated packets feature set from user-space. rmnet can be configured for downling aggregated packets, requiring the rx_urb_size to be as much as the value set from user-space with the proper QMI request (see libqmi wda_set_data_format), so a default value for rx_urb_size is set when the first qmimux netdevice is created. Since some modems could require a different (usually higher) value, an mtu change function for the master netdevice has been added, in order to link the mtu change with rx_urb_size when qmimux is enabled. This affects also rx_qlen, but not tx_qlen. The possibility of modifying the tx_qlen is left to the qmimux mtu change function. Signed-off-by: Daniele Palmas <dnlplm@gmail.com> --- Hi Bjørn and Paul, this is an attempt to fix the dl aggregated rx_urb_size related issue and provide an hook for solving also Paul's issue, that can be done with a follow-up patch: it currently does not change the behavior when qmap is not enabled, calling usbnet_change_mtu. Let me know if it is something that could make sense. Thanks, Daniele --- drivers/net/usb/qmi_wwan.c | 72 +++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-)