From 18abf874367456540846319574864e6ff32752e2 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 26 Apr 2021 11:26:22 +0200 Subject: cdc-wdm: untangle a circular dependency between callback and softint We have a cycle of callbacks scheduling works which submit URBs with those callbacks. This needs to be blocked, stopped and unblocked to untangle the circle. Signed-off-by: Oliver Neukum Link: https://lore.kernel.org/r/20210426092622.20433-1-oneukum@suse.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 508b1c3f8b73..d1e4a7379beb 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -321,12 +321,23 @@ exit: } -static void kill_urbs(struct wdm_device *desc) +static void poison_urbs(struct wdm_device *desc) { /* the order here is essential */ - usb_kill_urb(desc->command); - usb_kill_urb(desc->validity); - usb_kill_urb(desc->response); + usb_poison_urb(desc->command); + usb_poison_urb(desc->validity); + usb_poison_urb(desc->response); +} + +static void unpoison_urbs(struct wdm_device *desc) +{ + /* + * the order here is not essential + * it is symmetrical just to be nice + */ + usb_unpoison_urb(desc->response); + usb_unpoison_urb(desc->validity); + usb_unpoison_urb(desc->command); } static void free_urbs(struct wdm_device *desc) @@ -741,11 +752,12 @@ static int wdm_release(struct inode *inode, struct file *file) if (!desc->count) { if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { dev_dbg(&desc->intf->dev, "wdm_release: cleanup\n"); - kill_urbs(desc); + poison_urbs(desc); spin_lock_irq(&desc->iuspin); desc->resp_count = 0; spin_unlock_irq(&desc->iuspin); desc->manage_power(desc->intf, 0); + unpoison_urbs(desc); } else { /* must avoid dev_printk here as desc->intf is invalid */ pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); @@ -1037,9 +1049,9 @@ static void wdm_disconnect(struct usb_interface *intf) wake_up_all(&desc->wait); mutex_lock(&desc->rlock); mutex_lock(&desc->wlock); + poison_urbs(desc); cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->service_outs_intr); - kill_urbs(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); @@ -1080,9 +1092,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) set_bit(WDM_SUSPENDING, &desc->flags); spin_unlock_irq(&desc->iuspin); /* callback submits work - order is essential */ - kill_urbs(desc); + poison_urbs(desc); cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->service_outs_intr); + unpoison_urbs(desc); } if (!PMSG_IS_AUTO(message)) { mutex_unlock(&desc->wlock); @@ -1140,7 +1153,7 @@ static int wdm_pre_reset(struct usb_interface *intf) wake_up_all(&desc->wait); mutex_lock(&desc->rlock); mutex_lock(&desc->wlock); - kill_urbs(desc); + poison_urbs(desc); cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->service_outs_intr); return 0; @@ -1151,6 +1164,7 @@ static int wdm_post_reset(struct usb_interface *intf) struct wdm_device *desc = wdm_find_device(intf); int rv; + unpoison_urbs(desc); clear_bit(WDM_OVERFLOW, &desc->flags); clear_bit(WDM_RESETTING, &desc->flags); rv = recover_from_urb_loss(desc); -- cgit v1.2.3 From 04357fafea9c7ed34525eb9680c760245c3bb958 Mon Sep 17 00:00:00 2001 From: Ferry Toth Date: Sun, 25 Apr 2021 17:09:47 +0200 Subject: usb: dwc3: pci: Enable usb2-gadget-lpm-disable for Intel Merrifield On Intel Merrifield LPM is causing host to reset port after a timeout. By disabling LPM entirely this is prevented. Fixes: 066c09593454 ("usb: dwc3: pci: Enable extcon driver for Intel Merrifield") Reviewed-by: Andy Shevchenko Signed-off-by: Ferry Toth Cc: stable Link: https://lore.kernel.org/r/20210425150947.5862-1-ftoth@exalondelft.nl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index e7b932dcbf82..1e51460938b8 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -123,6 +123,7 @@ static const struct property_entry dwc3_pci_mrfld_properties[] = { PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"), PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), + PROPERTY_ENTRY_BOOL("snps,usb2-gadget-lpm-disable"), PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), {} }; -- cgit v1.2.3 From 9cbc7eb17cdf6d1adaa2aebfe0079077d31d39a9 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Mon, 26 Apr 2021 14:08:40 -0700 Subject: usb: dwc3: core: Add missing GHWPARAMS9 doc Add missing documentation for struct dwc3_hwparams new field hwparams9 to avoid kernel doc build warning. Fixes: 16710380d3aa ("usb: dwc3: Capture new capability register GHWPARAMS9") Reported-by: Stephen Rothwell Acked-by: Felipe Balbi Signed-off-by: Thinh Nguyen Link: https://lore.kernel.org/r/f4c491f7614e623755fafe640b7e690e7c5634e2.1619471127.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b1e875c58f20..3859d8cad3cb 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -850,6 +850,7 @@ struct dwc3_trb { * @hwparams6: GHWPARAMS6 * @hwparams7: GHWPARAMS7 * @hwparams8: GHWPARAMS8 + * @hwparams9: GHWPARAMS9 */ struct dwc3_hwparams { u32 hwparams0; -- cgit v1.2.3 From d1d90dd27254c44d087ad3f8b5b3e4fff0571f45 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 28 Apr 2021 02:01:10 -0700 Subject: usb: dwc3: gadget: Enable suspend events commit 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler") introduced (nearly 5 years ago!) an interrupt handler for U3/L1-L2 suspend events. The problem is that these events aren't currently enabled in the DEVTEN register so the handler is never even invoked. Fix this simply by enabling the corresponding bit in dwc3_gadget_enable_irq() using the same revision check as found in the handler. Fixes: 72704f876f50 ("dwc3: gadget: Implement the suspend entry event handler") Acked-by: Felipe Balbi Signed-off-by: Jack Pham Cc: stable Link: https://lore.kernel.org/r/20210428090111.3370-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dd80e5ca8c78..cab3a9184068 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2323,6 +2323,10 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) if (DWC3_VER_IS_PRIOR(DWC3, 250A)) reg |= DWC3_DEVTEN_ULSTCNGEN; + /* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */ + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + reg |= DWC3_DEVTEN_EOPFEN; + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } -- cgit v1.2.3 From 6f26ebb79a84bcad211cb2d8a2ef74dfc427322d Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 28 Apr 2021 02:01:11 -0700 Subject: usb: dwc3: gadget: Rename EOPF event macros to Suspend The device event corresponding to End of Periodic Frame is only found on older IP revisions (2.10a and prior, according to a cursory SNPS databook search). On revisions 2.30a and newer, including DWC3.1, the same event value and corresponding DEVTEN bit were repurposed to indicate that the link has gone into suspend state (U3 or L2/L1). EOPF events had never been enabled before in this driver, and going forward we expect current and future DWC3-based devices won't likely to be using such old DWC3 IP revisions either. Hence rather than keeping the deprecated EOPF macro names let's rename them to indicate their usage for suspend events. Acked-by: Felipe Balbi Signed-off-by: Jack Pham Link: https://lore.kernel.org/r/20210428090111.3370-2-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 6 +++--- drivers/usb/dwc3/debug.h | 8 ++++---- drivers/usb/dwc3/gadget.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3859d8cad3cb..c5d5760cdf53 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -57,7 +57,7 @@ #define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3 #define DWC3_DEVICE_EVENT_WAKEUP 4 #define DWC3_DEVICE_EVENT_HIBER_REQ 5 -#define DWC3_DEVICE_EVENT_EOPF 6 +#define DWC3_DEVICE_EVENT_SUSPEND 6 #define DWC3_DEVICE_EVENT_SOF 7 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 #define DWC3_DEVICE_EVENT_CMD_CMPL 10 @@ -460,7 +460,7 @@ #define DWC3_DEVTEN_CMDCMPLTEN BIT(10) #define DWC3_DEVTEN_ERRTICERREN BIT(9) #define DWC3_DEVTEN_SOFEN BIT(7) -#define DWC3_DEVTEN_EOPFEN BIT(6) +#define DWC3_DEVTEN_U3L2L1SUSPEN BIT(6) #define DWC3_DEVTEN_HIBERNATIONREQEVTEN BIT(5) #define DWC3_DEVTEN_WKUPEVTEN BIT(4) #define DWC3_DEVTEN_ULSTCNGEN BIT(3) @@ -1375,7 +1375,7 @@ struct dwc3_event_depevt { * 3 - ULStChng * 4 - WkUpEvt * 5 - Reserved - * 6 - EOPF + * 6 - Suspend (EOPF on revisions 2.10a and prior) * 7 - SOF * 8 - Reserved * 9 - ErrticErr diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index db231de46bb3..d0ac89c5b317 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -221,8 +221,8 @@ static inline const char *dwc3_gadget_event_string(char *str, size_t size, snprintf(str, size, "WakeUp [%s]", dwc3_gadget_link_string(state)); break; - case DWC3_DEVICE_EVENT_EOPF: - snprintf(str, size, "End-Of-Frame [%s]", + case DWC3_DEVICE_EVENT_SUSPEND: + snprintf(str, size, "Suspend [%s]", dwc3_gadget_link_string(state)); break; case DWC3_DEVICE_EVENT_SOF: @@ -353,8 +353,8 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) return "Wake-Up"; case DWC3_DEVICE_EVENT_HIBER_REQ: return "Hibernation"; - case DWC3_DEVICE_EVENT_EOPF: - return "End of Periodic Frame"; + case DWC3_DEVICE_EVENT_SUSPEND: + return "Suspend"; case DWC3_DEVICE_EVENT_SOF: return "Start of Frame"; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cab3a9184068..6eab78f8a1a7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2325,7 +2325,7 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) /* On 2.30a and above this bit enables U3/L2-L1 Suspend Events */ if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) - reg |= DWC3_DEVTEN_EOPFEN; + reg |= DWC3_DEVTEN_U3L2L1SUSPEN; dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } @@ -3744,7 +3744,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); break; - case DWC3_DEVICE_EVENT_EOPF: + case DWC3_DEVICE_EVENT_SUSPEND: /* It changed to be suspend event for version 2.30a and above */ if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { /* -- cgit v1.2.3 From 75a41ce46bae6cbe7d3bb2584eb844291d642874 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 6 May 2021 12:22:00 +0100 Subject: usb: dwc2: Fix gadget DMA unmap direction The dwc2 gadget support maps and unmaps DMA buffers as necessary. When mapping and unmapping it uses the direction of the endpoint to select the direction of the DMA transfer, but this fails for Control OUT transfers because the unmap occurs after the endpoint direction has been reversed for the status phase. A possible solution would be to unmap the buffer before the direction is changed, but a safer, less invasive fix is to remember the buffer direction independently of the endpoint direction. Fixes: fe0b94abcdf6 ("usb: dwc2: gadget: manage ep0 state in software") Acked-by: Minas Harutyunyan Cc: stable Signed-off-by: Phil Elwell Link: https://lore.kernel.org/r/20210506112200.2893922-1-phil@raspberrypi.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/core.h | 2 ++ drivers/usb/dwc2/gadget.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index da5ac4a4595b..ab6b815e0089 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -113,6 +113,7 @@ struct dwc2_hsotg_req; * @debugfs: File entry for debugfs file for this endpoint. * @dir_in: Set to true if this endpoint is of the IN direction, which * means that it is sending data to the Host. + * @map_dir: Set to the value of dir_in when the DMA buffer is mapped. * @index: The index for the endpoint registers. * @mc: Multi Count - number of transactions per microframe * @interval: Interval for periodic endpoints, in frames or microframes. @@ -162,6 +163,7 @@ struct dwc2_hsotg_ep { unsigned short fifo_index; unsigned char dir_in; + unsigned char map_dir; unsigned char index; unsigned char mc; u16 interval; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e6bb1bdb2760..184964174dc0 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -422,7 +422,7 @@ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, { struct usb_request *req = &hs_req->req; - usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->map_dir); } /* @@ -1242,6 +1242,7 @@ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, { int ret; + hs_ep->map_dir = hs_ep->dir_in; ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); if (ret) goto dma_error; -- cgit v1.2.3 From bb9c74a5bd1462499fe5ccb1e3c5ac40dcfa9139 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Sat, 1 May 2021 02:35:58 -0700 Subject: usb: dwc3: gadget: Free gadget structure only after freeing endpoints As part of commit e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") the dwc3_gadget_release() was added which will free the dwc->gadget structure upon the device's removal when usb_del_gadget_udc() is called in dwc3_gadget_exit(). However, simply freeing the gadget results a dangling pointer situation: the endpoints created in dwc3_gadget_init_endpoints() have their dep->endpoint.ep_list members chained off the list_head anchored at dwc->gadget->ep_list. Thus when dwc->gadget is freed, the first dwc3_ep in the list now has a dangling prev pointer and likewise for the next pointer of the dwc3_ep at the tail of the list. The dwc3_gadget_free_endpoints() that follows will result in a use-after-free when it calls list_del(). This was caught by enabling KASAN and performing a driver unbind. The recent commit 568262bf5492 ("usb: dwc3: core: Add shutdown callback for dwc3") also exposes this as a panic during shutdown. There are a few possibilities to fix this. One could be to perform a list_del() of the gadget->ep_list itself which removes it from the rest of the dwc3_ep chain. Another approach is what this patch does, by splitting up the usb_del_gadget_udc() call into its separate "del" and "put" components. This allows dwc3_gadget_free_endpoints() to be called before the gadget is finally freed with usb_put_gadget(). Fixes: e81a7018d93a ("usb: dwc3: allocate gadget structure dynamically") Reviewed-by: Peter Chen Signed-off-by: Jack Pham Link: https://lore.kernel.org/r/20210501093558.7375-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6eab78f8a1a7..dd1342403bb2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4062,8 +4062,9 @@ err0: void dwc3_gadget_exit(struct dwc3 *dwc) { - usb_del_gadget_udc(dwc->gadget); + usb_del_gadget(dwc->gadget); dwc3_gadget_free_endpoints(dwc); + usb_put_gadget(dwc->gadget); dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, dwc->bounce_addr); kfree(dwc->setup_buf); -- cgit v1.2.3 From 18ffa988dbae69cc6e9949cddd9606f6fe533894 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Fri, 7 May 2021 10:55:19 -0700 Subject: usb: dwc3: gadget: Return success always for kick transfer in ep queue If an error is received when issuing a start or update transfer command, the error handler will stop all active requests (including the current USB request), and call dwc3_gadget_giveback() to notify function drivers of the requests which have been stopped. Avoid returning an error for kick transfer during EP queue, to remove duplicate cleanup operations on the request being queued. Fixes: 8d99087c2db8 ("usb: dwc3: gadget: Properly handle failed kick_transfer") cc: stable@vger.kernel.org Signed-off-by: Wesley Cheng Link: https://lore.kernel.org/r/1620410119-24971-1-git-send-email-wcheng@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dd1342403bb2..49ca5da5e279 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1684,7 +1684,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) } } - return __dwc3_gadget_kick_transfer(dep); + __dwc3_gadget_kick_transfer(dep); + + return 0; } static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, -- cgit v1.2.3 From b96992081fde19806b5beb5b25f9327820ead77b Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 30 Apr 2021 14:57:16 +0800 Subject: usb: dwc3: imx8mp: detect dwc3 core node via compatible string New schema of usb controller DT-node should be named with prefix "^usb(@.*)?", dt changed the node name, but missed counter part change in driver, fix it by switching to use compatible string as the dwc3 core compatible string keeps "snps,dwc3" in all dt. Fixes: d1689cd3c0f4 ("arm64: dts: imx8mp: Use the correct name for child node "snps, dwc3"") Acked-by: Felipe Balbi Signed-off-by: Li Jun Link: https://lore.kernel.org/r/1619765836-20387-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-imx8mp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index b13cfab89d53..e9fced6f7a7c 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -165,7 +165,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) if (err < 0) goto disable_rpm; - dwc3_np = of_get_child_by_name(node, "dwc3"); + dwc3_np = of_get_compatible_child(node, "snps,dwc3"); if (!dwc3_np) { dev_err(dev, "failed to find dwc3 core child\n"); goto disable_rpm; -- cgit v1.2.3 From 0b2b149e918f6dddb4ea53615551bf7bc131f875 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Sat, 8 May 2021 09:53:10 +0800 Subject: usb: dwc3: imx8mp: fix error return code in dwc3_imx8mp_probe() Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Fixes: 6dd2565989b4 ("usb: dwc3: add imx8mp dwc3 glue layer driver") Reported-by: Hulk Robot Acked-by: Felipe Balbi Signed-off-by: Zhen Lei Cc: stable Link: https://lore.kernel.org/r/20210508015310.1627-1-thunder.leizhen@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-imx8mp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index e9fced6f7a7c..756faa46d33a 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -167,6 +167,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) dwc3_np = of_get_compatible_child(node, "snps,dwc3"); if (!dwc3_np) { + err = -ENODEV; dev_err(dev, "failed to find dwc3 core child\n"); goto disable_rpm; } -- cgit v1.2.3 From e89baeba4f64bab679618b3330cdcda5929fb8d5 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 3 May 2021 20:05:38 +0200 Subject: usb: dwc2: Remove obsolete MODULE_ constants from platform.c Originally, the core and platform drivers were separate modules, so each had its own module info. Since commit 2d1165a4b95e (usb: dwc2: remove dwc2_platform.ko) platform.c is included in the core module, which now contains duplicate module info (from core.c and platform.c). Due to the linking order and modinfo implementation, running `modinfo` on the resulting dwc2.ko shows just the info from platform.c, rather than that from core.c, suggesting that I am the author of the entire dwc2 module. Since platform.c is just a minor part of the entire module, this removes its module info in favor of the info from core.c. Acked-by: Minas Harutyunyan Signed-off-by: Matthijs Kooijman Link: https://lore.kernel.org/r/20210503180538.64423-1-matthijs@stdin.nl Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/platform.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 3024785d84cb..520a0beef77c 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -776,7 +776,3 @@ static struct platform_driver dwc2_platform_driver = { }; module_platform_driver(dwc2_platform_driver); - -MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue"); -MODULE_AUTHOR("Matthijs Kooijman "); -MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 2e2b8d15adc2f6ab2d4aa0550e241b9742a436a0 Mon Sep 17 00:00:00 2001 From: Kyle Tso Date: Tue, 4 May 2021 01:18:49 +0800 Subject: usb: typec: tcpm: Fix wrong handling in GET_SINK_CAP After receiving Sink Capabilities Message in GET_SINK_CAP AMS, it is incorrect to call tcpm_pd_handle_state because the Message is expected and the current state is not Ready states. The result of this incorrect operation ends in Soft Reset which is definitely wrong. Simply forwarding to Ready States is enough to finish the AMS. Fixes: 8dea75e11380 ("usb: typec: tcpm: Protocol Error handling") Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Kyle Tso Cc: stable Link: https://lore.kernel.org/r/20210503171849.2605302-1-kyletso@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index c4fdc00a3bc8..68e04e397e92 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -2390,7 +2390,7 @@ static void tcpm_pd_data_request(struct tcpm_port *port, port->nr_sink_caps = cnt; port->sink_cap_done = true; if (port->ams == GET_SINK_CAPABILITIES) - tcpm_pd_handle_state(port, ready_state(port), NONE_AMS, 0); + tcpm_set_state(port, ready_state(port), 0); /* Unexpected Sink Capabilities */ else tcpm_pd_handle_msg(port, -- cgit v1.2.3 From b9a0866a5bdf6a4643a52872ada6be6184c6f4f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 May 2021 01:23:37 +0300 Subject: usb: typec: ucsi: Put fwnode in any case during ->probe() device_for_each_child_node() bumps a reference counting of a returned variable. We have to balance it whenever we return to the caller. Fixes: c1b0bc2dabfa ("usb: typec: Add support for UCSI interface") Cc: Heikki Krogerus Reviewed-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210504222337.3151726-1-andy.shevchenko@gmail.com Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 282c3c825c13..0e1cec346e0f 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -999,6 +999,7 @@ static const struct typec_operations ucsi_ops = { .pr_set = ucsi_pr_swap }; +/* Caller must call fwnode_handle_put() after use */ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) { struct fwnode_handle *fwnode; @@ -1033,7 +1034,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) command |= UCSI_CONNECTOR_NUMBER(con->num); ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) - goto out; + goto out_unlock; if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP) cap->data = TYPEC_PORT_DRD; @@ -1151,6 +1152,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) trace_ucsi_register_port(con->num, &con->status); out: + fwnode_handle_put(cap->fwnode); +out_unlock: mutex_unlock(&con->lock); return ret; } -- cgit v1.2.3 From e17b02d4970913233d543c79c9c66e72cac05bdd Mon Sep 17 00:00:00 2001 From: Marcel Hamer Date: Tue, 27 Apr 2021 14:21:18 +0200 Subject: usb: dwc3: omap: improve extcon initialization When extcon is used in combination with dwc3, it is assumed that the dwc3 registers are untouched and as such are only configured if VBUS is valid or ID is tied to ground. In case VBUS is not valid or ID is floating, the registers are not configured as such during driver initialization, causing a wrong default state during boot. If the registers are not in a default state, because they are for instance touched by a boot loader, this can cause for a kernel error. Signed-off-by: Marcel Hamer Link: https://lore.kernel.org/r/20210427122118.1948340-1-marcel@solidxs.se Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-omap.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 3db17806e92e..e196673f5c64 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -437,8 +437,13 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) if (extcon_get_state(edev, EXTCON_USB) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF); + if (extcon_get_state(edev, EXTCON_USB_HOST) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + else + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT); omap->edev = edev; } -- cgit v1.2.3 From a60a34366e0d09ca002c966dd7c43a68c28b1f82 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 6 May 2021 22:39:10 +0200 Subject: usb: fotg210-hcd: Fix an error message 'retval' is known to be -ENODEV here. This is a hard-coded default error code which is not useful in the error message. Moreover, another error message is printed at the end of the error handling path. The corresponding error code (-ENOMEM) is more informative. So remove simplify the first error message. While at it, also remove the useless initialization of 'retval'. Fixes: 7d50195f6c50 ("usb: host: Faraday fotg210-hcd driver") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/94531bcff98e46d4f9c20183a90b7f47f699126c.1620333419.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fotg210-hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 6cac642520fc..9c2eda0918e1 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5568,7 +5568,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) struct usb_hcd *hcd; struct resource *res; int irq; - int retval = -ENODEV; + int retval; struct fotg210_hcd *fotg210; if (usb_disabled()) @@ -5588,7 +5588,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev) hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev, dev_name(dev)); if (!hcd) { - dev_err(dev, "failed to create hcd with err %d\n", retval); + dev_err(dev, "failed to create hcd\n"); retval = -ENOMEM; goto fail_create_hcd; } -- cgit v1.2.3 From 1f4642b72be79757f050924a9b9673b6a02034bc Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Mon, 3 May 2021 00:46:11 -0700 Subject: usb: typec: ucsi: Retrieve all the PDOs instead of just the first 4 commit 4dbc6a4ef06d ("usb: typec: ucsi: save power data objects in PD mode") introduced retrieval of the PDOs when connected to a PD-capable source. But only the first 4 PDOs are received since that is the maximum number that can be fetched at a time given the MESSAGE_IN length limitation (16 bytes). However, as per the PD spec a connected source may advertise up to a maximum of 7 PDOs. If such a source is connected it's possible the PPM could have negotiated a power contract with one of the PDOs at index greater than 4, and would be reflected in the request data object's (RDO) object position field. This would result in an out-of-bounds access when the rdo_index() is used to index into the src_pdos array in ucsi_psy_get_voltage_now(). With the help of the UBSAN -fsanitize=array-bounds checker enabled this exact issue is revealed when connecting to a PD source adapter that advertise 5 PDOs and the PPM enters a contract having selected the 5th one. [ 151.545106][ T70] Unexpected kernel BRK exception at EL1 [ 151.545112][ T70] Internal error: BRK handler: f2005512 [#1] PREEMPT SMP ... [ 151.545499][ T70] pc : ucsi_psy_get_prop+0x208/0x20c [ 151.545507][ T70] lr : power_supply_show_property+0xc0/0x328 ... [ 151.545542][ T70] Call trace: [ 151.545544][ T70] ucsi_psy_get_prop+0x208/0x20c [ 151.545546][ T70] power_supply_uevent+0x1a4/0x2f0 [ 151.545550][ T70] dev_uevent+0x200/0x384 [ 151.545555][ T70] kobject_uevent_env+0x1d4/0x7e8 [ 151.545557][ T70] power_supply_changed_work+0x174/0x31c [ 151.545562][ T70] process_one_work+0x244/0x6f0 [ 151.545564][ T70] worker_thread+0x3e0/0xa64 We can resolve this by instead retrieving and storing up to the maximum of 7 PDOs in the con->src_pdos array. This would involve two calls to the GET_PDOS command. Fixes: 992a60ed0d5e ("usb: typec: ucsi: register with power_supply class") Fixes: 4dbc6a4ef06d ("usb: typec: ucsi: save power data objects in PD mode") Cc: stable@vger.kernel.org Reported-and-tested-by: Subbaraman Narayanamurthy Reviewed-by: Heikki Krogerus Signed-off-by: Jack Pham Link: https://lore.kernel.org/r/20210503074611.30973-1-jackp@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 41 ++++++++++++++++++++++++++++++++--------- drivers/usb/typec/ucsi/ucsi.h | 6 ++++-- 2 files changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 0e1cec346e0f..1d8b7df59ff4 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -495,7 +495,8 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) } } -static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner) +static int ucsi_get_pdos(struct ucsi_connector *con, int is_partner, + u32 *pdos, int offset, int num_pdos) { struct ucsi *ucsi = con->ucsi; u64 command; @@ -503,17 +504,39 @@ static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner) command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner); - command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1); + command |= UCSI_GET_PDOS_PDO_OFFSET(offset); + command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1); command |= UCSI_GET_PDOS_SRC_PDOS; - ret = ucsi_send_command(ucsi, command, con->src_pdos, - sizeof(con->src_pdos)); - if (ret < 0) { + ret = ucsi_send_command(ucsi, command, pdos + offset, + num_pdos * sizeof(u32)); + if (ret < 0) dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); + if (ret == 0 && offset == 0) + dev_warn(ucsi->dev, "UCSI_GET_PDOS returned 0 bytes\n"); + + return ret; +} + +static void ucsi_get_src_pdos(struct ucsi_connector *con, int is_partner) +{ + int ret; + + /* UCSI max payload means only getting at most 4 PDOs at a time */ + ret = ucsi_get_pdos(con, 1, con->src_pdos, 0, UCSI_MAX_PDOS); + if (ret < 0) return; - } + con->num_pdos = ret / sizeof(u32); /* number of bytes to 32-bit PDOs */ - if (ret == 0) - dev_warn(ucsi->dev, "UCSI_GET_PDOS returned 0 bytes\n"); + if (con->num_pdos < UCSI_MAX_PDOS) + return; + + /* get the remaining PDOs, if any */ + ret = ucsi_get_pdos(con, 1, con->src_pdos, UCSI_MAX_PDOS, + PDO_MAX_OBJECTS - UCSI_MAX_PDOS); + if (ret < 0) + return; + + con->num_pdos += ret / sizeof(u32); } static void ucsi_pwr_opmode_change(struct ucsi_connector *con) @@ -522,7 +545,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con) case UCSI_CONSTAT_PWR_OPMODE_PD: con->rdo = con->status.request_data_obj; typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD); - ucsi_get_pdos(con, 1); + ucsi_get_src_pdos(con, 1); break; case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: con->rdo = 0; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 3920e20a9e9e..cee666790907 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -8,6 +8,7 @@ #include #include #include +#include #include /* -------------------------------------------------------------------------- */ @@ -134,7 +135,9 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); /* GET_PDOS command bits */ #define UCSI_GET_PDOS_PARTNER_PDO(_r_) ((u64)(_r_) << 23) +#define UCSI_GET_PDOS_PDO_OFFSET(_r_) ((u64)(_r_) << 24) #define UCSI_GET_PDOS_NUM_PDOS(_r_) ((u64)(_r_) << 32) +#define UCSI_MAX_PDOS (4) #define UCSI_GET_PDOS_SRC_PDOS ((u64)1 << 34) /* -------------------------------------------------------------------------- */ @@ -302,7 +305,6 @@ struct ucsi { #define UCSI_MAX_SVID 5 #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) -#define UCSI_MAX_PDOS (4) #define UCSI_TYPEC_VSAFE5V 5000 #define UCSI_TYPEC_1_5_CURRENT 1500 @@ -330,7 +332,7 @@ struct ucsi_connector { struct power_supply *psy; struct power_supply_desc psy_desc; u32 rdo; - u32 src_pdos[UCSI_MAX_PDOS]; + u32 src_pdos[PDO_MAX_OBJECTS]; int num_pdos; struct usb_role_switch *usb_role_sw; -- cgit v1.2.3 From c34e85fa69b9f4568f19da3af06c3870dd8fcc50 Mon Sep 17 00:00:00 2001 From: Kyle Tso Date: Fri, 7 May 2021 14:22:59 +0800 Subject: usb: typec: tcpm: Send DISCOVER_IDENTITY from dedicated work In current design, DISCOVER_IDENTITY is queued to VDM state machine immediately in Ready states and never retries if it fails in the AMS. Move the process to a delayed work so that when it fails for some reasons (e.g. Sink Tx No Go), it can be retried by queueing the work again. Also fix a problem that the vdm_state is not set to a proper state if it is blocked by Collision Avoidance mechanism. Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Kyle Tso Link: https://lore.kernel.org/r/20210507062300.1945009-2-kyletso@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 85 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 68e04e397e92..ae1e84252d38 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -259,6 +259,7 @@ enum frs_typec_current { #define ALTMODE_DISCOVERY_MAX (SVID_DISCOVERY_MAX * MODE_DISCOVERY_MAX) #define GET_SINK_CAP_RETRY_MS 100 +#define SEND_DISCOVER_RETRY_MS 100 struct pd_mode_data { int svid_index; /* current SVID index */ @@ -366,6 +367,8 @@ struct tcpm_port { struct kthread_work vdm_state_machine; struct hrtimer enable_frs_timer; struct kthread_work enable_frs; + struct hrtimer send_discover_timer; + struct kthread_work send_discover_work; bool state_machine_running; bool vdm_sm_running; @@ -1178,6 +1181,16 @@ static void mod_enable_frs_delayed_work(struct tcpm_port *port, unsigned int del } } +static void mod_send_discover_delayed_work(struct tcpm_port *port, unsigned int delay_ms) +{ + if (delay_ms) { + hrtimer_start(&port->send_discover_timer, ms_to_ktime(delay_ms), HRTIMER_MODE_REL); + } else { + hrtimer_cancel(&port->send_discover_timer); + kthread_queue_work(port->wq, &port->send_discover_work); + } +} + static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state, unsigned int delay_ms) { @@ -1855,6 +1868,9 @@ static void vdm_run_state_machine(struct tcpm_port *port) res = tcpm_ams_start(port, DISCOVER_IDENTITY); if (res == 0) port->send_discover = false; + else if (res == -EAGAIN) + mod_send_discover_delayed_work(port, + SEND_DISCOVER_RETRY_MS); break; case CMD_DISCOVER_SVID: res = tcpm_ams_start(port, DISCOVER_SVIDS); @@ -1880,6 +1896,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) } if (res < 0) { + port->vdm_state = VDM_STATE_ERR_BUSY; port->vdm_sm_running = false; return; } @@ -3682,14 +3699,6 @@ static inline enum tcpm_state unattached_state(struct tcpm_port *port) return SNK_UNATTACHED; } -static void tcpm_check_send_discover(struct tcpm_port *port) -{ - if ((port->data_role == TYPEC_HOST || port->negotiated_rev > PD_REV20) && - port->send_discover && port->pd_capable) - tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0); - port->send_discover = false; -} - static void tcpm_swap_complete(struct tcpm_port *port, int result) { if (port->swap_pending) { @@ -3926,7 +3935,18 @@ static void run_state_machine(struct tcpm_port *port) break; } - tcpm_check_send_discover(port); + /* + * 6.4.4.3.1 Discover Identity + * "The Discover Identity Command Shall only be sent to SOP when there is an + * Explicit Contract." + * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using + * port->explicit_contract to decide whether to send the command. + */ + if (port->explicit_contract) + mod_send_discover_delayed_work(port, 0); + else + port->send_discover = false; + /* * 6.3.5 * Sending ping messages is not necessary if @@ -4194,7 +4214,18 @@ static void run_state_machine(struct tcpm_port *port) break; } - tcpm_check_send_discover(port); + /* + * 6.4.4.3.1 Discover Identity + * "The Discover Identity Command Shall only be sent to SOP when there is an + * Explicit Contract." + * For now, this driver only supports SOP for DISCOVER_IDENTITY, thus using + * port->explicit_contract. + */ + if (port->explicit_contract) + mod_send_discover_delayed_work(port, 0); + else + port->send_discover = false; + power_supply_changed(port->psy); break; @@ -5288,6 +5319,29 @@ unlock: mutex_unlock(&port->lock); } +static void tcpm_send_discover_work(struct kthread_work *work) +{ + struct tcpm_port *port = container_of(work, struct tcpm_port, send_discover_work); + + mutex_lock(&port->lock); + /* No need to send DISCOVER_IDENTITY anymore */ + if (!port->send_discover) + goto unlock; + + /* Retry if the port is not idle */ + if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) { + mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); + goto unlock; + } + + /* Only send the Message if the port is host for PD rev2.0 */ + if (port->data_role == TYPEC_HOST || port->negotiated_rev > PD_REV20) + tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0); + +unlock: + mutex_unlock(&port->lock); +} + static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data) { struct tcpm_port *port = typec_get_drvdata(p); @@ -6093,6 +6147,14 @@ static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer) return HRTIMER_NORESTART; } +static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer) +{ + struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer); + + kthread_queue_work(port->wq, &port->send_discover_work); + return HRTIMER_NORESTART; +} + struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; @@ -6123,12 +6185,15 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) kthread_init_work(&port->vdm_state_machine, vdm_state_machine_work); kthread_init_work(&port->event_work, tcpm_pd_event_handler); kthread_init_work(&port->enable_frs, tcpm_enable_frs_work); + kthread_init_work(&port->send_discover_work, tcpm_send_discover_work); hrtimer_init(&port->state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); port->state_machine_timer.function = state_machine_timer_handler; hrtimer_init(&port->vdm_state_machine_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); port->vdm_state_machine_timer.function = vdm_state_machine_timer_handler; hrtimer_init(&port->enable_frs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); port->enable_frs_timer.function = enable_frs_timer_handler; + hrtimer_init(&port->send_discover_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + port->send_discover_timer.function = send_discover_timer_handler; spin_lock_init(&port->pd_event_lock); -- cgit v1.2.3 From f1fbd950b59b67bc5c202216c8e1c6ca8c99a3b4 Mon Sep 17 00:00:00 2001 From: Kyle Tso Date: Fri, 7 May 2021 14:23:00 +0800 Subject: usb: typec: tcpm: Fix wrong handling for Not_Supported in VDM AMS Not_Supported Message is acceptable in VDM AMS. Redirect the VDM state machine to VDM_STATE_DONE when receiving Not_Supported and finish the VDM AMS. Also, after the loop in vdm_state_machine_work, add more conditions of VDM states to clear the vdm_sm_running flag because those are all stopping states when leaving the loop. In addition, finish the VDM AMS if the port partner responds BUSY. Fixes: 8dea75e11380 ("usb: typec: tcpm: Protocol Error handling") Fixes: 8d3a0578ad1a ("usb: typec: tcpm: Respond Wait if VDM state machine is running") Reviewed-by: Guenter Roeck Signed-off-by: Kyle Tso Link: https://lore.kernel.org/r/20210507062300.1945009-3-kyletso@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index ae1e84252d38..db567e6fde92 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1897,7 +1897,6 @@ static void vdm_run_state_machine(struct tcpm_port *port) if (res < 0) { port->vdm_state = VDM_STATE_ERR_BUSY; - port->vdm_sm_running = false; return; } } @@ -1913,6 +1912,7 @@ static void vdm_run_state_machine(struct tcpm_port *port) port->vdo_data[0] = port->vdo_retry; port->vdo_count = 1; port->vdm_state = VDM_STATE_READY; + tcpm_ams_finish(port); break; case VDM_STATE_BUSY: port->vdm_state = VDM_STATE_ERR_TMOUT; @@ -1978,7 +1978,7 @@ static void vdm_state_machine_work(struct kthread_work *work) port->vdm_state != VDM_STATE_BUSY && port->vdm_state != VDM_STATE_SEND_MESSAGE); - if (port->vdm_state == VDM_STATE_ERR_TMOUT) + if (port->vdm_state < VDM_STATE_READY) port->vdm_sm_running = false; mutex_unlock(&port->lock); @@ -2569,6 +2569,16 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, port->sink_cap_done = true; tcpm_set_state(port, ready_state(port), 0); break; + case SRC_READY: + case SNK_READY: + if (port->vdm_state > VDM_STATE_READY) { + port->vdm_state = VDM_STATE_DONE; + if (tcpm_vdm_ams(port)) + tcpm_ams_finish(port); + mod_vdm_delayed_work(port, 0); + break; + } + fallthrough; default: tcpm_pd_handle_state(port, port->pwr_role == TYPEC_SOURCE ? -- cgit v1.2.3 From d9ff1096a840dddea3d5cfa2149ff7da9f499fb2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 4 May 2021 22:26:29 +0200 Subject: usb: musb: Fix an error message 'ret' is known to be 0 here. Initialize 'ret' with the expected error code before using it. Fixes: 0990366bab3c ("usb: musb: Add support for MediaTek musb controller") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/69f514dc7134e3c917cad208e73cc650cb9e2bd6.1620159879.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c index eebeadd26946..6b92d037d8fc 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -518,8 +518,8 @@ static int mtk_musb_probe(struct platform_device *pdev) glue->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); if (IS_ERR(glue->xceiv)) { - dev_err(dev, "fail to getting usb-phy %d\n", ret); ret = PTR_ERR(glue->xceiv); + dev_err(dev, "fail to getting usb-phy %d\n", ret); goto err_unregister_usb_phy; } -- cgit v1.2.3 From b813511135e8b84fa741afdfbab4937919100bef Mon Sep 17 00:00:00 2001 From: Abhijeet Rao Date: Wed, 12 May 2021 11:08:12 +0300 Subject: xhci-pci: Allow host runtime PM as default for Intel Alder Lake xHCI In the same way as Intel Tiger Lake TCSS (Type-C Subsystem) the Alder Lake TCSS xHCI needs to be runtime suspended whenever possible to allow the TCSS hardware block to enter D3cold and thus save energy. Cc: stable@vger.kernel.org Signed-off-by: Abhijeet Rao Signed-off-by: Nikunj A. Dadhania Signed-off-by: Azhar Shaikh Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210512080816.866037-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 5bbccc9a0179..a858add8436c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -57,6 +57,7 @@ #define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af #define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI 0x9a13 #define PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI 0x1138 +#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI 0x461e #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba @@ -243,7 +244,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI)) + pdev->device == PCI_DEVICE_ID_INTEL_MAPLE_RIDGE_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ALDER_LAKE_XHCI)) xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; if (pdev->vendor == PCI_VENDOR_ID_ETRON && -- cgit v1.2.3 From 9b6a126ae58d9edfdde2d5f2e87f7615ea5e0155 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Wed, 12 May 2021 11:08:13 +0300 Subject: xhci: Fix giving back cancelled URBs even if halted endpoint can't reset Commit 9ebf30007858 ("xhci: Fix halted endpoint at stop endpoint command completion") in 5.12 changes how cancelled URBs are given back. To cancel a URB xhci driver needs to stop the endpoint first. To clear a halted endpoint xhci driver needs to reset the endpoint. In rare cases when an endpoint halt (error) races with a endpoint stop we need to clear the reset before removing, and giving back the cancelled URB. The above change in 5.12 takes care of this, but it also relies on the reset endpoint completion handler to give back the cancelled URBs. There are cases when driver refuses to queue reset endpoint commands, for example when a link suddenly goes to an inactive error state. In this case the cancelled URB is never given back. Fix this by giving back the URB in the stop endpoint if queuing a reset endpoint command fails. Fixes: 9ebf30007858 ("xhci: Fix halted endpoint at stop endpoint command completion") CC: # 5.12 Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210512080816.866037-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 05c38dd3ee36..a8e4189277da 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -862,7 +862,7 @@ done: return ret; } -static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci, +static int xhci_handle_halted_endpoint(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, unsigned int stream_id, struct xhci_td *td, enum xhci_ep_reset_type reset_type) @@ -875,7 +875,7 @@ static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci, * Device will be reset soon to recover the link so don't do anything */ if (ep->vdev->flags & VDEV_PORT_ERROR) - return; + return -ENODEV; /* add td to cancelled list and let reset ep handler take care of it */ if (reset_type == EP_HARD_RESET) { @@ -888,16 +888,18 @@ static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci, if (ep->ep_state & EP_HALTED) { xhci_dbg(xhci, "Reset ep command already pending\n"); - return; + return 0; } err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); if (err) - return; + return err; ep->ep_state |= EP_HALTED; xhci_ring_cmd_db(xhci); + + return 0; } /* @@ -1014,6 +1016,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, struct xhci_td *td = NULL; enum xhci_ep_reset_type reset_type; struct xhci_command *command; + int err; if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { if (!xhci->devs[slot_id]) @@ -1058,7 +1061,10 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, td->status = -EPROTO; } /* reset ep, reset handler cleans up cancelled tds */ - xhci_handle_halted_endpoint(xhci, ep, 0, td, reset_type); + err = xhci_handle_halted_endpoint(xhci, ep, 0, td, + reset_type); + if (err) + break; xhci_stop_watchdog_timer_in_irq(xhci, ep); return; case EP_STATE_RUNNING: -- cgit v1.2.3 From dda32c00c9a0fa103b5d54ef72c477b7aa993679 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 12 May 2021 11:08:14 +0300 Subject: xhci: Do not use GFP_KERNEL in (potentially) atomic context 'xhci_urb_enqueue()' is passed a 'mem_flags' argument, because "URBs may be submitted in interrupt context" (see comment related to 'usb_submit_urb()' in 'drivers/usb/core/urb.c') So this flag should be used in all the calling chain. Up to now, 'xhci_check_maxpacket()' which is only called from 'xhci_urb_enqueue()', uses GFP_KERNEL. Be safe and pass the mem_flags to this function as well. Fixes: ddba5cd0aeff ("xhci: Use command structures when queuing commands on the command ring") Cc: Signed-off-by: Christophe JAILLET Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210512080816.866037-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ca9385d22f68..27283654ca08 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1514,7 +1514,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, * we need to issue an evaluate context command and wait on it. */ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index, struct urb *urb) + unsigned int ep_index, struct urb *urb, gfp_t mem_flags) { struct xhci_container_ctx *out_ctx; struct xhci_input_control_ctx *ctrl_ctx; @@ -1545,7 +1545,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, * changes max packet sizes. */ - command = xhci_alloc_command(xhci, true, GFP_KERNEL); + command = xhci_alloc_command(xhci, true, mem_flags); if (!command) return -ENOMEM; @@ -1639,7 +1639,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag */ if (urb->dev->speed == USB_SPEED_FULL) { ret = xhci_check_maxpacket(xhci, slot_id, - ep_index, urb); + ep_index, urb, mem_flags); if (ret < 0) { xhci_urb_free_priv(urb_priv); urb->hcpriv = NULL; -- cgit v1.2.3 From ca09b1bea63ab83f4cca3a2ae8bc4f597ec28851 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Wed, 12 May 2021 11:08:15 +0300 Subject: usb: xhci: Increase timeout for HC halt On some devices (specifically the SC8180x based Surface Pro X with QCOM04A6) HC halt / xhci_halt() times out during boot. Manually binding the xhci-hcd driver at some point later does not exhibit this behavior. To work around this, double XHCI_MAX_HALT_USEC, which also resolves this issue. Cc: Signed-off-by: Maximilian Luz Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210512080816.866037-5-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ext-caps.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index fa59b242cd51..e8af0a125f84 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -7,8 +7,9 @@ * Author: Sarah Sharp * Some code borrowed from the Linux EHCI driver. */ -/* Up to 16 ms to halt an HC */ -#define XHCI_MAX_HALT_USEC (16*1000) + +/* HC should halt within 16 ms, but use 32 ms as some hosts take longer */ +#define XHCI_MAX_HALT_USEC (32 * 1000) /* HC not running - set to 1 when run/stop bit is cleared. */ #define XHCI_STS_HALT (1<<0) -- cgit v1.2.3 From 3c128781d8da463761495aaf8898c9ecb4e71528 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Wed, 12 May 2021 11:08:16 +0300 Subject: xhci: Add reset resume quirk for AMD xhci controller. One of AMD xhci controller require reset on resume. Occasionally AMD xhci controller does not respond to Stop endpoint command. Once the issue happens controller goes into bad state and in that case controller needs to be reset. Cc: Signed-off-by: Sandeep Singh Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20210512080816.866037-6-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index a858add8436c..7bc18cf8042c 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -167,8 +167,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) (pdev->device == 0x15e0 || pdev->device == 0x15e1)) xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND; - if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5) + if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5) { xhci->quirks |= XHCI_DISABLE_SPARSE; + xhci->quirks |= XHCI_RESET_ON_RESUME; + } if (pdev->vendor == PCI_VENDOR_ID_AMD) xhci->quirks |= XHCI_TRUST_TX_LENGTH; -- cgit v1.2.3 From 12701ce524bc9b7c6345a2425208501fd2c62aad Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Mon, 10 May 2021 14:17:56 -0700 Subject: usb: typec: tcpm: Fix SINK_DISCOVERY current limit for Rp-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a regression introduced by 1373fefc6243 ("usb: typec: tcpm: Allow slow charging loops to comply to pSnkStby") When Source advertises Rp-default, tcpm would request 500mA when in SINK_DISCOVERY, Type-C spec advises the sink to follow BC1.2 current limits when Rp-default is advertised. [12750.503381] Requesting mux state 1, usb-role 2, orientation 1 [12750.503837] state change SNK_ATTACHED -> SNK_STARTUP [rev3 NONE_AMS] [12751.003891] state change SNK_STARTUP -> SNK_DISCOVERY [12751.003900] Setting voltage/current limit 5000 mV 500 mA This patch restores the behavior where the tcpm would request 0mA when Rp-default is advertised by the source. [   73.174252] Requesting mux state 1, usb-role 2, orientation 1 [   73.174749] state change SNK_ATTACHED -> SNK_STARTUP [rev3 NONE_AMS] [   73.674800] state change SNK_STARTUP -> SNK_DISCOVERY [   73.674808] Setting voltage/current limit 5000 mV 0 mA During SNK_DISCOVERY, Cap the current limit to PD_P_SNK_STDBY_MW / 5 only for slow_charger_loop case. Fixes: 1373fefc6243 ("usb: typec: tcpm: Allow slow charging loops to comply to pSnkStby") Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Badhri Jagan Sridharan Link: https://lore.kernel.org/r/20210510211756.3346954-1-badhri@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index db567e6fde92..72e4d63a2366 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4085,7 +4085,7 @@ static void run_state_machine(struct tcpm_port *port) if (port->vbus_present) { u32 current_lim = tcpm_get_current_limit(port); - if (port->slow_charger_loop || (current_lim > PD_P_SNK_STDBY_MW / 5)) + if (port->slow_charger_loop && (current_lim > PD_P_SNK_STDBY_MW / 5)) current_lim = PD_P_SNK_STDBY_MW / 5; tcpm_set_current_limit(port, current_lim, 5000); tcpm_set_charge(port, true); -- cgit v1.2.3 From 975f94c7d6c306b833628baa9aec3f79db1eb3a1 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 12 May 2021 10:07:38 +0800 Subject: usb: core: hub: fix race condition about TRSMRCY of resume This may happen if the port becomes resume status exactly when usb_port_resume() gets port status, it still need provide a TRSMCRY time before access the device. CC: Reported-by: Tianping Fang Acked-by: Alan Stern Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20210512020738.52961-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b2bc4b7c4289..fc7d6cdacf16 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3642,9 +3642,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) * sequence. */ status = hub_port_status(hub, port1, &portstatus, &portchange); - - /* TRSMRCY = 10 msec */ - msleep(10); } SuspendCleared: @@ -3659,6 +3656,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_SUSPEND); } + + /* TRSMRCY = 10 msec */ + msleep(10); } if (udev->persist_enabled) -- cgit v1.2.3