OSDN Git Service

usb: dwc3-msm: Queue resume_work unconditionally on pm_resume
authorAjay Agarwal <ajaya@codeaurora.org>
Tue, 31 Jul 2018 07:10:10 +0000 (12:40 +0530)
committerAjay Agarwal <ajaya@codeaurora.org>
Tue, 31 Jul 2018 07:17:12 +0000 (12:47 +0530)
Currently on pm_resume, the driver queues resume_work only if
vbus_active is true or id_state is false. So when the system is
suspended with host mode cable connected and the cable is
disconnected, the port still remains in host mode. Fix this by
unconditionally queueing resume_work from pm_resume and adding
required pm_relax in B_IDLE branch of sm_work.
Also create a freezable workqueue for sm_work so that the work
items do not race with pm_resume of child devices.

Change-Id: I9b79ddcc44c87111fc85086038361d9140be2af5
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
drivers/usb/dwc3/dwc3-msm.c

index de6bb29..95e27e0 100644 (file)
@@ -188,6 +188,7 @@ struct dwc3_msm {
        struct work_struct      restart_usb_work;
        bool                    in_restart;
        struct workqueue_struct *dwc3_wq;
+       struct workqueue_struct *sm_usb_wq;
        struct delayed_work     sm_work;
        unsigned long           inputs;
        unsigned                max_power;
@@ -1597,7 +1598,7 @@ static int msm_dwc3_usbdev_notify(struct notifier_block *self,
        }
 
        mdwc->hc_died = true;
-       schedule_delayed_work(&mdwc->sm_work, 0);
+       queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
        return 0;
 }
 
@@ -2358,7 +2359,7 @@ static void dwc3_ext_event_notify(struct dwc3_msm *mdwc)
        }
 
        pm_stay_awake(mdwc->dev);
-       schedule_delayed_work(&mdwc->sm_work, 0);
+       queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
 }
 
 static void dwc3_resume_work(struct work_struct *w)
@@ -2944,6 +2945,12 @@ static int dwc3_msm_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&mdwc->perf_vote_work, msm_dwc3_perf_vote_work);
        INIT_DELAYED_WORK(&mdwc->sdp_check, check_for_sdp_connection);
 
+       mdwc->sm_usb_wq = create_freezable_workqueue("k_sm_usb");
+       if (!mdwc->sm_usb_wq) {
+               pr_err("%s: Failed to create workqueue for sm_usb\n", __func__);
+               return -ENOMEM;
+       }
+
        mdwc->dwc3_wq = alloc_ordered_workqueue("dwc3_wq", 0);
        if (!mdwc->dwc3_wq) {
                pr_err("%s: Unable to create workqueue dwc3_wq\n", __func__);
@@ -3248,7 +3255,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
                dwc3_msm_id_notifier(&mdwc->id_nb, true, mdwc->extcon_id);
        else if (!pval.intval) {
                /* USB cable is not connected */
-               schedule_delayed_work(&mdwc->sm_work, 0);
+               queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
        } else {
                if (pval.intval > 0)
                        dev_info(mdwc->dev, "charger detection in progress\n");
@@ -3868,6 +3875,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
                        break;
                } else {
                        dwc3_msm_gadget_vbus_draw(mdwc, 0);
+                       pm_relax(mdwc->dev);
                        dev_dbg(mdwc->dev, "Cable disconnected\n");
                }
                break;
@@ -3981,7 +3989,7 @@ static void dwc3_otg_sm_work(struct work_struct *w)
        }
 
        if (work)
-               schedule_delayed_work(&mdwc->sm_work, delay);
+               queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, delay);
 
 ret:
        return;
@@ -4086,9 +4094,7 @@ static int dwc3_msm_pm_resume(struct device *dev)
        if (mdwc->no_wakeup_src_in_hostmode && !test_bit(ID, &mdwc->inputs))
                dwc3_msm_resume(mdwc);
 
-       /* kick in otg state machine */
-       if (mdwc->vbus_active || !mdwc->id_state)
-               queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
+       queue_work(mdwc->dwc3_wq, &mdwc->resume_work);
 
        return 0;
 }