]> Git Repo - linux.git/commitdiff
Merge 4.9-rc7 into usb-next
authorGreg Kroah-Hartman <[email protected]>
Mon, 28 Nov 2016 07:34:10 +0000 (08:34 +0100)
committerGreg Kroah-Hartman <[email protected]>
Mon, 28 Nov 2016 07:34:10 +0000 (08:34 +0100)
We want the USB fixes in here as well.

Signed-off-by: Greg Kroah-Hartman <[email protected]>
1  2 
drivers/usb/chipidea/udc.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/omap2430.c

index a7b383dc3d07156438f0599c2f52d68b143c0482,c9e80ad48fdcdb0912271a336600167ff91d7276..f5320d66019a1836dfcfd30b90d8b690a081d7c0
@@@ -821,7 -821,7 +821,7 @@@ static int _ep_queue(struct usb_ep *ep
        }
  
        if (usb_endpoint_xfer_isoc(hwep->ep.desc) &&
 -          hwreq->req.length > (1 + hwep->ep.mult) * hwep->ep.maxpacket) {
 +          hwreq->req.length > hwep->ep.mult * hwep->ep.maxpacket) {
                dev_err(hwep->ci->dev, "request length too big for isochronous\n");
                return -EMSGSIZE;
        }
@@@ -1253,8 -1253,8 +1253,8 @@@ static int ep_enable(struct usb_ep *ep
        hwep->num  = usb_endpoint_num(desc);
        hwep->type = usb_endpoint_type(desc);
  
 -      hwep->ep.maxpacket = usb_endpoint_maxp(desc) & 0x07ff;
 -      hwep->ep.mult = QH_ISO_MULT(usb_endpoint_maxp(desc));
 +      hwep->ep.maxpacket = usb_endpoint_maxp(desc);
 +      hwep->ep.mult = usb_endpoint_maxp_mult(desc);
  
        if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
                cap |= QH_IOS;
@@@ -1889,8 -1889,6 +1889,6 @@@ static int udc_start(struct ci_hdrc *ci
        struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
        int retval = 0;
  
-       spin_lock_init(&ci->lock);
        ci->gadget.ops          = &usb_gadget_ops;
        ci->gadget.speed        = USB_SPEED_UNKNOWN;
        ci->gadget.max_speed    = USB_SPEED_HIGH;
index dff72a8732974f9f6ca9be457689a2a87a77e084,17989b72cdaec18dbf55d0709897fc75d1842ab7..0780d8311ec648bf3ac703bb79deb0f9abda5601
@@@ -266,7 -266,7 +266,7 @@@ static void ffs_ep0_complete(struct usb
  {
        struct ffs_data *ffs = req->context;
  
 -      complete_all(&ffs->ep0req_completion);
 +      complete(&ffs->ep0req_completion);
  }
  
  static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
@@@ -3225,11 -3225,11 +3225,11 @@@ static bool ffs_func_req_match(struct u
  
        switch (creq->bRequestType & USB_RECIP_MASK) {
        case USB_RECIP_INTERFACE:
-               return ffs_func_revmap_intf(func,
-                                           le16_to_cpu(creq->wIndex) >= 0);
+               return (ffs_func_revmap_intf(func,
+                                            le16_to_cpu(creq->wIndex)) >= 0);
        case USB_RECIP_ENDPOINT:
-               return ffs_func_revmap_ep(func,
-                                         le16_to_cpu(creq->wIndex) >= 0);
+               return (ffs_func_revmap_ep(func,
+                                          le16_to_cpu(creq->wIndex)) >= 0);
        default:
                return (bool) (func->ffs->user_flags &
                               FUNCTIONFS_ALL_CTRL_RECIP);
index a109f22fefcd14a3caf499abfe6087b49c999c1f,c3e172e15ec3d9d9ec7346b972b2702fed710c65..9e226468a13eb07af0bf5a6407d81cd304436369
  #include <linux/io.h>
  #include <linux/dma-mapping.h>
  #include <linux/usb.h>
 +#include <linux/usb/of.h>
  
  #include "musb_core.h"
  #include "musb_trace.h"
@@@ -131,24 -130,6 +131,24 @@@ static inline struct musb *dev_to_musb(
        return dev_get_drvdata(dev);
  }
  
 +enum musb_mode musb_get_mode(struct device *dev)
 +{
 +      enum usb_dr_mode mode;
 +
 +      mode = usb_get_dr_mode(dev);
 +      switch (mode) {
 +      case USB_DR_MODE_HOST:
 +              return MUSB_HOST;
 +      case USB_DR_MODE_PERIPHERAL:
 +              return MUSB_PERIPHERAL;
 +      case USB_DR_MODE_OTG:
 +      case USB_DR_MODE_UNKNOWN:
 +      default:
 +              return MUSB_OTG;
 +      }
 +}
 +EXPORT_SYMBOL_GPL(musb_get_mode);
 +
  /*-------------------------------------------------------------------------*/
  
  #ifndef CONFIG_BLACKFIN
@@@ -588,7 -569,10 +588,7 @@@ static irqreturn_t musb_stage0_irq(stru
                if (devctl & MUSB_DEVCTL_HM) {
                        switch (musb->xceiv->otg->state) {
                        case OTG_STATE_A_SUSPEND:
 -                              /* remote wakeup?  later, GetPortStatus
 -                               * will stop RESUME signaling
 -                               */
 -
 +                              /* remote wakeup? */
                                musb->port1_status |=
                                                (USB_PORT_STAT_C_SUSPEND << 16)
                                                | MUSB_PORT_STAT_RESUME;
@@@ -1002,7 -986,7 +1002,7 @@@ b_host
        }
  #endif
  
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
  
        return handled;
  }
@@@ -1871,14 -1855,23 +1871,23 @@@ static void musb_pm_runtime_check_sessi
                MUSB_DEVCTL_HR;
        switch (devctl & ~s) {
        case MUSB_QUIRK_B_INVALID_VBUS_91:
-               if (!musb->session && !musb->quirk_invalid_vbus) {
-                       musb->quirk_invalid_vbus = true;
+               if (musb->quirk_retries--) {
                        musb_dbg(musb,
-                                "First invalid vbus, assume no session");
+                                "Poll devctl on invalid vbus, assume no session");
+                       schedule_delayed_work(&musb->irq_work,
+                                             msecs_to_jiffies(1000));
                        return;
                }
-               break;
        case MUSB_QUIRK_A_DISCONNECT_19:
+               if (musb->quirk_retries--) {
+                       musb_dbg(musb,
+                                "Poll devctl on possible host mode disconnect");
+                       schedule_delayed_work(&musb->irq_work,
+                                             msecs_to_jiffies(1000));
+                       return;
+               }
                if (!musb->session)
                        break;
                musb_dbg(musb, "Allow PM on possible host mode disconnect");
                if (error < 0)
                        dev_err(musb->controller, "Could not enable: %i\n",
                                error);
+               musb->quirk_retries = 3;
        } else {
                musb_dbg(musb, "Allow PM with no session: %02x", devctl);
-               musb->quirk_invalid_vbus = false;
                pm_runtime_mark_last_busy(musb->controller);
                pm_runtime_put_autosuspend(musb->controller);
        }
  /* Only used to provide driver mode change events */
  static void musb_irq_work(struct work_struct *data)
  {
-       struct musb *musb = container_of(data, struct musb, irq_work);
+       struct musb *musb = container_of(data, struct musb, irq_work.work);
  
        musb_pm_runtime_check_session(musb);
  
@@@ -1985,6 -1978,7 +1994,7 @@@ static struct musb *allocate_instance(s
        INIT_LIST_HEAD(&musb->control);
        INIT_LIST_HEAD(&musb->in_bulk);
        INIT_LIST_HEAD(&musb->out_bulk);
+       INIT_LIST_HEAD(&musb->pending_list);
  
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
        musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@@ -2034,6 -2028,84 +2044,84 @@@ static void musb_free(struct musb *musb
        musb_host_free(musb);
  }
  
+ struct musb_pending_work {
+       int (*callback)(struct musb *musb, void *data);
+       void *data;
+       struct list_head node;
+ };
+ /*
+  * Called from musb_runtime_resume(), musb_resume(), and
+  * musb_queue_resume_work(). Callers must take musb->lock.
+  */
+ static int musb_run_resume_work(struct musb *musb)
+ {
+       struct musb_pending_work *w, *_w;
+       unsigned long flags;
+       int error = 0;
+       spin_lock_irqsave(&musb->list_lock, flags);
+       list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
+               if (w->callback) {
+                       error = w->callback(musb, w->data);
+                       if (error < 0) {
+                               dev_err(musb->controller,
+                                       "resume callback %p failed: %i\n",
+                                       w->callback, error);
+                       }
+               }
+               list_del(&w->node);
+               devm_kfree(musb->controller, w);
+       }
+       spin_unlock_irqrestore(&musb->list_lock, flags);
+       return error;
+ }
+ /*
+  * Called to run work if device is active or else queue the work to happen
+  * on resume. Caller must take musb->lock and must hold an RPM reference.
+  *
+  * Note that we cowardly refuse queuing work after musb PM runtime
+  * resume is done calling musb_run_resume_work() and return -EINPROGRESS
+  * instead.
+  */
+ int musb_queue_resume_work(struct musb *musb,
+                          int (*callback)(struct musb *musb, void *data),
+                          void *data)
+ {
+       struct musb_pending_work *w;
+       unsigned long flags;
+       int error;
+       if (WARN_ON(!callback))
+               return -EINVAL;
+       if (pm_runtime_active(musb->controller))
+               return callback(musb, data);
+       w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
+       if (!w)
+               return -ENOMEM;
+       w->callback = callback;
+       w->data = data;
+       spin_lock_irqsave(&musb->list_lock, flags);
+       if (musb->is_runtime_suspended) {
+               list_add_tail(&w->node, &musb->pending_list);
+               error = 0;
+       } else {
+               dev_err(musb->controller, "could not add resume work %p\n",
+                       callback);
+               devm_kfree(musb->controller, w);
+               error = -EINPROGRESS;
+       }
+       spin_unlock_irqrestore(&musb->list_lock, flags);
+       return error;
+ }
+ EXPORT_SYMBOL_GPL(musb_queue_resume_work);
  static void musb_deassert_reset(struct work_struct *work)
  {
        struct musb *musb;
@@@ -2081,6 -2153,7 +2169,7 @@@ musb_init_controller(struct device *dev
        }
  
        spin_lock_init(&musb->lock);
+       spin_lock_init(&musb->list_lock);
        musb->board_set_power = plat->set_power;
        musb->min_power = plat->min_power;
        musb->ops = plat->platform_ops;
        musb_generic_disable(musb);
  
        /* Init IRQ workqueue before request_irq */
-       INIT_WORK(&musb->irq_work, musb_irq_work);
+       INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work);
        INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
        INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
  
        if (status)
                goto fail5;
  
+       musb->is_initialized = 1;
        pm_runtime_mark_last_busy(musb->controller);
        pm_runtime_put_autosuspend(musb->controller);
  
@@@ -2320,7 -2394,7 +2410,7 @@@ fail4
        musb_host_cleanup(musb);
  
  fail3:
-       cancel_work_sync(&musb->irq_work);
+       cancel_delayed_work_sync(&musb->irq_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        if (musb->dma_controller)
@@@ -2340,9 -2414,8 +2430,9 @@@ fail2
        musb_platform_exit(musb);
  
  fail1:
 -      dev_err(musb->controller,
 -              "musb_init_controller failed with status %d\n", status);
 +      if (status != -EPROBE_DEFER)
 +              dev_err(musb->controller,
 +                      "%s failed with status %d\n", __func__, status);
  
        musb_free(musb);
  
@@@ -2388,7 -2461,7 +2478,7 @@@ static int musb_remove(struct platform_
         */
        musb_exit_debugfs(musb);
  
-       cancel_work_sync(&musb->irq_work);
+       cancel_delayed_work_sync(&musb->irq_work);
        cancel_delayed_work_sync(&musb->finish_resume_work);
        cancel_delayed_work_sync(&musb->deassert_reset_work);
        pm_runtime_get_sync(musb->controller);
@@@ -2574,6 -2647,7 +2664,7 @@@ static int musb_suspend(struct device *
  
        musb_platform_disable(musb);
        musb_generic_disable(musb);
+       WARN_ON(!list_empty(&musb->pending_list));
  
        spin_lock_irqsave(&musb->lock, flags);
  
  
  static int musb_resume(struct device *dev)
  {
-       struct musb     *musb = dev_to_musb(dev);
-       u8              devctl;
-       u8              mask;
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int error;
+       u8 devctl;
+       u8 mask;
  
        /*
         * For static cmos like DaVinci, register values were preserved
  
        musb_start(musb);
  
+       spin_lock_irqsave(&musb->lock, flags);
+       error = musb_run_resume_work(musb);
+       if (error)
+               dev_err(musb->controller, "resume work failed with %i\n",
+                       error);
+       spin_unlock_irqrestore(&musb->lock, flags);
        return 0;
  }
  
@@@ -2639,14 -2722,16 +2739,16 @@@ static int musb_runtime_suspend(struct 
        struct musb     *musb = dev_to_musb(dev);
  
        musb_save_context(musb);
+       musb->is_runtime_suspended = 1;
  
        return 0;
  }
  
  static int musb_runtime_resume(struct device *dev)
  {
-       struct musb     *musb = dev_to_musb(dev);
-       static int      first = 1;
+       struct musb *musb = dev_to_musb(dev);
+       unsigned long flags;
+       int error;
  
        /*
         * When pm_runtime_get_sync called for the first time in driver
         * Also context restore without save does not make
         * any sense
         */
-       if (!first)
-               musb_restore_context(musb);
-       first = 0;
+       if (!musb->is_initialized)
+               return 0;
+       musb_restore_context(musb);
  
        if (musb->need_finish_resume) {
                musb->need_finish_resume = 0;
                                msecs_to_jiffies(USB_RESUME_TIMEOUT));
        }
  
+       spin_lock_irqsave(&musb->lock, flags);
+       error = musb_run_resume_work(musb);
+       if (error)
+               dev_err(musb->controller, "resume work failed with %i\n",
+                       error);
+       musb->is_runtime_suspended = 0;
+       spin_unlock_irqrestore(&musb->lock, flags);
        return 0;
  }
  
index 76f00f61b874ad8a978f53007fb9eb078ad420b0,91817d77d59c8ecd226e25fb6ce9e07b5a597d3f..a611e2f67bdc9e3233e4d6efde27d8ce18fe0a67
@@@ -303,13 -303,14 +303,14 @@@ struct musb_context_registers 
  struct musb {
        /* device lock */
        spinlock_t              lock;
+       spinlock_t              list_lock;      /* resume work list lock */
  
        struct musb_io          io;
        const struct musb_platform_ops *ops;
        struct musb_context_registers context;
  
        irqreturn_t             (*isr)(int, void *);
-       struct work_struct      irq_work;
+       struct delayed_work     irq_work;
        struct delayed_work     deassert_reset_work;
        struct delayed_work     finish_resume_work;
        struct delayed_work     gadget_work;
        struct list_head        control;        /* of musb_qh */
        struct list_head        in_bulk;        /* of musb_qh */
        struct list_head        out_bulk;       /* of musb_qh */
+       struct list_head        pending_list;   /* pending work list */
  
        struct timer_list       otg_timer;
        struct notifier_block   nb;
  
        int                     port_mode;      /* MUSB_PORT_MODE_* */
        bool                    session;
-       bool                    quirk_invalid_vbus;
+       unsigned long           quirk_retries;
        bool                    is_host;
  
        int                     a_wait_bcon;    /* VBUS timeout in msecs */
        unsigned long           idle_timeout;   /* Next timeout in jiffies */
  
+       unsigned                is_initialized:1;
+       unsigned                is_runtime_suspended:1;
        /* active means connected and not suspended */
        unsigned                is_active:1;
  
@@@ -540,6 -545,10 +545,10 @@@ extern irqreturn_t musb_interrupt(struc
  
  extern void musb_hnp_stop(struct musb *musb);
  
+ int musb_queue_resume_work(struct musb *musb,
+                          int (*callback)(struct musb *musb, void *data),
+                          void *data);
  static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
  {
        if (musb->ops->set_vbus)
@@@ -617,10 -626,4 +626,10 @@@ static inline void musb_platform_post_r
                musb->ops->post_root_reset_end(musb);
  }
  
 +/*
 + * gets the "dr_mode" property from DT and converts it into musb_mode
 + * if the property is not found or not recognized returns MUSB_OTG
 + */
 +extern enum musb_mode musb_get_mode(struct device *dev);
 +
  #endif        /* __MUSB_CORE_H__ */
index 47304560f105fb1c4ab2123f520b8a9e6a8a8583,a55173c9e5645d6f5245c0ff78c4ccf151d75107..1acc4864f9f6f0bf52cb5a084475fdab13bbab07
@@@ -974,8 -974,8 +974,8 @@@ static int musb_gadget_enable(struct us
                goto fail;
  
        /* REVISIT this rules out high bandwidth periodic transfers */
 -      tmp = usb_endpoint_maxp(desc);
 -      if (tmp & ~0x07ff) {
 +      tmp = usb_endpoint_maxp_mult(desc) - 1;
 +      if (tmp) {
                int ok;
  
                if (usb_endpoint_dir_in(desc))
                        musb_dbg(musb, "no support for high bandwidth ISO");
                        goto fail;
                }
 -              musb_ep->hb_mult = (tmp >> 11) & 3;
 +              musb_ep->hb_mult = tmp;
        } else {
                musb_ep->hb_mult = 0;
        }
  
 -      musb_ep->packet_sz = tmp & 0x7ff;
 +      musb_ep->packet_sz = usb_endpoint_maxp(desc);
        tmp = musb_ep->packet_sz * (musb_ep->hb_mult + 1);
  
        /* enable the interrupts for the endpoint, set the endpoint
                        musb_ep->dma ? "dma, " : "",
                        musb_ep->packet_sz);
  
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
  
  fail:
        spin_unlock_irqrestore(&musb->lock, flags);
@@@ -1158,7 -1158,7 +1158,7 @@@ static int musb_gadget_disable(struct u
        musb_ep->desc = NULL;
        musb_ep->end_point.desc = NULL;
  
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
  
        spin_unlock_irqrestore(&(musb->lock), flags);
  
@@@ -1222,13 -1222,22 +1222,22 @@@ void musb_ep_restart(struct musb *musb
                rxstate(musb, req);
  }
  
+ static int musb_ep_restart_resume_work(struct musb *musb, void *data)
+ {
+       struct musb_request *req = data;
+       musb_ep_restart(musb, req);
+       return 0;
+ }
  static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
                        gfp_t gfp_flags)
  {
        struct musb_ep          *musb_ep;
        struct musb_request     *request;
        struct musb             *musb;
-       int                     status = 0;
+       int                     status;
        unsigned long           lockflags;
  
        if (!ep || !req)
        if (request->ep != musb_ep)
                return -EINVAL;
  
+       status = pm_runtime_get(musb->controller);
+       if ((status != -EINPROGRESS) && status < 0) {
+               dev_err(musb->controller,
+                       "pm runtime get failed in %s\n",
+                       __func__);
+               pm_runtime_put_noidle(musb->controller);
+               return status;
+       }
+       status = 0;
        trace_musb_req_enq(request);
  
        /* request is mine now... */
  
        map_dma_buffer(request, musb, musb_ep);
  
-       pm_runtime_get_sync(musb->controller);
        spin_lock_irqsave(&musb->lock, lockflags);
  
        /* don't queue if the ep is down */
        list_add_tail(&request->list, &musb_ep->req_list);
  
        /* it this is the head of the queue, start i/o ... */
-       if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
-               musb_ep_restart(musb, request);
+       if (!musb_ep->busy && &request->list == musb_ep->req_list.next) {
+               status = musb_queue_resume_work(musb,
+                                               musb_ep_restart_resume_work,
+                                               request);
+               if (status < 0)
+                       dev_err(musb->controller, "%s resume work: %i\n",
+                               __func__, status);
+       }
  
  unlock:
        spin_unlock_irqrestore(&musb->lock, lockflags);
@@@ -1969,7 -1994,7 +1994,7 @@@ static int musb_gadget_stop(struct usb_
         */
  
        /* Force check of devctl register for PM runtime */
-       schedule_work(&musb->irq_work);
+       schedule_delayed_work(&musb->irq_work, 0);
  
        pm_runtime_mark_last_busy(musb->controller);
        pm_runtime_put_autosuspend(musb->controller);
index 7c9aa5e7866665f1bdb6f0449fcd3a4db31985e3,e8be8e39ab8fbd2d5b03a6fdc98dc3d78b00512e..8b73214a9ea3b41aa40848bb17c6f2c25397a457
@@@ -277,12 -277,12 +277,12 @@@ static int omap2430_musb_init(struct mu
                if (status == -ENXIO)
                        return status;
  
 -              pr_err("HS USB OTG: no transceiver configured\n");
 +              dev_dbg(dev, "HS USB OTG: no transceiver configured\n");
                return -EPROBE_DEFER;
        }
  
        if (IS_ERR(musb->phy)) {
 -              pr_err("HS USB OTG: no PHY configured\n");
 +              dev_err(dev, "HS USB OTG: no PHY configured\n");
                return PTR_ERR(musb->phy);
        }
        musb->isr = omap2430_musb_interrupt;
  
        musb_writel(musb->mregs, OTG_INTERFSEL, l);
  
 -      pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
 +      dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
                        "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
                        musb_readl(musb->mregs, OTG_REVISION),
                        musb_readl(musb->mregs, OTG_SYSCONFIG),
@@@ -513,17 -513,18 +513,18 @@@ static int omap2430_probe(struct platfo
        }
  
        pm_runtime_enable(glue->dev);
-       pm_runtime_use_autosuspend(glue->dev);
-       pm_runtime_set_autosuspend_delay(glue->dev, 100);
  
        ret = platform_device_add(musb);
        if (ret) {
                dev_err(&pdev->dev, "failed to register musb device\n");
-               goto err2;
+               goto err3;
        }
  
        return 0;
  
+ err3:
+       pm_runtime_disable(glue->dev);
  err2:
        platform_device_put(musb);
  
@@@ -535,10 -536,7 +536,7 @@@ static int omap2430_remove(struct platf
  {
        struct omap2430_glue *glue = platform_get_drvdata(pdev);
  
-       pm_runtime_get_sync(glue->dev);
        platform_device_unregister(glue->musb);
-       pm_runtime_put_sync(glue->dev);
-       pm_runtime_dont_use_autosuspend(glue->dev);
        pm_runtime_disable(glue->dev);
  
        return 0;
This page took 0.22333 seconds and 4 git commands to generate.