diff options
-rw-r--r-- | drivers/net/usb/cdc_ncm.c | 108 |
1 files changed, 44 insertions, 64 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 83e6d5ba962a..62dcb2e11e0b 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -76,8 +76,7 @@ static u8 cdc_ncm_setup(struct usbnet *dev) int err; int eth_hlen; u16 ntb_fmt_supported; - u32 min_dgram_size; - u32 min_hdr_size; + __le16 max_datagram_size; iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; @@ -101,20 +100,29 @@ static u8 cdc_ncm_setup(struct usbnet *dev) ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams); ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported); - eth_hlen = ETH_HLEN; - min_dgram_size = CDC_NCM_MIN_DATAGRAM_SIZE; - min_hdr_size = CDC_NCM_MIN_HDR_SIZE; - if (ctx->mbim_desc != NULL) { - flags = ctx->mbim_desc->bmNetworkCapabilities; + /* there are some minor differences in NCM and MBIM defaults */ + if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) { + if (!ctx->mbim_desc) + return -EINVAL; eth_hlen = 0; - min_dgram_size = CDC_MBIM_MIN_DATAGRAM_SIZE; - min_hdr_size = 0; - } else if (ctx->func_desc != NULL) { - flags = ctx->func_desc->bmNetworkCapabilities; + flags = ctx->mbim_desc->bmNetworkCapabilities; + ctx->max_datagram_size = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize); + if (ctx->max_datagram_size < CDC_MBIM_MIN_DATAGRAM_SIZE) + ctx->max_datagram_size = CDC_MBIM_MIN_DATAGRAM_SIZE; } else { - flags = 0; + if (!ctx->func_desc) + return -EINVAL; + eth_hlen = ETH_HLEN; + flags = ctx->func_desc->bmNetworkCapabilities; + ctx->max_datagram_size = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); + if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE) + ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE; } + /* common absolute max for NCM and MBIM */ + if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) + ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE; + dev_dbg(&dev->intf->dev, "dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n", ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus, @@ -151,8 +159,7 @@ static u8 cdc_ncm_setup(struct usbnet *dev) } /* verify maximum size of transmitted NTB in bytes */ - if ((ctx->tx_max < - (min_hdr_size + min_dgram_size)) || + if ((ctx->tx_max < (CDC_NCM_MIN_HDR_SIZE + ctx->max_datagram_size)) || (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) { dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n", CDC_NCM_NTB_MAX_SIZE_TX); @@ -229,60 +236,33 @@ static u8 cdc_ncm_setup(struct usbnet *dev) dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit failed\n"); } - ctx->max_datagram_size = min_dgram_size; + /* inform the device about the selected Max Datagram Size */ + if (!(flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE)) + goto out; - /* set Max Datagram Size (MTU) */ - if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { - __le16 max_datagram_size; - u16 eth_max_sz; - if (ctx->ether_desc != NULL) - eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - else if (ctx->mbim_desc != NULL) - eth_max_sz = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize); - else - goto max_dgram_err; - - err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_IN - | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, 2); - if (err < 0) { - dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", - min_dgram_size); - } else { - ctx->max_datagram_size = - le16_to_cpu(max_datagram_size); - /* Check Eth descriptor value */ - if (ctx->max_datagram_size > eth_max_sz) - ctx->max_datagram_size = eth_max_sz; - - if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE) - ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE; - - if (ctx->max_datagram_size < min_dgram_size) - ctx->max_datagram_size = min_dgram_size; - - /* if value changed, update device */ - if (ctx->max_datagram_size != - le16_to_cpu(max_datagram_size)) { - max_datagram_size = cpu_to_le16(ctx->max_datagram_size); - err = usbnet_write_cmd(dev, - USB_CDC_SET_MAX_DATAGRAM_SIZE, - USB_TYPE_CLASS | USB_DIR_OUT - | USB_RECIP_INTERFACE, - 0, - iface_no, &max_datagram_size, - 2); - if (err < 0) - dev_dbg(&dev->intf->dev, "SET_MAX_DGRAM_SIZE failed\n"); - } - } + /* read current mtu value from device */ + err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE, + USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, + 0, iface_no, &max_datagram_size, 2); + if (err < 0) { + dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n"); + goto out; } -max_dgram_err: - if (dev->net->mtu != (ctx->max_datagram_size - eth_hlen)) - dev->net->mtu = ctx->max_datagram_size - eth_hlen; + if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size) + goto out; + + max_datagram_size = cpu_to_le16(ctx->max_datagram_size); + err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, + 0, iface_no, &max_datagram_size, 2); + if (err < 0) + dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n"); +out: + /* set MTU to max supported by the device if necessary */ + if (dev->net->mtu > ctx->max_datagram_size - eth_hlen) + dev->net->mtu = ctx->max_datagram_size - eth_hlen; return 0; } |