]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge tag 'usb-for-v3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Jul 2014 18:33:41 +0000 (11:33 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 21 Jul 2014 18:33:41 +0000 (11:33 -0700)
Felipe writes:

usb: patches for v3.17 merge window

Surprisingly enough, while a big set of patches, the majority is
composed of cleanups (using devm_*, fixing sparse errors, moving
code around, adding const, etc).

The highlights are addition of new support for PLX USB338x devices,
and support for USB 2.0-only configurations of the DWC3 IP core.

Signed-of-by: Felipe Balbi <balbi@ti.com>
16 files changed:
1  2 
Documentation/DocBook/gadget.tmpl
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_rndis.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/musb/musb_cppi41.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/ux500.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-tegra-usb.c
include/uapi/linux/usb/functionfs.h

index 2c425d70f7e2670405164da3b70e3a6e9d734811,1197165b8f28397e256c522fc79e8fc479e279b6..64162922117651344d698ffd53ece06eafca3324
@@@ -556,11 -556,11 +556,11 @@@ been converted to this framework
  Near-term plans include converting all of them, except for "gadgetfs".
  </para>
  
- !Edrivers/usb/gadget/f_acm.c
- !Edrivers/usb/gadget/f_ecm.c
- !Edrivers/usb/gadget/f_subset.c
- !Edrivers/usb/gadget/f_obex.c
- !Edrivers/usb/gadget/f_serial.c
+ !Edrivers/usb/gadget/function/f_acm.c
+ !Edrivers/usb/gadget/function/f_ecm.c
+ !Edrivers/usb/gadget/function/f_subset.c
+ !Edrivers/usb/gadget/function/f_obex.c
+ !Edrivers/usb/gadget/function/f_serial.c
  
  </sect1>
  
@@@ -708,7 -708,7 +708,7 @@@ hardware level details could be very di
  
  <para>Systems need specialized hardware support to implement OTG,
  notably including a special <emphasis>Mini-AB</emphasis> jack
 -and associated transciever to support <emphasis>Dual-Role</emphasis>
 +and associated transceiver to support <emphasis>Dual-Role</emphasis>
  operation:
  they can act either as a host, using the standard
  Linux-USB host side driver stack,
index 07a736acd0f247e6675a4c21ab8a6ddeda085137,961295d7042f39aceb05cf1d28e605a68dfac552..ef4936ff626c3cdea2bd0bc6e0a7e7328481a3a7
  #define USBOTGSS_DEV_EBC_EN                   0x0110
  #define USBOTGSS_DEBUG_OFFSET                 0x0600
  
- /* REVISION REGISTER */
- #define USBOTGSS_REVISION_XMAJOR(reg)         ((reg >> 8) & 0x7)
- #define USBOTGSS_REVISION_XMAJOR1             1
- #define USBOTGSS_REVISION_XMAJOR2             2
  /* SYSCONFIG REGISTER */
  #define USBOTGSS_SYSCONFIG_DMADISABLE         (1 << 16)
  
@@@ -129,7 -125,6 +125,6 @@@ struct dwc3_omap 
        u32                     irq_eoi_offset;
        u32                     debug_offset;
        u32                     irq0_offset;
-       u32                     revision;
  
        u32                     dma_status:1;
  
@@@ -322,7 -317,7 +317,7 @@@ static int dwc3_omap_remove_core(struc
  {
        struct platform_device *pdev = to_platform_device(dev);
  
 -      platform_device_unregister(pdev);
 +      of_device_unregister(pdev);
  
        return 0;
  }
@@@ -383,6 -378,87 +378,87 @@@ static int dwc3_omap_vbus_notifier(stru
        return NOTIFY_DONE;
  }
  
+ static void dwc3_omap_map_offset(struct dwc3_omap *omap)
+ {
+       struct device_node      *node = omap->dev->of_node;
+       /*
+        * Differentiate between OMAP5 and AM437x.
+        *
+        * For OMAP5(ES2.0) and AM437x wrapper revision is same, even
+        * though there are changes in wrapper register offsets.
+        *
+        * Using dt compatible to differentiate AM437x.
+        */
+       if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
+               omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
+               omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
+               omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
+               omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
+               omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
+       }
+ }
+ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
+ {
+       u32                     reg;
+       struct device_node      *node = omap->dev->of_node;
+       int                     utmi_mode = 0;
+       reg = dwc3_omap_read_utmi_status(omap);
+       of_property_read_u32(node, "utmi-mode", &utmi_mode);
+       switch (utmi_mode) {
+       case DWC3_OMAP_UTMI_MODE_SW:
+               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               break;
+       case DWC3_OMAP_UTMI_MODE_HW:
+               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+               break;
+       default:
+               dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
+       }
+       dwc3_omap_write_utmi_status(omap, reg);
+ }
+ static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
+ {
+       u32                     ret;
+       struct device_node      *node = omap->dev->of_node;
+       struct extcon_dev       *edev;
+       if (of_property_read_bool(node, "extcon")) {
+               edev = extcon_get_edev_by_phandle(omap->dev, 0);
+               if (IS_ERR(edev)) {
+                       dev_vdbg(omap->dev, "couldn't get extcon device\n");
+                       return -EPROBE_DEFER;
+               }
+               omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
+               ret = extcon_register_interest(&omap->extcon_vbus_dev,
+                                              edev->name, "USB",
+                                              &omap->vbus_nb);
+               if (ret < 0)
+                       dev_vdbg(omap->dev, "failed to register notifier for USB\n");
+               omap->id_nb.notifier_call = dwc3_omap_id_notifier;
+               ret = extcon_register_interest(&omap->extcon_id_dev,
+                                              edev->name, "USB-HOST",
+                                              &omap->id_nb);
+               if (ret < 0)
+                       dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n");
+               if (extcon_get_cable_state(edev, "USB") == true)
+                       dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+               if (extcon_get_cable_state(edev, "USB-HOST") == true)
+                       dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+       }
+       return 0;
+ }
  static int dwc3_omap_probe(struct platform_device *pdev)
  {
        struct device_node      *node = pdev->dev.of_node;
        struct dwc3_omap        *omap;
        struct resource         *res;
        struct device           *dev = &pdev->dev;
-       struct extcon_dev       *edev;
        struct regulator        *vbus_reg = NULL;
  
        int                     ret;
        int                     irq;
  
-       int                     utmi_mode = 0;
-       int                     x_major;
        u32                     reg;
  
        void __iomem            *base;
                goto err0;
        }
  
-       reg = dwc3_omap_readl(omap->base, USBOTGSS_REVISION);
-       omap->revision = reg;
-       x_major = USBOTGSS_REVISION_XMAJOR(reg);
-       /* Differentiate between OMAP5 and AM437x */
-       switch (x_major) {
-       case USBOTGSS_REVISION_XMAJOR1:
-       case USBOTGSS_REVISION_XMAJOR2:
-               omap->irq_eoi_offset = 0;
-               omap->irq0_offset = 0;
-               omap->irqmisc_offset = 0;
-               omap->utmi_otg_offset = 0;
-               omap->debug_offset = 0;
-               break;
-       default:
-               /* Default to the latest revision */
-               omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
-               omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
-               omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
-               omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
-               omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
-               break;
-       }
-       /* For OMAP5(ES2.0) and AM437x x_major is 2 even though there are
-        * changes in wrapper registers, Using dt compatible for aegis
-        */
-       if (of_device_is_compatible(node, "ti,am437x-dwc3")) {
-               omap->irq_eoi_offset = USBOTGSS_EOI_OFFSET;
-               omap->irq0_offset = USBOTGSS_IRQ0_OFFSET;
-               omap->irqmisc_offset = USBOTGSS_IRQMISC_OFFSET;
-               omap->utmi_otg_offset = USBOTGSS_UTMI_OTG_OFFSET;
-               omap->debug_offset = USBOTGSS_DEBUG_OFFSET;
-       }
-       reg = dwc3_omap_read_utmi_status(omap);
-       of_property_read_u32(node, "utmi-mode", &utmi_mode);
-       switch (utmi_mode) {
-       case DWC3_OMAP_UTMI_MODE_SW:
-               reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-               break;
-       case DWC3_OMAP_UTMI_MODE_HW:
-               reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
-               break;
-       default:
-               dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
-       }
-       dwc3_omap_write_utmi_status(omap, reg);
+       dwc3_omap_map_offset(omap);
+       dwc3_omap_set_utmi_mode(omap);
  
        /* check the DMA Status */
        reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
  
        dwc3_omap_enable_irqs(omap);
  
-       if (of_property_read_bool(node, "extcon")) {
-               edev = extcon_get_edev_by_phandle(dev, 0);
-               if (IS_ERR(edev)) {
-                       dev_vdbg(dev, "couldn't get extcon device\n");
-                       ret = -EPROBE_DEFER;
-                       goto err2;
-               }
-               omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
-               ret = extcon_register_interest(&omap->extcon_vbus_dev,
-                       edev->name, "USB", &omap->vbus_nb);
-               if (ret < 0)
-                       dev_vdbg(dev, "failed to register notifier for USB\n");
-               omap->id_nb.notifier_call = dwc3_omap_id_notifier;
-               ret = extcon_register_interest(&omap->extcon_id_dev, edev->name,
-                                        "USB-HOST", &omap->id_nb);
-               if (ret < 0)
-                       dev_vdbg(dev,
-                               "failed to register notifier for USB-HOST\n");
-               if (extcon_get_cable_state(edev, "USB") == true)
-                       dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
-               if (extcon_get_cable_state(edev, "USB-HOST") == true)
-                       dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
-       }
+       ret = dwc3_omap_extcon_register(omap);
+       if (ret < 0)
+               goto err2;
  
        ret = of_platform_populate(node, NULL, NULL, dev);
        if (ret) {
@@@ -599,7 -599,7 +599,7 @@@ static int dwc3_omap_prepare(struct dev
  {
        struct dwc3_omap        *omap = dev_get_drvdata(dev);
  
 -      dwc3_omap_disable_irqs(omap);
 +      dwc3_omap_write_irqmisc_set(omap, 0x00);
  
        return 0;
  }
  static void dwc3_omap_complete(struct device *dev)
  {
        struct dwc3_omap        *omap = dev_get_drvdata(dev);
 +      u32                     reg;
  
 -      dwc3_omap_enable_irqs(omap);
 +      reg = (USBOTGSS_IRQMISC_OEVT |
 +                      USBOTGSS_IRQMISC_DRVVBUS_RISE |
 +                      USBOTGSS_IRQMISC_CHRGVBUS_RISE |
 +                      USBOTGSS_IRQMISC_DISCHRGVBUS_RISE |
 +                      USBOTGSS_IRQMISC_IDPULLUP_RISE |
 +                      USBOTGSS_IRQMISC_DRVVBUS_FALL |
 +                      USBOTGSS_IRQMISC_CHRGVBUS_FALL |
 +                      USBOTGSS_IRQMISC_DISCHRGVBUS_FALL |
 +                      USBOTGSS_IRQMISC_IDPULLUP_FALL);
 +
 +      dwc3_omap_write_irqmisc_set(omap, reg);
  }
  
  static int dwc3_omap_suspend(struct device *dev)
index dab7927d10094e17d8105a25e28a17fd785ae6de,d9304a8ceef39748f843e455254a3aa85b9d0716..349cacc577d81a679cacd4494bb7ead82f11cfa4
@@@ -828,6 -828,10 +828,6 @@@ static void dwc3_prepare_one_trb(struc
                        length, last ? " last" : "",
                        chain ? " chain" : "");
  
 -      /* Skip the LINK-TRB on ISOC */
 -      if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
 -                      usb_endpoint_xfer_isoc(dep->endpoint.desc))
 -              dep->free_slot++;
  
        trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
  
        }
  
        dep->free_slot++;
 +      /* Skip the LINK-TRB on ISOC */
 +      if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
 +                      usb_endpoint_xfer_isoc(dep->endpoint.desc))
 +              dep->free_slot++;
  
        trb->size = DWC3_TRB_SIZE_LENGTH(length);
        trb->bpl = lower_32_bits(dma);
@@@ -1971,8 -1971,7 +1971,7 @@@ static int dwc3_cleanup_done_reqs(struc
  }
  
  static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
-               struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
-               int start_new)
+               struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
  {
        unsigned                status = 0;
        int                     clean_busy;
@@@ -2039,7 -2038,7 +2038,7 @@@ static void dwc3_endpoint_interrupt(str
                        return;
                }
  
-               dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+               dwc3_endpoint_transfer_complete(dwc, dep, event);
                break;
        case DWC3_DEPEVT_XFERINPROGRESS:
                if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
                        return;
                }
  
-               dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+               dwc3_endpoint_transfer_complete(dwc, dep, event);
                break;
        case DWC3_DEPEVT_XFERNOTREADY:
                if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
index 97142146eead170243c131a7e9ad0356dac63444,bcc2a6248187fd58693d45075c6dde314a6bb545..811c2c7cc2694303ca40bcad14054d8599a1be93
@@@ -1021,12 -1021,10 +1021,10 @@@ static ssize_t ext_prop_data_store(stru
  
        if (page[len - 1] == '\n' || page[len - 1] == '\0')
                --len;
-       new_data = kzalloc(len, GFP_KERNEL);
+       new_data = kmemdup(page, len, GFP_KERNEL);
        if (!new_data)
                return -ENOMEM;
  
-       memcpy(new_data, page, len);
        if (desc->opts_mutex)
                mutex_lock(desc->opts_mutex);
        kfree(ext_prop->data);
@@@ -1145,15 -1143,15 +1143,15 @@@ static struct configfs_item_operations 
        .store_attribute        = usb_os_desc_attr_store,
  };
  
 -static ssize_t rndis_grp_compatible_id_show(struct usb_os_desc *desc,
 -                                          char *page)
 +static ssize_t interf_grp_compatible_id_show(struct usb_os_desc *desc,
 +                                           char *page)
  {
        memcpy(page, desc->ext_compat_id, 8);
        return 8;
  }
  
 -static ssize_t rndis_grp_compatible_id_store(struct usb_os_desc *desc,
 -                                           const char *page, size_t len)
 +static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
 +                                            const char *page, size_t len)
  {
        int l;
  
        return len;
  }
  
 -static struct usb_os_desc_attribute rndis_grp_attr_compatible_id =
 +static struct usb_os_desc_attribute interf_grp_attr_compatible_id =
        __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR,
 -                      rndis_grp_compatible_id_show,
 -                      rndis_grp_compatible_id_store);
 +                      interf_grp_compatible_id_show,
 +                      interf_grp_compatible_id_store);
  
 -static ssize_t rndis_grp_sub_compatible_id_show(struct usb_os_desc *desc,
 -                                              char *page)
 +static ssize_t interf_grp_sub_compatible_id_show(struct usb_os_desc *desc,
 +                                               char *page)
  {
        memcpy(page, desc->ext_compat_id + 8, 8);
        return 8;
  }
  
 -static ssize_t rndis_grp_sub_compatible_id_store(struct usb_os_desc *desc,
 -                                               const char *page, size_t len)
 +static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
 +                                                const char *page, size_t len)
  {
        int l;
  
        return len;
  }
  
 -static struct usb_os_desc_attribute rndis_grp_attr_sub_compatible_id =
 +static struct usb_os_desc_attribute interf_grp_attr_sub_compatible_id =
        __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR,
 -                      rndis_grp_sub_compatible_id_show,
 -                      rndis_grp_sub_compatible_id_store);
 +                      interf_grp_sub_compatible_id_show,
 +                      interf_grp_sub_compatible_id_store);
  
  static struct configfs_attribute *interf_grp_attrs[] = {
 -      &rndis_grp_attr_compatible_id.attr,
 -      &rndis_grp_attr_sub_compatible_id.attr,
 +      &interf_grp_attr_compatible_id.attr,
 +      &interf_grp_attr_sub_compatible_id.attr,
        NULL
  };
  
  int usb_os_desc_prepare_interf_dir(struct config_group *parent,
                                   int n_interf,
                                   struct usb_os_desc **desc,
 +                                 char **names,
                                   struct module *owner)
  {
        struct config_group **f_default_groups, *os_desc_group,
                d = desc[n_interf];
                d->owner = owner;
                config_group_init_type_name(&d->group, "", interface_type);
 -              config_item_set_name(&d->group.cg_item, "interface.%d",
 -                                   n_interf);
 +              config_item_set_name(&d->group.cg_item, "interface.%s",
 +                                   names[n_interf]);
                interface_groups[n_interf] = &d->group;
        }
  
index 8598c27c7d4344e6448dc4fcae7ff38577156278,fe45060e0a7a3e19df5b0383d88daefeae8e19a6..dc30adf15a01d22cbde3c3a195a146373e302ef0
@@@ -34,6 -34,7 +34,7 @@@
  
  #include "u_fs.h"
  #include "u_f.h"
+ #include "u_os_desc.h"
  #include "configfs.h"
  
  #define FUNCTIONFS_MAGIC      0xa647361 /* Chosen by a honest dice roll ;) */
@@@ -1483,13 -1484,11 +1484,13 @@@ static int functionfs_bind(struct ffs_d
        ffs->ep0req->context = ffs;
  
        lang = ffs->stringtabs;
 -      for (lang = ffs->stringtabs; *lang; ++lang) {
 -              struct usb_string *str = (*lang)->strings;
 -              int id = first_id;
 -              for (; str->s; ++id, ++str)
 -                      str->id = id;
 +      if (lang) {
 +              for (; *lang; ++lang) {
 +                      struct usb_string *str = (*lang)->strings;
 +                      int id = first_id;
 +                      for (; str->s; ++id, ++str)
 +                              str->id = id;
 +              }
        }
  
        ffs->gadget = cdev->gadget;
@@@ -1646,13 -1645,22 +1647,22 @@@ enum ffs_entity_type 
        FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
  };
  
+ enum ffs_os_desc_type {
+       FFS_OS_DESC, FFS_OS_DESC_EXT_COMPAT, FFS_OS_DESC_EXT_PROP
+ };
  typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
                                   u8 *valuep,
                                   struct usb_descriptor_header *desc,
                                   void *priv);
  
- static int __must_check ffs_do_desc(char *data, unsigned len,
-                                   ffs_entity_callback entity, void *priv)
+ typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
+                                   struct usb_os_desc_header *h, void *data,
+                                   unsigned len, void *priv);
+ static int __must_check ffs_do_single_desc(char *data, unsigned len,
+                                          ffs_entity_callback entity,
+                                          void *priv)
  {
        struct usb_descriptor_header *_ds = (void *)data;
        u8 length;
@@@ -1804,7 -1812,7 +1814,7 @@@ static int __must_check ffs_do_descs(un
                if (!data)
                        return _len - len;
  
-               ret = ffs_do_desc(data, len, entity, priv);
+               ret = ffs_do_single_desc(data, len, entity, priv);
                if (unlikely(ret < 0)) {
                        pr_debug("%s returns %d\n", __func__, ret);
                        return ret;
@@@ -1857,11 -1865,191 +1867,191 @@@ static int __ffs_data_do_entity(enum ff
        return 0;
  }
  
+ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type,
+                                  struct usb_os_desc_header *desc)
+ {
+       u16 bcd_version = le16_to_cpu(desc->bcdVersion);
+       u16 w_index = le16_to_cpu(desc->wIndex);
+       if (bcd_version != 1) {
+               pr_vdebug("unsupported os descriptors version: %d",
+                         bcd_version);
+               return -EINVAL;
+       }
+       switch (w_index) {
+       case 0x4:
+               *next_type = FFS_OS_DESC_EXT_COMPAT;
+               break;
+       case 0x5:
+               *next_type = FFS_OS_DESC_EXT_PROP;
+               break;
+       default:
+               pr_vdebug("unsupported os descriptor type: %d", w_index);
+               return -EINVAL;
+       }
+       return sizeof(*desc);
+ }
+ /*
+  * Process all extended compatibility/extended property descriptors
+  * of a feature descriptor
+  */
+ static int __must_check ffs_do_single_os_desc(char *data, unsigned len,
+                                             enum ffs_os_desc_type type,
+                                             u16 feature_count,
+                                             ffs_os_desc_callback entity,
+                                             void *priv,
+                                             struct usb_os_desc_header *h)
+ {
+       int ret;
+       const unsigned _len = len;
+       ENTER();
+       /* loop over all ext compat/ext prop descriptors */
+       while (feature_count--) {
+               ret = entity(type, h, data, len, priv);
+               if (unlikely(ret < 0)) {
+                       pr_debug("bad OS descriptor, type: %d\n", type);
+                       return ret;
+               }
+               data += ret;
+               len -= ret;
+       }
+       return _len - len;
+ }
+ /* Process a number of complete Feature Descriptors (Ext Compat or Ext Prop) */
+ static int __must_check ffs_do_os_descs(unsigned count,
+                                       char *data, unsigned len,
+                                       ffs_os_desc_callback entity, void *priv)
+ {
+       const unsigned _len = len;
+       unsigned long num = 0;
+       ENTER();
+       for (num = 0; num < count; ++num) {
+               int ret;
+               enum ffs_os_desc_type type;
+               u16 feature_count;
+               struct usb_os_desc_header *desc = (void *)data;
+               if (len < sizeof(*desc))
+                       return -EINVAL;
+               /*
+                * Record "descriptor" entity.
+                * Process dwLength, bcdVersion, wIndex, get b/wCount.
+                * Move the data pointer to the beginning of extended
+                * compatibilities proper or extended properties proper
+                * portions of the data
+                */
+               if (le32_to_cpu(desc->dwLength) > len)
+                       return -EINVAL;
+               ret = __ffs_do_os_desc_header(&type, desc);
+               if (unlikely(ret < 0)) {
+                       pr_debug("entity OS_DESCRIPTOR(%02lx); ret = %d\n",
+                                num, ret);
+                       return ret;
+               }
+               /*
+                * 16-bit hex "?? 00" Little Endian looks like 8-bit hex "??"
+                */
+               feature_count = le16_to_cpu(desc->wCount);
+               if (type == FFS_OS_DESC_EXT_COMPAT &&
+                   (feature_count > 255 || desc->Reserved))
+                               return -EINVAL;
+               len -= ret;
+               data += ret;
+               /*
+                * Process all function/property descriptors
+                * of this Feature Descriptor
+                */
+               ret = ffs_do_single_os_desc(data, len, type,
+                                           feature_count, entity, priv, desc);
+               if (unlikely(ret < 0)) {
+                       pr_debug("%s returns %d\n", __func__, ret);
+                       return ret;
+               }
+               len -= ret;
+               data += ret;
+       }
+       return _len - len;
+ }
+ /**
+  * Validate contents of the buffer from userspace related to OS descriptors.
+  */
+ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
+                                struct usb_os_desc_header *h, void *data,
+                                unsigned len, void *priv)
+ {
+       struct ffs_data *ffs = priv;
+       u8 length;
+       ENTER();
+       switch (type) {
+       case FFS_OS_DESC_EXT_COMPAT: {
+               struct usb_ext_compat_desc *d = data;
+               int i;
+               if (len < sizeof(*d) ||
+                   d->bFirstInterfaceNumber >= ffs->interfaces_count ||
+                   d->Reserved1)
+                       return -EINVAL;
+               for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i)
+                       if (d->Reserved2[i])
+                               return -EINVAL;
+               length = sizeof(struct usb_ext_compat_desc);
+       }
+               break;
+       case FFS_OS_DESC_EXT_PROP: {
+               struct usb_ext_prop_desc *d = data;
+               u32 type, pdl;
+               u16 pnl;
+               if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
+                       return -EINVAL;
+               length = le32_to_cpu(d->dwSize);
+               type = le32_to_cpu(d->dwPropertyDataType);
+               if (type < USB_EXT_PROP_UNICODE ||
+                   type > USB_EXT_PROP_UNICODE_MULTI) {
+                       pr_vdebug("unsupported os descriptor property type: %d",
+                                 type);
+                       return -EINVAL;
+               }
+               pnl = le16_to_cpu(d->wPropertyNameLength);
+               pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
+               if (length != 14 + pnl + pdl) {
+                       pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
+                                 length, pnl, pdl, type);
+                       return -EINVAL;
+               }
+               ++ffs->ms_os_descs_ext_prop_count;
+               /* property name reported to the host as "WCHAR"s */
+               ffs->ms_os_descs_ext_prop_name_len += pnl * 2;
+               ffs->ms_os_descs_ext_prop_data_len += pdl;
+       }
+               break;
+       default:
+               pr_vdebug("unknown descriptor: %d\n", type);
+               return -EINVAL;
+       }
+       return length;
+ }
  static int __ffs_data_got_descs(struct ffs_data *ffs,
                                char *const _data, size_t len)
  {
        char *data = _data, *raw_descs;
-       unsigned counts[3], flags;
+       unsigned os_descs_count = 0, counts[3], flags;
        int ret = -EINVAL, i;
  
        ENTER();
                flags = get_unaligned_le32(data + 8);
                if (flags & ~(FUNCTIONFS_HAS_FS_DESC |
                              FUNCTIONFS_HAS_HS_DESC |
-                             FUNCTIONFS_HAS_SS_DESC)) {
+                             FUNCTIONFS_HAS_SS_DESC |
+                             FUNCTIONFS_HAS_MS_OS_DESC)) {
                        ret = -ENOSYS;
                        goto error;
                }
                        len  -= 4;
                }
        }
+       if (flags & (1 << i)) {
+               os_descs_count = get_unaligned_le32(data);
+               data += 4;
+               len -= 4;
+       };
  
        /* Read descriptors */
        raw_descs = data;
                data += ret;
                len  -= ret;
        }
+       if (os_descs_count) {
+               ret = ffs_do_os_descs(os_descs_count, data, len,
+                                     __ffs_data_do_os_desc, ffs);
+               if (ret < 0)
+                       goto error;
+               data += ret;
+               len -= ret;
+       }
  
        if (raw_descs == data || len) {
                ret = -EINVAL;
        ffs->fs_descs_count     = counts[0];
        ffs->hs_descs_count     = counts[1];
        ffs->ss_descs_count     = counts[2];
+       ffs->ms_os_descs_count  = os_descs_count;
  
        return 0;
  
@@@ -2268,6 -2471,85 +2473,85 @@@ static int __ffs_func_bind_do_nums(enu
        return 0;
  }
  
+ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
+                                     struct usb_os_desc_header *h, void *data,
+                                     unsigned len, void *priv)
+ {
+       struct ffs_function *func = priv;
+       u8 length = 0;
+       switch (type) {
+       case FFS_OS_DESC_EXT_COMPAT: {
+               struct usb_ext_compat_desc *desc = data;
+               struct usb_os_desc_table *t;
+               t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
+               t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
+               memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
+                      ARRAY_SIZE(desc->CompatibleID) +
+                      ARRAY_SIZE(desc->SubCompatibleID));
+               length = sizeof(*desc);
+       }
+               break;
+       case FFS_OS_DESC_EXT_PROP: {
+               struct usb_ext_prop_desc *desc = data;
+               struct usb_os_desc_table *t;
+               struct usb_os_desc_ext_prop *ext_prop;
+               char *ext_prop_name;
+               char *ext_prop_data;
+               t = &func->function.os_desc_table[h->interface];
+               t->if_id = func->interfaces_nums[h->interface];
+               ext_prop = func->ffs->ms_os_descs_ext_prop_avail;
+               func->ffs->ms_os_descs_ext_prop_avail += sizeof(*ext_prop);
+               ext_prop->type = le32_to_cpu(desc->dwPropertyDataType);
+               ext_prop->name_len = le16_to_cpu(desc->wPropertyNameLength);
+               ext_prop->data_len = le32_to_cpu(*(u32 *)
+                       usb_ext_prop_data_len_ptr(data, ext_prop->name_len));
+               length = ext_prop->name_len + ext_prop->data_len + 14;
+               ext_prop_name = func->ffs->ms_os_descs_ext_prop_name_avail;
+               func->ffs->ms_os_descs_ext_prop_name_avail +=
+                       ext_prop->name_len;
+               ext_prop_data = func->ffs->ms_os_descs_ext_prop_data_avail;
+               func->ffs->ms_os_descs_ext_prop_data_avail +=
+                       ext_prop->data_len;
+               memcpy(ext_prop_data,
+                      usb_ext_prop_data_ptr(data, ext_prop->name_len),
+                      ext_prop->data_len);
+               /* unicode data reported to the host as "WCHAR"s */
+               switch (ext_prop->type) {
+               case USB_EXT_PROP_UNICODE:
+               case USB_EXT_PROP_UNICODE_ENV:
+               case USB_EXT_PROP_UNICODE_LINK:
+               case USB_EXT_PROP_UNICODE_MULTI:
+                       ext_prop->data_len *= 2;
+                       break;
+               }
+               ext_prop->data = ext_prop_data;
+               memcpy(ext_prop_name, usb_ext_prop_name_ptr(data),
+                      ext_prop->name_len);
+               /* property name reported to the host as "WCHAR"s */
+               ext_prop->name_len *= 2;
+               ext_prop->name = ext_prop_name;
+               t->os_desc->ext_prop_len +=
+                       ext_prop->name_len + ext_prop->data_len + 14;
+               ++t->os_desc->ext_prop_count;
+               list_add_tail(&ext_prop->entry, &t->os_desc->ext_prop);
+       }
+               break;
+       default:
+               pr_vdebug("unknown descriptor: %d\n", type);
+       }
+       return length;
+ }
  static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f,
                                                struct usb_configuration *c)
  {
@@@ -2329,7 -2611,7 +2613,7 @@@ static int _ffs_func_bind(struct usb_co
        const int super = gadget_is_superspeed(func->gadget) &&
                func->ffs->ss_descs_count;
  
-       int fs_len, hs_len, ret;
+       int fs_len, hs_len, ss_len, ret, i;
  
        /* Make it a single chunk, less management later on */
        vla_group(d);
        vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs,
                super ? ffs->ss_descs_count + 1 : 0);
        vla_item_with_sz(d, short, inums, ffs->interfaces_count);
+       vla_item_with_sz(d, struct usb_os_desc_table, os_desc_table,
+                        c->cdev->use_os_string ? ffs->interfaces_count : 0);
+       vla_item_with_sz(d, char[16], ext_compat,
+                        c->cdev->use_os_string ? ffs->interfaces_count : 0);
+       vla_item_with_sz(d, struct usb_os_desc, os_desc,
+                        c->cdev->use_os_string ? ffs->interfaces_count : 0);
+       vla_item_with_sz(d, struct usb_os_desc_ext_prop, ext_prop,
+                        ffs->ms_os_descs_ext_prop_count);
+       vla_item_with_sz(d, char, ext_prop_name,
+                        ffs->ms_os_descs_ext_prop_name_len);
+       vla_item_with_sz(d, char, ext_prop_data,
+                        ffs->ms_os_descs_ext_prop_data_len);
        vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length);
        char *vlabuf;
  
                return -ENOTSUPP;
  
        /* Allocate a single chunk, less management later on */
-       vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
+       vlabuf = kzalloc(vla_group_size(d), GFP_KERNEL);
        if (unlikely(!vlabuf))
                return -ENOMEM;
  
-       /* Zero */
-       memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz);
+       ffs->ms_os_descs_ext_prop_avail = vla_ptr(vlabuf, d, ext_prop);
+       ffs->ms_os_descs_ext_prop_name_avail =
+               vla_ptr(vlabuf, d, ext_prop_name);
+       ffs->ms_os_descs_ext_prop_data_avail =
+               vla_ptr(vlabuf, d, ext_prop_data);
        /* Copy descriptors  */
        memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs,
               ffs->raw_descs_length);
  
        if (likely(super)) {
                func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs);
-               ret = ffs_do_descs(ffs->ss_descs_count,
+               ss_len = ffs_do_descs(ffs->ss_descs_count,
                                vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len,
                                d_raw_descs__sz - fs_len - hs_len,
                                __ffs_func_bind_do_descs, func);
-               if (unlikely(ret < 0))
+               if (unlikely(ss_len < 0)) {
+                       ret = ss_len;
                        goto error;
+               }
+       } else {
+               ss_len = 0;
        }
  
        /*
        if (unlikely(ret < 0))
                goto error;
  
+       func->function.os_desc_table = vla_ptr(vlabuf, d, os_desc_table);
+       if (c->cdev->use_os_string)
+               for (i = 0; i < ffs->interfaces_count; ++i) {
+                       struct usb_os_desc *desc;
+                       desc = func->function.os_desc_table[i].os_desc =
+                               vla_ptr(vlabuf, d, os_desc) +
+                               i * sizeof(struct usb_os_desc);
+                       desc->ext_compat_id =
+                               vla_ptr(vlabuf, d, ext_compat) + i * 16;
+                       INIT_LIST_HEAD(&desc->ext_prop);
+               }
+       ret = ffs_do_os_descs(ffs->ms_os_descs_count,
+                             vla_ptr(vlabuf, d, raw_descs) +
+                             fs_len + hs_len + ss_len,
+                             d_raw_descs__sz - fs_len - hs_len - ss_len,
+                             __ffs_func_bind_do_os_desc, func);
+       if (unlikely(ret < 0))
+               goto error;
+       func->function.os_desc_n =
+               c->cdev->use_os_string ? ffs->interfaces_count : 0;
        /* And we're done */
        ffs_event_add(ffs, FUNCTIONFS_BIND);
        return 0;
@@@ -2901,12 -3225,12 +3227,12 @@@ static void *ffs_acquire_dev(const cha
  
        ffs_dev = _ffs_find_dev(dev_name);
        if (!ffs_dev)
-               ffs_dev = ERR_PTR(-ENODEV);
+               ffs_dev = ERR_PTR(-ENOENT);
        else if (ffs_dev->mounted)
                ffs_dev = ERR_PTR(-EBUSY);
        else if (ffs_dev->ffs_acquire_dev_callback &&
            ffs_dev->ffs_acquire_dev_callback(ffs_dev))
-               ffs_dev = ERR_PTR(-ENODEV);
+               ffs_dev = ERR_PTR(-ENOENT);
        else
                ffs_dev->mounted = true;
  
index 9c41e9515b8e06a131b65b12fc1d70413459c2e5,a7b6bbbd697d49f74219e095a6922c41e382a056..ddb09dc6d1f2382f556ce378dada0b13df1f8462
@@@ -687,7 -687,7 +687,7 @@@ rndis_bind(struct usb_configuration *c
                f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
                                           GFP_KERNEL);
                if (!f->os_desc_table)
 -                      return PTR_ERR(f->os_desc_table);
 +                      return -ENOMEM;
                f->os_desc_n = 1;
                f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;
        }
        rndis_control_intf.bInterfaceNumber = status;
        rndis_union_desc.bMasterInterface0 = status;
  
+       if (cdev->use_os_string)
+               f->os_desc_table[0].if_id =
+                       rndis_iad_descriptor.bFirstInterface;
        status = usb_interface_id(c, f);
        if (status < 0)
                goto fail;
@@@ -905,7 -909,6 +909,7 @@@ static struct usb_function_instance *rn
  {
        struct f_rndis_opts *opts;
        struct usb_os_desc *descs[1];
 +      char *names[1];
  
        opts = kzalloc(sizeof(*opts), GFP_KERNEL);
        if (!opts)
        INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop);
  
        descs[0] = &opts->rndis_os_desc;
 +      names[0] = "rndis";
        usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
 -                                     THIS_MODULE);
 +                                     names, THIS_MODULE);
        config_group_init_type_name(&opts->func_inst.group, "",
                                    &rndis_func_type);
  
index 97b027724ee7a5a5ce28d1fdf5feb9335c4fef22,6e6f87656e7b0f5795caa17f387aa6cf89de2d41..d50adda913cfa6d57e1e6191ab5444d6981af47a
@@@ -483,7 -483,7 +483,7 @@@ static netdev_tx_t eth_start_xmit(struc
                                        struct net_device *net)
  {
        struct eth_dev          *dev = netdev_priv(net);
-       int                     length = skb->len;
+       int                     length = 0;
        int                     retval;
        struct usb_request      *req = NULL;
        unsigned long           flags;
        }
        spin_unlock_irqrestore(&dev->lock, flags);
  
-       if (!in) {
+       if (skb && !in) {
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
  
        /* apply outgoing CDC or RNDIS filters */
-       if (!is_promisc(cdc_filter)) {
+       if (skb && !is_promisc(cdc_filter)) {
                u8              *dest = skb->data;
  
                if (is_multicast_ether_addr(dest)) {
                if (dev->port_usb)
                        skb = dev->wrap(dev->port_usb, skb);
                spin_unlock_irqrestore(&dev->lock, flags);
-               if (!skb)
+               if (!skb) {
+                       /* Multi frame CDC protocols may store the frame for
+                        * later which is not a dropped frame.
+                        */
+                       if (dev->port_usb->supports_multi_frame)
+                               goto multiframe;
                        goto drop;
-               length = skb->len;
+               }
        }
+       length = skb->len;
        req->buf = skb->data;
        req->context = skb;
        req->complete = tx_complete;
                dev_kfree_skb_any(skb);
  drop:
                dev->net->stats.tx_dropped++;
+ multiframe:
                spin_lock_irqsave(&dev->req_lock, flags);
                if (list_empty(&dev->tx_reqs))
                        netif_start_queue(net);
@@@ -1120,10 -1127,7 +1127,10 @@@ void gether_disconnect(struct gether *l
  
        DBG(dev, "%s\n", __func__);
  
 +      netif_tx_lock(dev->net);
        netif_stop_queue(dev->net);
 +      netif_tx_unlock(dev->net);
 +
        netif_carrier_off(dev->net);
  
        /* disable endpoints, forcing (synchronous) completion
index 2e4ce7704908bc78e4ed2385842a1e6dbec1d59c,ee6c16416c300121aad92cca9479fb0613b96af9..2e4ce7704908bc78e4ed2385842a1e6dbec1d59c
@@@ -1264,13 -1264,8 +1264,13 @@@ dev_release (struct inode *inode, struc
  
        kfree (dev->buf);
        dev->buf = NULL;
 -      put_dev (dev);
  
 +      /* other endpoints were all decoupled from this device */
 +      spin_lock_irq(&dev->lock);
 +      dev->state = STATE_DEV_DISABLED;
 +      spin_unlock_irq(&dev->lock);
 +
 +      put_dev (dev);
        return 0;
  }
  
index c7004ee89c90d17eaded6f653a93acbf2af96aa6,5d93f2b1e394b355ebbe93caf9ab5e103acf77bd..08df5c4f46ce4137f91a2c86727765850924c7b2
@@@ -1532,9 -1532,8 +1532,9 @@@ static int gr_ep_enable(struct usb_ep *
                        "%s mode: multiple trans./microframe not valid\n",
                        (mode == 2 ? "Bulk" : "Control"));
                return -EINVAL;
 -      } else if (nt == 0x11) {
 -              dev_err(dev->dev, "Invalid value for trans./microframe\n");
 +      } else if (nt == 0x3) {
 +              dev_err(dev->dev,
 +                      "Invalid value 0x3 for additional trans./microframe\n");
                return -EINVAL;
        } else if ((nt + 1) * max > buffer_size) {
                dev_err(dev->dev, "Hw buffer size %d < max payload %d * %d\n",
@@@ -2213,7 -2212,7 +2213,7 @@@ out
        return retval;
  }
  
- static struct of_device_id gr_match[] = {
+ static const struct of_device_id gr_match[] = {
        {.name = "GAISLER_USBDC"},
        {.name = "01_021"},
        {},
index 040fb169b162a1e381180bc92ab408bc9268170f,fcff3a571b45da76ff466bcb76bbe219d9d25e53..040fb169b162a1e381180bc92ab408bc9268170f
@@@ -332,7 -332,7 +332,7 @@@ static int queue_dtd(struct mv_ep *ep, 
        /* clear active and halt bit, in case set from a previous error */
        dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
  
 -      /* Ensure that updates to the QH will occure before priming. */
 +      /* Ensure that updates to the QH will occur before priming. */
        wmb();
  
        /* Prime the Endpoint */
@@@ -1656,7 -1656,7 +1656,7 @@@ static void handle_setup_packet(struct 
        dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
                        setup->bRequestType, setup->bRequest,
                        setup->wValue, setup->wIndex, setup->wLength);
 -      /* We process some stardard setup requests here */
 +      /* We process some standard setup requests here */
        if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
                switch (setup->bRequest) {
                case USB_REQ_GET_STATUS:
index 5341bb223b7cbab3b4465fed5ad83e7a4825b360,adfffe8848911e5c6a5013ba3a7589f8ef99c4e1..47ae6455d0733c2d3ef4093aa4408e98969b3644
@@@ -39,7 -39,6 +39,6 @@@ struct cppi41_dma_channel 
        u32 transferred;
        u32 packet_sz;
        struct list_head tx_check;
-       struct work_struct dma_completion;
  };
  
  #define MUSB_DMA_NUM_CHANNELS 15
@@@ -74,15 -73,18 +73,18 @@@ static void save_rx_toggle(struct cppi4
  
  static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
  {
+       struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+       struct musb *musb = hw_ep->musb;
        u16 csr;
        u8 toggle;
  
        if (cppi41_channel->is_tx)
                return;
-       if (!is_host_active(cppi41_channel->controller->musb))
+       if (!is_host_active(musb))
                return;
  
-       csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+       musb_ep_select(musb->mregs, hw_ep->epnum);
+       csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
        toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
  
        /*
@@@ -107,24 -109,13 +109,13 @@@ static bool musb_is_tx_fifo_empty(struc
        void __iomem    *epio = musb->endpoints[epnum].regs;
        u16             csr;
  
+       musb_ep_select(musb->mregs, hw_ep->epnum);
        csr = musb_readw(epio, MUSB_TXCSR);
        if (csr & MUSB_TXCSR_TXPKTRDY)
                return false;
        return true;
  }
  
- static bool is_isoc(struct musb_hw_ep *hw_ep, bool in)
- {
-       if (in && hw_ep->in_qh) {
-               if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC)
-                       return true;
-       } else if (hw_ep->out_qh) {
-               if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC)
-                       return true;
-       }
-       return false;
- }
  static void cppi41_dma_callback(void *private_data);
  
  static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
                cppi41_channel->channel.actual_len =
                        cppi41_channel->transferred;
                cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+               cppi41_channel->channel.rx_packet_done = true;
                musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
        } else {
                /* next iteration, reload */
                dma_async_issue_pending(dc);
  
                if (!cppi41_channel->is_tx) {
+                       musb_ep_select(musb->mregs, hw_ep->epnum);
                        csr = musb_readw(epio, MUSB_RXCSR);
                        csr |= MUSB_RXCSR_H_REQPKT;
                        musb_writew(epio, MUSB_RXCSR, csr);
        }
  }
  
- static void cppi_trans_done_work(struct work_struct *work)
- {
-       unsigned long flags;
-       struct cppi41_dma_channel *cppi41_channel =
-               container_of(work, struct cppi41_dma_channel, dma_completion);
-       struct cppi41_dma_controller *controller = cppi41_channel->controller;
-       struct musb *musb = controller->musb;
-       struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
-       bool empty;
-       if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) {
-               spin_lock_irqsave(&musb->lock, flags);
-               cppi41_trans_done(cppi41_channel);
-               spin_unlock_irqrestore(&musb->lock, flags);
-       } else {
-               empty = musb_is_tx_fifo_empty(hw_ep);
-               if (empty) {
-                       spin_lock_irqsave(&musb->lock, flags);
-                       cppi41_trans_done(cppi41_channel);
-                       spin_unlock_irqrestore(&musb->lock, flags);
-               } else {
-                       schedule_work(&cppi41_channel->dma_completion);
-               }
-       }
- }
  static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
  {
        struct cppi41_dma_controller *controller;
        if (!list_empty(&controller->early_tx_list)) {
                ret = HRTIMER_RESTART;
                hrtimer_forward_now(&controller->early_tx,
-                               ktime_set(0, 150 * NSEC_PER_USEC));
+                               ktime_set(0, 50 * NSEC_PER_USEC));
        }
  
        spin_unlock_irqrestore(&musb->lock, flags);
@@@ -268,14 -235,6 +235,6 @@@ static void cppi41_dma_callback(void *p
                        transferred < cppi41_channel->packet_sz)
                cppi41_channel->prog_len = 0;
  
-       if (!cppi41_channel->is_tx) {
-               if (is_isoc(hw_ep, 1))
-                       schedule_work(&cppi41_channel->dma_completion);
-               else
-                       cppi41_trans_done(cppi41_channel);
-               goto out;
-       }
        empty = musb_is_tx_fifo_empty(hw_ep);
        if (empty) {
                cppi41_trans_done(cppi41_channel);
                                goto out;
                        }
                }
-               if (is_isoc(hw_ep, 0)) {
-                       schedule_work(&cppi41_channel->dma_completion);
-                       goto out;
-               }
                list_add_tail(&cppi41_channel->tx_check,
                                &controller->early_tx_list);
 -              if (!hrtimer_active(&controller->early_tx)) {
 +              if (!hrtimer_is_queued(&controller->early_tx)) {
+                       unsigned long usecs = cppi41_channel->total_len / 10;
                        hrtimer_start_range_ns(&controller->early_tx,
-                               ktime_set(0, 140 * NSEC_PER_USEC),
+                               ktime_set(0, usecs * NSEC_PER_USEC),
                                40 * NSEC_PER_USEC,
                                HRTIMER_MODE_REL);
                }
@@@ -450,6 -407,7 +407,7 @@@ static bool cppi41_configure_channel(st
        dma_desc->callback = cppi41_dma_callback;
        dma_desc->callback_param = channel;
        cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+       cppi41_channel->channel.rx_packet_done = false;
  
        save_rx_toggle(cppi41_channel);
        dma_async_issue_pending(dc);
@@@ -672,8 -630,6 +630,6 @@@ static int cppi41_dma_controller_start(
                cppi41_channel->port_num = port;
                cppi41_channel->is_tx = is_tx;
                INIT_LIST_HEAD(&cppi41_channel->tx_check);
-               INIT_WORK(&cppi41_channel->dma_completion,
-                         cppi_trans_done_work);
  
                musb_dma = &cppi41_channel->channel;
                musb_dma->private_data = cppi41_channel;
index 09529f94e72d7771661c33e77c5b364cc6bdecf3,f119a62140efe9cd18fd44f9b1deef27e3b98b70..c791ba5da91a464128aa856bc9ab1a82b7e0626a
@@@ -56,16 -56,24 +56,24 @@@ static const struct of_device_id musb_d
   * dependent on musb core layer symbols.
   */
  static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
-       { return __raw_readb(addr + offset); }
+ {
+       return __raw_readb(addr + offset);
+ }
  
  static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
-       { return __raw_readl(addr + offset); }
+ {
+       return __raw_readl(addr + offset);
+ }
  
  static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
-       { __raw_writeb(data, addr + offset); }
+ {
+       __raw_writeb(data, addr + offset);
+ }
  
  static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
-       { __raw_writel(data, addr + offset); }
+ {
+       __raw_writel(data, addr + offset);
+ }
  
  /**
   * DSPS musb wrapper register offset.
@@@ -136,6 -144,7 +144,7 @@@ struct dsps_glue 
        const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
        struct timer_list timer;        /* otg_workaround timer */
        unsigned long last_timer;    /* last timer data for each instance */
+       bool sw_babble_enabled;
  
        struct dsps_context context;
        struct debugfs_regset32 regset;
@@@ -469,6 -478,19 +478,19 @@@ static int dsps_musb_init(struct musb *
        val &= ~(1 << wrp->otg_disable);
        dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
  
+       /*
+        *  Check whether the dsps version has babble control enabled.
+        * In latest silicon revision the babble control logic is enabled.
+        * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
+        * logic enabled.
+        */
+       val = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+       if (val == MUSB_BABBLE_RCV_DISABLE) {
+               glue->sw_babble_enabled = true;
+               val |= MUSB_BABBLE_SW_SESSION_CTRL;
+               dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
+       }
        ret = dsps_musb_dbg_init(musb, glue);
        if (ret)
                return ret;
@@@ -494,9 -516,10 +516,9 @@@ static int dsps_musb_set_mode(struct mu
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
        void __iomem *ctrl_base = musb->ctrl_base;
 -      void __iomem *base = musb->mregs;
        u32 reg;
  
 -      reg = dsps_readl(base, wrp->mode);
 +      reg = dsps_readl(ctrl_base, wrp->mode);
  
        switch (mode) {
        case MUSB_HOST:
                 */
                reg |= (1 << wrp->iddig_mux);
  
 -              dsps_writel(base, wrp->mode, reg);
 +              dsps_writel(ctrl_base, wrp->mode, reg);
                dsps_writel(ctrl_base, wrp->phy_utmi, 0x02);
                break;
        case MUSB_PERIPHERAL:
                 */
                reg |= (1 << wrp->iddig_mux);
  
 -              dsps_writel(base, wrp->mode, reg);
 +              dsps_writel(ctrl_base, wrp->mode, reg);
                break;
        case MUSB_OTG:
 -              dsps_writel(base, wrp->phy_utmi, 0x02);
 +              dsps_writel(ctrl_base, wrp->phy_utmi, 0x02);
                break;
        default:
                dev_err(glue->dev, "unsupported mode %d\n", mode);
        return 0;
  }
  
- static void dsps_musb_reset(struct musb *musb)
+ static bool  sw_babble_control(struct musb *musb)
+ {
+       u8 babble_ctl;
+       bool session_restart =  false;
+       babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+       dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n",
+               babble_ctl);
+       /*
+        * check line monitor flag to check whether babble is
+        * due to noise
+        */
+       dev_dbg(musb->controller, "STUCK_J is %s\n",
+               babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset");
+       if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+               int timeout = 10;
+               /*
+                * babble is due to noise, then set transmit idle (d7 bit)
+                * to resume normal operation
+                */
+               babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+               babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE;
+               dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl);
+               /* wait till line monitor flag cleared */
+               dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n");
+               do {
+                       babble_ctl = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
+                       udelay(1);
+               } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--);
+               /* check whether stuck_at_j bit cleared */
+               if (babble_ctl & MUSB_BABBLE_STUCK_J) {
+                       /*
+                        * real babble condition has occurred
+                        * restart the controller to start the
+                        * session again
+                        */
+                       dev_dbg(musb->controller, "J not cleared, misc (%x)\n",
+                               babble_ctl);
+                       session_restart = true;
+               }
+       } else {
+               session_restart = true;
+       }
+       return session_restart;
+ }
+ static int dsps_musb_reset(struct musb *musb)
  {
        struct device *dev = musb->controller;
        struct dsps_glue *glue = dev_get_drvdata(dev->parent);
        const struct dsps_musb_wrapper *wrp = glue->wrp;
+       int session_restart = 0;
+       if (glue->sw_babble_enabled)
+               session_restart = sw_babble_control(musb);
+       /*
+        * In case of new silicon version babble condition can be recovered
+        * without resetting the MUSB. But for older silicon versions, MUSB
+        * reset is needed
+        */
+       if (session_restart || !glue->sw_babble_enabled) {
+               dev_info(musb->controller, "Restarting MUSB to recover from Babble\n");
+               dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
+               usleep_range(100, 200);
+               usb_phy_shutdown(musb->xceiv);
+               usleep_range(100, 200);
+               usb_phy_init(musb->xceiv);
+               session_restart = 1;
+       }
  
-       dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset));
-       udelay(100);
+       return !session_restart;
  }
  
  static struct musb_platform_ops dsps_ops = {
diff --combined drivers/usb/musb/ux500.c
index f202e50884615cb50fb9259f43cbc54099d403a8,f18c03795ed55f131b2636aaf2e581be80fcbb73..dc666e96f45f4ee553ee2e1071613c7e6870a2b9
@@@ -246,7 -246,7 +246,7 @@@ static int ux500_probe(struct platform_
                }
        }
  
-       glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+       glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&pdev->dev, "failed to allocate glue context\n");
                goto err0;
        musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
        if (!musb) {
                dev_err(&pdev->dev, "failed to allocate musb device\n");
-               goto err1;
+               goto err0;
        }
  
-       clk = clk_get(&pdev->dev, NULL);
+       clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "failed to get clock\n");
                ret = PTR_ERR(clk);
-               goto err3;
+               goto err1;
        }
  
        ret = clk_prepare_enable(clk);
        if (ret) {
                dev_err(&pdev->dev, "failed to enable clock\n");
-               goto err4;
+               goto err1;
        }
  
        musb->dev.parent                = &pdev->dev;
        musb->dev.dma_mask              = &pdev->dev.coherent_dma_mask;
        musb->dev.coherent_dma_mask     = pdev->dev.coherent_dma_mask;
 -      musb->dev.of_node               = pdev->dev.of_node;
  
        glue->dev                       = &pdev->dev;
        glue->musb                      = musb;
                        ARRAY_SIZE(musb_resources));
        if (ret) {
                dev_err(&pdev->dev, "failed to add resources\n");
-               goto err5;
+               goto err2;
        }
  
        ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
        if (ret) {
                dev_err(&pdev->dev, "failed to add platform_data\n");
-               goto err5;
+               goto err2;
        }
  
        ret = platform_device_add(musb);
        if (ret) {
                dev_err(&pdev->dev, "failed to register musb device\n");
-               goto err5;
+               goto err2;
        }
  
        return 0;
  
- err5:
+ err2:
        clk_disable_unprepare(clk);
  
- err4:
-       clk_put(clk);
- err3:
-       platform_device_put(musb);
  err1:
-       kfree(glue);
+       platform_device_put(musb);
  
  err0:
        return ret;
@@@ -340,8 -335,6 +334,6 @@@ static int ux500_remove(struct platform
  
        platform_device_unregister(glue->musb);
        clk_disable_unprepare(glue->clk);
-       clk_put(glue->clk);
-       kfree(glue);
  
        return 0;
  }
index c929370cdaa64454201d7b2a1884f0d88f3c87a8,d1f5da5b8d1bb1f31b5cc57fa5b39ab70280d95c..e4108eec5ef4153c7370f405040618cd1df41114
@@@ -279,11 -279,11 +279,11 @@@ static int msm_otg_link_clk_reset(struc
  
  static int msm_otg_phy_clk_reset(struct msm_otg *motg)
  {
-       int ret;
+       int ret = 0;
  
-       if (motg->pdata->phy_clk_reset)
+       if (motg->pdata->phy_clk_reset && motg->phy_reset_clk)
                ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk);
-       else
+       else if (motg->phy_rst)
                ret = reset_control_reset(motg->phy_rst);
  
        if (ret)
@@@ -1229,9 -1229,7 +1229,9 @@@ static void msm_otg_sm_work(struct work
                        motg->chg_state = USB_CHG_STATE_UNDEFINED;
                        motg->chg_type = USB_INVALID_CHARGER;
                }
 -              pm_runtime_put_sync(otg->phy->dev);
 +
 +              if (otg->phy->state == OTG_STATE_B_IDLE)
 +                      pm_runtime_put_sync(otg->phy->dev);
                break;
        case OTG_STATE_B_PERIPHERAL:
                dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
@@@ -1429,7 -1427,7 +1429,7 @@@ static void msm_otg_debugfs_cleanup(voi
        debugfs_remove(msm_otg_dbg_root);
  }
  
- static struct of_device_id msm_otg_dt_match[] = {
+ static const struct of_device_id msm_otg_dt_match[] = {
        {
                .compatible = "qcom,usb-otg-ci",
                .data = (void *) CI_45NM_INTEGRATED_PHY
@@@ -1466,7 -1464,7 +1466,7 @@@ static int msm_otg_read_dt(struct platf
  
        motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy");
        if (IS_ERR(motg->phy_rst))
-               return PTR_ERR(motg->phy_rst);
+               motg->phy_rst = NULL;
  
        pdata->mode = of_usb_get_dr_mode(node);
        if (pdata->mode == USB_DR_MODE_UNKNOWN)
@@@ -1558,7 -1556,7 +1558,7 @@@ static int msm_otg_probe(struct platfor
                                           np ? "phy" : "usb_phy_clk");
        if (IS_ERR(motg->phy_reset_clk)) {
                dev_err(&pdev->dev, "failed to get usb_phy_clk\n");
-               return PTR_ERR(motg->phy_reset_clk);
+               motg->phy_reset_clk = NULL;
        }
  
        motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");
index 50dc69e1666f2d2fedf8a76c7e7e3f8ebee5a6a5,cd9d25e804b2a3819b88f9d05ce2bffee6585286..13b4fa287da8aff05739a657fb9c24b3f5541ea7
@@@ -685,8 -685,10 +685,8 @@@ static int ulpi_phy_power_off(struct te
        return gpio_direction_output(phy->reset_gpio, 0);
  }
  
 -static void tegra_usb_phy_close(struct usb_phy *x)
 +static void tegra_usb_phy_close(struct tegra_usb_phy *phy)
  {
 -      struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
 -
        if (!IS_ERR(phy->vbus))
                regulator_disable(phy->vbus);
  
@@@ -962,7 -964,7 +962,7 @@@ static const struct tegra_phy_soc_confi
        .requires_extra_tuning_parameters = true,
  };
  
- static struct of_device_id tegra_usb_phy_id_table[] = {
+ static const struct of_device_id tegra_usb_phy_id_table[] = {
        { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
        { .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
        { },
@@@ -1058,13 -1060,14 +1058,13 @@@ static int tegra_usb_phy_probe(struct p
        if (err < 0)
                return err;
  
 -      tegra_phy->u_phy.shutdown = tegra_usb_phy_close;
        tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
  
        platform_set_drvdata(pdev, tegra_phy);
  
        err = usb_add_phy_dev(&tegra_phy->u_phy);
        if (err < 0) {
 -              tegra_usb_phy_close(&tegra_phy->u_phy);
 +              tegra_usb_phy_close(tegra_phy);
                return err;
        }
  
@@@ -1076,7 -1079,6 +1076,7 @@@ static int tegra_usb_phy_remove(struct 
        struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
  
        usb_remove_phy(&tegra_phy->u_phy);
 +      tegra_usb_phy_close(tegra_phy);
  
        return 0;
  }
index 24b68c59dcf85363b3bad8853392ae8a51112025,b66fae77c08cf5059e31c1fdfea20ecff5051608..0154b2859fd7dd868a65dcb30bc6455594e23b65
@@@ -18,10 -18,9 +18,9 @@@ enum functionfs_flags 
        FUNCTIONFS_HAS_FS_DESC = 1,
        FUNCTIONFS_HAS_HS_DESC = 2,
        FUNCTIONFS_HAS_SS_DESC = 4,
+       FUNCTIONFS_HAS_MS_OS_DESC = 8,
  };
  
- #ifndef __KERNEL__
  /* Descriptor of an non-audio endpoint */
  struct usb_endpoint_descriptor_no_audio {
        __u8  bLength;
        __u8  bInterval;
  } __attribute__((packed));
  
 +/* Legacy format, deprecated as of 3.14. */
 +struct usb_functionfs_descs_head {
 +      __le32 magic;
 +      __le32 length;
 +      __le32 fs_count;
 +      __le32 hs_count;
 +} __attribute__((packed, deprecated));
 +
+ /* MS OS Descriptor header */
+ struct usb_os_desc_header {
+       __u8    interface;
+       __le32  dwLength;
+       __le16  bcdVersion;
+       __le16  wIndex;
+       union {
+               struct {
+                       __u8    bCount;
+                       __u8    Reserved;
+               };
+               __le16  wCount;
+       };
+ } __attribute__((packed));
+ struct usb_ext_compat_desc {
+       __u8    bFirstInterfaceNumber;
+       __u8    Reserved1;
+       __u8    CompatibleID[8];
+       __u8    SubCompatibleID[8];
+       __u8    Reserved2[6];
+ };
+ struct usb_ext_prop_desc {
+       __le32  dwSize;
+       __le32  dwPropertyDataType;
+       __le16  wPropertyNameLength;
+ } __attribute__((packed));
+ #ifndef __KERNEL__
  /*
   * Descriptors format:
   *
   * |     | fs_count  | LE32         | number of full-speed descriptors     |
   * |     | hs_count  | LE32         | number of high-speed descriptors     |
   * |     | ss_count  | LE32         | number of super-speed descriptors    |
+  * |     | os_count  | LE32         | number of MS OS descriptors          |
   * |     | fs_descrs | Descriptor[] | list of full-speed descriptors       |
   * |     | hs_descrs | Descriptor[] | list of high-speed descriptors       |
   * |     | ss_descrs | Descriptor[] | list of super-speed descriptors      |
+  * |     | os_descrs | OSDesc[]     | list of MS OS descriptors            |
   *
   * Depending on which flags are set, various fields may be missing in the
   * structure.  Any flags that are not recognised cause the whole block to be
   * |   0 | bLength         | U8   | length of the descriptor |
   * |   1 | bDescriptorType | U8   | descriptor type          |
   * |   2 | payload         |      | descriptor's payload     |
+  *
+  * OSDesc[] is an array of valid MS OS Feature Descriptors which have one of
+  * the following formats:
+  *
+  * | off | name            | type | description              |
+  * |-----+-----------------+------+--------------------------|
+  * |   0 | inteface        | U8   | related interface number |
+  * |   1 | dwLength        | U32  | length of the descriptor |
+  * |   5 | bcdVersion      | U16  | currently supported: 1   |
+  * |   7 | wIndex          | U16  | currently supported: 4   |
+  * |   9 | bCount          | U8   | number of ext. compat.   |
+  * |  10 | Reserved        | U8   | 0                        |
+  * |  11 | ExtCompat[]     |      | list of ext. compat. d.  |
+  *
+  * | off | name            | type | description              |
+  * |-----+-----------------+------+--------------------------|
+  * |   0 | inteface        | U8   | related interface number |
+  * |   1 | dwLength        | U32  | length of the descriptor |
+  * |   5 | bcdVersion      | U16  | currently supported: 1   |
+  * |   7 | wIndex          | U16  | currently supported: 5   |
+  * |   9 | wCount          | U16  | number of ext. compat.   |
+  * |  11 | ExtProp[]       |      | list of ext. prop. d.    |
+  *
+  * ExtCompat[] is an array of valid Extended Compatiblity descriptors
+  * which have the following format:
+  *
+  * | off | name                  | type | description                         |
+  * |-----+-----------------------+------+-------------------------------------|
+  * |   0 | bFirstInterfaceNumber | U8   | index of the interface or of the 1st|
+  * |     |                       |      | interface in an IAD group           |
+  * |   1 | Reserved              | U8   | 0                                   |
+  * |   2 | CompatibleID          | U8[8]| compatible ID string                |
+  * |  10 | SubCompatibleID       | U8[8]| subcompatible ID string             |
+  * |  18 | Reserved              | U8[6]| 0                                   |
+  *
+  * ExtProp[] is an array of valid Extended Properties descriptors
+  * which have the following format:
+  *
+  * | off | name                  | type | description                         |
+  * |-----+-----------------------+------+-------------------------------------|
+  * |   0 | dwSize                | U32  | length of the descriptor            |
+  * |   4 | dwPropertyDataType    | U32  | 1..7                                |
+  * |   8 | wPropertyNameLength   | U16  | bPropertyName length (NL)           |
+  * |  10 | bPropertyName         |U8[NL]| name of this property               |
+  * |10+NL| dwPropertyDataLength  | U32  | bPropertyData length (DL)           |
+  * |14+NL| bProperty             |U8[DL]| payload of this property            |
   */
  
  struct usb_functionfs_strings_head {