From 9acdf4df2fc4680b08fa242b09717892cd687d4a Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 8 Mar 2016 20:21:47 +0000 Subject: usb: gadget: f_midi: added spinlock on transmit function Since f_midi_transmit is called by both ALSA and USB sub-systems, it can potentially cause a race condition between both calls because f_midi_transmit is not reentrant nor thread-safe. This is due to an implementation detail that the transmit function looks for the next available usb request from the fifo and only enqueues it if there is data to send, otherwise just re-uses it. So, if both ALSA and USB frameworks calls this function at the same time, kfifo_seek() will return the same usb_request, which will cause a race condition. To solve this problem a syncronization mechanism is necessary. In this case it is used a spinlock since f_midi_transmit is also called by usb_request->complete callback in interrupt context. Cc: # v4.5+ Fixes: e1e3d7ec5da3 ("usb: gadget: f_midi: pre-allocate IN requests") Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 84c0ee5ebd1e..56e2dde99b03 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,7 @@ struct f_midi { unsigned int buflen, qlen; /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */ DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); + spinlock_t transmit_lock; unsigned int in_last_port; struct gmidi_in_port in_ports_array[/* in_ports */]; @@ -597,17 +599,22 @@ static void f_midi_transmit(struct f_midi *midi) { struct usb_ep *ep = midi->in_ep; int ret; + unsigned long flags; /* We only care about USB requests if IN endpoint is enabled */ if (!ep || !ep->enabled) goto drop_out; + spin_lock_irqsave(&midi->transmit_lock, flags); + do { ret = f_midi_do_transmit(midi, ep); if (ret < 0) goto drop_out; } while (ret); + spin_unlock_irqrestore(&midi->transmit_lock, flags); + return; drop_out: @@ -1201,6 +1208,8 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) if (status) goto setup_fail; + spin_lock_init(&midi->transmit_lock); + ++opts->refcnt; mutex_unlock(&opts->lock); -- cgit v1.2.3 From f59dcab176293b646e1358144c93c58c3cda2813 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 11 Mar 2016 10:51:52 +0200 Subject: usb: dwc3: core: improve reset sequence According to Synopsys Databook, we shouldn't be relying on GCTL.CORESOFTRESET bit as that's only for debugging purposes. Instead, let's use DCTL.CSFTRST if we're OTG or PERIPHERAL mode. Host side block will be reset by XHCI driver if necessary. Note that this reduces amount of time spent on dwc3_probe() by a long margin. We're still gonna wait for reset to finish for a long time (default to 1ms max), but tests show that the reset polling loop executed at most 19 times (modprobe dwc3 && modprobe -r dwc3 executed 1000 times in a row). Suggested-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 48 ++++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 17fd81447c9f..fa20f5a99d12 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -67,23 +67,9 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) static int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; + int retries = 1000; int ret; - /* Before Resetting PHY, put Core in Reset */ - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - - /* Assert USB3 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); - - /* Assert USB2 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); - usb_phy_init(dwc->usb2_phy); usb_phy_init(dwc->usb3_phy); ret = phy_init(dwc->usb2_generic_phy); @@ -95,26 +81,28 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) phy_exit(dwc->usb2_generic_phy); return ret; } - mdelay(100); - /* Clear USB3 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + /* + * We're resetting only the device side because, if we're in host mode, + * XHCI driver will reset the host block. If dwc3 was configured for + * host-only mode, then we can return early. + */ + if (dwc->dr_mode == USB_DR_MODE_HOST) + return 0; - /* Clear USB2 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_CSFTRST; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); - mdelay(100); + do { + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (!(reg & DWC3_DCTL_CSFTRST)) + return 0; - /* After PHYs are stable we can take Core out of reset state */ - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); + udelay(1); + } while (--retries); - return 0; + return -ETIMEDOUT; } /** -- cgit v1.2.3 From ad14d4e0308afda06a60036020a15025571604af Mon Sep 17 00:00:00 2001 From: Jiebing Li Date: Thu, 11 Dec 2014 13:26:29 +0800 Subject: usb: dwc3: gadget: release spin lock during gadget resume It's a requirement that we release controller's lock while calling gadget API function pointers. This patch just fixes that long standing bug. Signed-off-by: Jiebing Li Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3ac170f9d94d..3d2c53e4ac92 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2487,7 +2487,11 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) * implemented. */ - dwc->gadget_driver->resume(&dwc->gadget); + if (dwc->gadget_driver && dwc->gadget_driver->resume) { + spin_unlock(&dwc->lock); + dwc->gadget_driver->resume(&dwc->gadget); + spin_lock(&dwc->lock); + } } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, -- cgit v1.2.3 From e901aa159dac9988c9961c31c01730effe8f5c22 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 16 Mar 2016 14:01:37 +0200 Subject: usb: dwc3: gadget: fix endpoint renaming We were exitting the function before actually renaming anything. While at that, also always leave control endpoint un-renamed. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3d2c53e4ac92..d54a028cdfeb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -568,7 +568,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); if (!usb_endpoint_xfer_isoc(desc)) - return 0; + goto out; /* Link TRB for ISOC. The HWO bit is never reset */ trb_st_hw = &dep->trb_pool[0]; @@ -582,9 +582,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } +out: switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: - strlcat(dep->name, "-control", sizeof(dep->name)); + /* don't change name */ break; case USB_ENDPOINT_XFER_ISOC: strlcat(dep->name, "-isoc", sizeof(dep->name)); -- cgit v1.2.3 From 38e58986e6fc14617f6361ec5178e5191e7ab5c1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 21 Mar 2016 09:04:23 +0200 Subject: usb: gadget: udc: atmel: don't disable enpdoints we don't own UDC driver should NEVER do anything behind udc-core's back, so let's stop disabling endpoints we don't exactly own - rather we provide as resources for gadget drivers. This fixes the regression reported by Gil. Reported-by: Gil Weber Tested-by: Gil Weber Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 81d42cce885a..18569de06b04 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1045,20 +1045,6 @@ static void reset_all_endpoints(struct usba_udc *udc) list_del_init(&req->queue); request_complete(ep, req, -ECONNRESET); } - - /* NOTE: normally, the next call to the gadget driver is in - * charge of disabling endpoints... usually disconnect(). - * The exception would be entering a high speed test mode. - * - * FIXME remove this code ... and retest thoroughly. - */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->ep.desc) { - spin_unlock(&udc->lock); - usba_ep_disable(&ep->ep); - spin_lock(&udc->lock); - } - } } static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) -- cgit v1.2.3 From 08f8cabf715654634a0bae8bee7afea964c6c9cb Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 28 Mar 2016 16:12:24 -0700 Subject: usb: gadget: composite: Access SSP Dev Cap fields properly Access multi-byte fields of the SSP Dev Cap descriptor using the correct endianness. Fixes: f228a8de242a ("usb: gadget: composite: Return SSP Dev Cap descriptor") Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index a5c62093c26c..de9ffd60fcfa 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -656,7 +656,8 @@ static int bos_desc(struct usb_composite_dev *cdev) ssp_cap->bmAttributes = cpu_to_le32(1); /* Min RX/TX Lane Count = 1 */ - ssp_cap->wFunctionalitySupport = (1 << 8) | (1 << 12); + ssp_cap->wFunctionalitySupport = + cpu_to_le16((1 << 8) | (1 << 12)); /* * bmSublinkSpeedAttr[0]: @@ -666,7 +667,7 @@ static int bos_desc(struct usb_composite_dev *cdev) * LSM = 10 (10 Gbps) */ ssp_cap->bmSublinkSpeedAttr[0] = - (3 << 4) | (1 << 14) | (0xa << 16); + cpu_to_le32((3 << 4) | (1 << 14) | (0xa << 16)); /* * bmSublinkSpeedAttr[1] = * ST = Symmetric, TX @@ -675,7 +676,8 @@ static int bos_desc(struct usb_composite_dev *cdev) * LSM = 10 (10 Gbps) */ ssp_cap->bmSublinkSpeedAttr[1] = - (3 << 4) | (1 << 14) | (0xa << 16) | (1 << 7); + cpu_to_le32((3 << 4) | (1 << 14) | + (0xa << 16) | (1 << 7)); } return le16_to_cpu(bos->wTotalLength); -- cgit v1.2.3 From 743bc4b069517d3bae69349a1a23511eaaae5ede Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 28 Mar 2016 16:12:21 -0700 Subject: usb: ch9: Fix SSP Device Cap wFunctionalitySupport type The wFunctionalitySupport field should be __le16. Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- include/uapi/linux/usb/ch9.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h index 06d6c6228a7a..d5ce71607972 100644 --- a/include/uapi/linux/usb/ch9.h +++ b/include/uapi/linux/usb/ch9.h @@ -899,7 +899,7 @@ struct usb_ssp_cap_descriptor { __le32 bmAttributes; #define USB_SSP_SUBLINK_SPEED_ATTRIBS (0x1f << 0) /* sublink speed entries */ #define USB_SSP_SUBLINK_SPEED_IDS (0xf << 5) /* speed ID entries */ - __u16 wFunctionalitySupport; + __le16 wFunctionalitySupport; #define USB_SSP_MIN_SUBLINK_SPEED_ATTRIBUTE_ID (0xf) #define USB_SSP_MIN_RX_LANE_COUNT (0xf << 8) #define USB_SSP_MIN_TX_LANE_COUNT (0xf << 12) -- cgit v1.2.3 From 7e8ac87a44746b03a37d296fdb3e6b5d96350952 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Mar 2016 17:29:14 +0100 Subject: usb: phy: qcom-8x16: fix regulator API abuse gcc warns about the use of regulators in phy_8x16_probe: drivers/usb/phy/phy-qcom-8x16-usb.c: In function 'phy_8x16_probe': drivers/usb/phy/phy-qcom-8x16-usb.c:284:13: error: 'regs[0].consumer' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/usb/phy/phy-qcom-8x16-usb.c:285:13: error: 'regs[1].consumer' may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/usb/phy/phy-qcom-8x16-usb.c:286:12: error: 'regs[2].consumer' may be used uninitialized in this function [-Werror=maybe-uninitialized] According to Mark Brown, this is the result of various abuses of the PHY interfaces [1], so let's fix the driver instead. This puts the regulator bulk data into the device structure so it gets properly initialized and lets us call regulator_bulk_enable() and regulator_bulk_disable() rather than open-coding them. Setting the voltages the way the driver does is rather pointless because for each regulator there is only one valid voltage range, so that can just get set up in the DT. As there doesn't seem to be any user of the newly added driver yet, we can simply make sure the DTs are setting this up right when they get added. I'm also fixing the handling of regulator_bulk_enable() failure. Right now, the driver just ignores any failure, which doesn't make sense, so I'm changing it to loudly complain (in case we actually had a bug here) and error out. Doing a fly-by review of the driver, I notice a couple of other problems that I'm not addressing here: - It really should not have been written as a USB PHY driver, but instead should use the PHY subsystem. - The DT compatible string does not follow the usual conventions, and it should have a proper identifier in it rather than a wildcard. - The example in the devicetree binding lists a register address that is the same as the actual EHCI host controller in the SoC as well as the otg-snps and the ci-hdrc device, which indicates that these are probably not even distinct devices (or all but one of them are wrong), and if more than one of them tries to request the resources correctly, they fail. [1] https://lkml.org/lkml/2016/1/26/267 Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-qcom-8x16-usb.c | 72 ++++++------------------------------- 1 file changed, 11 insertions(+), 61 deletions(-) diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index 579587d97217..3d7af85aecb9 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -65,9 +65,7 @@ struct phy_8x16 { void __iomem *regs; struct clk *core_clk; struct clk *iface_clk; - struct regulator *v3p3; - struct regulator *v1p8; - struct regulator *vdd; + struct regulator_bulk_data regulator[3]; struct reset_control *phy_reset; @@ -78,51 +76,6 @@ struct phy_8x16 { struct notifier_block reboot_notify; }; -static int phy_8x16_regulators_enable(struct phy_8x16 *qphy) -{ - int ret; - - ret = regulator_set_voltage(qphy->vdd, HSPHY_VDD_MIN, HSPHY_VDD_MAX); - if (ret) - return ret; - - ret = regulator_enable(qphy->vdd); - if (ret) - return ret; - - ret = regulator_set_voltage(qphy->v3p3, HSPHY_3P3_MIN, HSPHY_3P3_MAX); - if (ret) - goto off_vdd; - - ret = regulator_enable(qphy->v3p3); - if (ret) - goto off_vdd; - - ret = regulator_set_voltage(qphy->v1p8, HSPHY_1P8_MIN, HSPHY_1P8_MAX); - if (ret) - goto off_3p3; - - ret = regulator_enable(qphy->v1p8); - if (ret) - goto off_3p3; - - return 0; - -off_3p3: - regulator_disable(qphy->v3p3); -off_vdd: - regulator_disable(qphy->vdd); - - return ret; -} - -static void phy_8x16_regulators_disable(struct phy_8x16 *qphy) -{ - regulator_disable(qphy->v1p8); - regulator_disable(qphy->v3p3); - regulator_disable(qphy->vdd); -} - static int phy_8x16_notify_connect(struct usb_phy *phy, enum usb_device_speed speed) { @@ -261,7 +214,6 @@ static void phy_8x16_shutdown(struct usb_phy *phy) static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) { - struct regulator_bulk_data regs[3]; struct device *dev = qphy->phy.dev; int ret; @@ -273,18 +225,15 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) if (IS_ERR(qphy->iface_clk)) return PTR_ERR(qphy->iface_clk); - regs[0].supply = "v3p3"; - regs[1].supply = "v1p8"; - regs[2].supply = "vddcx"; + qphy->regulator[0].supply = "v3p3"; + qphy->regulator[1].supply = "v1p8"; + qphy->regulator[2].supply = "vddcx"; - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs); + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(qphy->regulator), + qphy->regulator); if (ret) return ret; - qphy->v3p3 = regs[0].consumer; - qphy->v1p8 = regs[1].consumer; - qphy->vdd = regs[2].consumer; - qphy->phy_reset = devm_reset_control_get(dev, "phy"); if (IS_ERR(qphy->phy_reset)) return PTR_ERR(qphy->phy_reset); @@ -364,8 +313,9 @@ static int phy_8x16_probe(struct platform_device *pdev) if (ret < 0) goto off_core; - ret = phy_8x16_regulators_enable(qphy); - if (0 && ret) + ret = regulator_bulk_enable(ARRAY_SIZE(qphy->regulator), + qphy->regulator); + if (WARN_ON(ret)) goto off_clks; qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; @@ -387,7 +337,7 @@ off_extcon: extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB, &qphy->vbus_notify); off_power: - phy_8x16_regulators_disable(qphy); + regulator_bulk_disable(ARRAY_SIZE(qphy->regulator), qphy->regulator); off_clks: clk_disable_unprepare(qphy->iface_clk); off_core: @@ -413,7 +363,7 @@ static int phy_8x16_remove(struct platform_device *pdev) clk_disable_unprepare(qphy->iface_clk); clk_disable_unprepare(qphy->core_clk); - phy_8x16_regulators_disable(qphy); + regulator_bulk_disable(ARRAY_SIZE(qphy->regulator), qphy->regulator); return 0; } -- cgit v1.2.3