From 078dfef931523b64c1904517a1a6f04511fe42a2 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Thu, 3 Feb 2022 15:20:11 -0600 Subject: [PATCH 1/3] usb: ehci-mx6: Enable OTG detection on imx8mm and imx8mn The imx8mm and imx8mn appear compatible with imx7d-usb flags in the OTG driver. If the dr_mode is defined as host or peripheral, the device appears to operate correctly, however the auto host/peripheral detection results in an error. The solution isn't just adding checks for imx8mm and imx8mn to the check for imx7, because the USB clock needs to be running to read from the USBNC_PHY_STATUS_OFFSET register or it will hang. Marek requested that I not enable the clocks in ehci_usb_of_to_plat, so I modified that function to return an unknown state if the device tree does not explicitly state whether it is a host or a peripheral. When the driver probes, it looks to see if it's in the unknown state, and only then will it read the register to auto-detect. Signed-off-by: Adam Ford Tested-by: Tim Harvey --- drivers/usb/host/ehci-mx6.c | 23 ++++++++++++++++++----- include/usb.h | 3 ++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 1bd6147c76a..060b02accc5 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -543,7 +543,7 @@ static int ehci_usb_phy_mode(struct udevice *dev) plat->init_type = USB_INIT_DEVICE; else plat->init_type = USB_INIT_HOST; - } else if (is_mx7()) { + } else if (is_mx7() || is_imx8mm() || is_imx8mn()) { phy_status = (void __iomem *)(addr + USBNC_PHY_STATUS_OFFSET); val = readl(phy_status); @@ -573,9 +573,8 @@ static int ehci_usb_of_to_plat(struct udevice *dev) case USB_DR_MODE_PERIPHERAL: plat->init_type = USB_INIT_DEVICE; break; - case USB_DR_MODE_OTG: - case USB_DR_MODE_UNKNOWN: - return ehci_usb_phy_mode(dev); + default: + plat->init_type = USB_INIT_UNKNOWN; }; return 0; @@ -677,6 +676,20 @@ static int ehci_usb_probe(struct udevice *dev) mdelay(1); #endif + /* + * If the device tree didn't specify host or device, + * the default is USB_INIT_UNKNOWN, so we need to check + * the register. For imx8mm and imx8mn, the clocks need to be + * running first, so we defer the check until they are. + */ + if (priv->init_type == USB_INIT_UNKNOWN) { + ret = ehci_usb_phy_mode(dev); + if (ret) + goto err_clk; + else + priv->init_type = plat->init_type; + } + #if CONFIG_IS_ENABLED(DM_REGULATOR) ret = device_get_supply_regulator(dev, "vbus-supply", &priv->vbus_supply); @@ -741,8 +754,8 @@ err_regulator: #if CONFIG_IS_ENABLED(DM_REGULATOR) if (priv->vbus_supply) regulator_set_enable(priv->vbus_supply, false); -err_clk: #endif +err_clk: #if CONFIG_IS_ENABLED(CLK) clk_disable(&priv->clk); #else diff --git a/include/usb.h b/include/usb.h index f032de8af93..7e3796bd5ba 100644 --- a/include/usb.h +++ b/include/usb.h @@ -163,7 +163,8 @@ struct int_queue; */ enum usb_init_type { USB_INIT_HOST, - USB_INIT_DEVICE + USB_INIT_DEVICE, + USB_INIT_UNKNOWN, }; /********************************************************************** From 96991e652f541323a03c5b7e075d54a117091618 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 10 Feb 2022 15:13:14 -0600 Subject: [PATCH 2/3] console: usb: kbd: Limit poll frequency to improve performance Using the XHCI driver, the function `usb_kbd_poll_for_event` takes 30-40ms to run. The exact time is dependent on the polling interval the keyboard requests in its descriptor, and likely cannot be significantly reduced without major rework to the XHCI driver. The U-Boot EFI console service sets a timer to poll the keyboard every 5 microseconds, and this timer is checked every time a block is read off disk. The net effect is that, on my system, loading a ~40MiB kernel and initrd takes about 62 seconds with a slower keyboard and 53 seconds with a faster one, with the vast majority of the time spent polling the keyboard. To solve this problem, this patch adds a 20ms delay between consecutive calls to `usb_kbd_poll_for_event`. This is sufficient to reduce the total loading time to under half a second for both keyboards, and does not impact the perceived keystroke latency. Signed-off-by: Thomas Watson --- common/usb_kbd.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/common/usb_kbd.c b/common/usb_kbd.c index afad260d3dc..352d86fb2ec 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -17,6 +17,9 @@ #include #include #include +#ifdef CONFIG_SANDBOX +#include +#endif #include @@ -118,7 +121,7 @@ struct usb_kbd_pdata { extern int __maybe_unused net_busy_flag; /* The period of time between two calls of usb_kbd_testc(). */ -static unsigned long __maybe_unused kbd_testc_tms; +static unsigned long kbd_testc_tms; /* Puts character in the queue and sets up the in and out pointer. */ static void usb_kbd_put_queue(struct usb_kbd_pdata *data, u8 c) @@ -394,21 +397,39 @@ static int usb_kbd_testc(struct stdio_dev *sdev) struct usb_device *usb_kbd_dev; struct usb_kbd_pdata *data; + /* + * Polling the keyboard for an event can take dozens of milliseconds. + * Add a delay between polls to avoid blocking activity which polls + * rapidly, like the UEFI console timer. + */ + unsigned long poll_delay = CONFIG_SYS_HZ / 50; + #ifdef CONFIG_CMD_NET /* * If net_busy_flag is 1, NET transfer is running, * then we check key-pressed every second (first check may be * less than 1 second) to improve TFTP booting performance. */ - if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ)) - return 0; - kbd_testc_tms = get_timer(0); + if (net_busy_flag) + poll_delay = CONFIG_SYS_HZ; #endif + +#ifdef CONFIG_SANDBOX + /* + * Skip delaying polls if a test requests it. + */ + if (state_get_skip_delays()) + poll_delay = 0; +#endif + dev = stdio_get_by_name(sdev->name); usb_kbd_dev = (struct usb_device *)dev->priv; data = usb_kbd_dev->privptr; - usb_kbd_poll_for_event(usb_kbd_dev); + if (get_timer(kbd_testc_tms) >= poll_delay) { + usb_kbd_poll_for_event(usb_kbd_dev); + kbd_testc_tms = get_timer(0); + } return !(data->usb_in_pointer == data->usb_out_pointer); } From 1f54025d70c4c9e6ec8d82d8b69b0d66a7bbbdc1 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 28 Jan 2022 04:39:09 +0100 Subject: [PATCH 3/3] usb: gadget: ci: Avoid null pointer dereference The ci_req->hw_buf can be NULL, test whether it is and if so, avoid accessing it. Else, the system may crash. Signed-off-by: Marek Vasut Cc: Peter Chen Cc: Li Jun Cc: Peng Fan --- drivers/usb/gadget/ci_udc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 226a9e6d671..542684c1c30 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -402,6 +402,9 @@ align: flush: hwaddr = (unsigned long)ci_req->hw_buf; + if (!hwaddr) + return 0; + aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN); flush_dcache_range(hwaddr, hwaddr + aligned_used_len); @@ -415,7 +418,7 @@ static void ci_debounce(struct ci_req *ci_req, int in) unsigned long hwaddr = (unsigned long)ci_req->hw_buf; uint32_t aligned_used_len; - if (in) + if (in || !hwaddr) return; aligned_used_len = roundup(req->actual, ARCH_DMA_MINALIGN);