From fa0777162ee0366fb176266c24fa1812a547c6b0 Mon Sep 17 00:00:00 2001 From: Wu Liang feng Date: Sat, 10 Sep 2016 12:34:14 +0800 Subject: [PATCH] usb: dwc3: introduce a connection flag for rockchip platform We used dwc->connected flag for rockchip platform before, but this flag can be modified both in dwc3_gadget_disconnect_interrupt() and dwc3_rockchip_otg_extcon_evt_work(), this result in race condition may casue USB hot plug failed. A typical error case is: Set DWC3 works as peripheral device, connect to PC, after PC identifies the USB device, and then disconnet USB cable, if dwc3_gadget_disconnect_interrupt() is called prior to dwc3_rockchip_otg_extcon_evt_work(), it will cause extcon work unable to do disconnect operation, and let DWC3 core device stay in runtime active status. Then if we plug in USB cable again, we'll fail to do runtime resume DWC3 core and reinit it. Change-Id: I1c06fa55c10b3dfb749b689a116ab939a6e13f97 Signed-off-by: Wu Liang feng --- drivers/usb/dwc3/dwc3-rockchip.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-rockchip.c b/drivers/usb/dwc3/dwc3-rockchip.c index 744e0e171273..3c77bd3fed70 100644 --- a/drivers/usb/dwc3/dwc3-rockchip.c +++ b/drivers/usb/dwc3/dwc3-rockchip.c @@ -37,6 +37,7 @@ struct dwc3_rockchip { int num_clocks; + bool connected; struct device *dev; struct clk **clks; struct dwc3 *dwc; @@ -84,7 +85,7 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) return; if (extcon_get_cable_state_(edev, EXTCON_USB) > 0) { - if (dwc->connected) + if (rockchip->connected) return; /* @@ -97,13 +98,13 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) pm_runtime_get_sync(dwc->dev); spin_lock_irqsave(&dwc->lock, flags); - dwc->connected = true; dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); spin_unlock_irqrestore(&dwc->lock, flags); + rockchip->connected = true; dev_info(rockchip->dev, "USB peripheral connected\n"); } else if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) > 0) { - if (dwc->connected) + if (rockchip->connected) return; /* @@ -131,7 +132,6 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) spin_lock_irqsave(&dwc->lock, flags); dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); - dwc->connected = true; spin_unlock_irqrestore(&dwc->lock, flags); if (hcd->state == HC_STATE_HALT) { @@ -139,9 +139,10 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) usb_add_hcd(hcd->shared_hcd, hcd->irq, IRQF_SHARED); } + rockchip->connected = true; dev_info(rockchip->dev, "USB HOST connected\n"); } else { - if (!dwc->connected) + if (!rockchip->connected) return; reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -160,12 +161,9 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) } - spin_lock_irqsave(&dwc->lock, flags); - dwc->connected = false; - spin_unlock_irqrestore(&dwc->lock, flags); - pm_runtime_put_sync(dwc->dev); + rockchip->connected = false; dev_info(rockchip->dev, "USB unconnected\n"); } } -- 2.34.1