From f0d70eec2a16b8689b8764e49d5e465433fda5a6 Mon Sep 17 00:00:00 2001 From: leoliuoc Date: Thu, 24 Nov 2022 11:44:18 +0800 Subject: [PATCH] Fix mouse enumeration issue after wakeup from s4 zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I62V77 CVE: NA ---------------------------------------------------------------- There is a mouse attached in the xHCI port. Then plug out this mouse and plug to UHCI port after system go into hibernation. This mouse will random be identified after system wakeup from hibernation. During s4 wakeup, xHCI driver will cleanup this disconnect mouse (not connect to xHCI port). This will delay s4 wakeup process and UHCI root hub will goto auto suspend. Usb hub threads will be called to handle usb controller root hub's event after S4 wakeup completed. However, this are too many usb controllers to ensure EHCI and UHCI hub threads execute order. Once, EHCI giveback port to UHCI before UHCI hub event check. UHCI will try to enumerate this mouse with UHCI run bit not set. Which will cause control transfer fail during enumeration phase. In order to fix this issues, set UHCI root hub auto suspend delay value larger. UHCI run bit will be set after wakeup from S4 and mouse will be identified. Signed-off-by: leoliuoc --- drivers/usb/host/uhci-hcd.h | 1 + drivers/usb/host/uhci-hub.c | 5 ++++- drivers/usb/host/uhci-pci.c | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7f9f33c8c232..f2252f46c3e6 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -432,6 +432,7 @@ struct uhci_hcd { unsigned int big_endian_mmio:1; /* Big endian registers */ unsigned int big_endian_desc:1; /* Big endian descriptors */ unsigned int is_aspeed:1; /* Aspeed impl. workarounds */ + unsigned int auto_suspend_delay:1; /* delay root hub autosuspend*/ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 47106dd8ca7c..7ff2ba4deae5 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -217,7 +217,10 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* are any devices attached? */ if (!any_ports_active(uhci)) { uhci->rh_state = UHCI_RH_RUNNING_NODEVS; - uhci->auto_stop_time = jiffies + HZ; + if (!uhci->auto_suspend_delay) + uhci->auto_stop_time = jiffies + HZ; + else + uhci->auto_stop_time = jiffies + 3 * HZ; } break; diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 3c0d4c43b640..8dfd051b84b3 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -134,8 +134,10 @@ static int uhci_pci_init(struct usb_hcd *hcd) if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_INTEL) device_set_wakeup_capable(uhci_dev(uhci), true); - if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_ZHAOXIN) + if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_ZHAOXIN) { uhci->oc_low = 1; + uhci->auto_suspend_delay = 1; + } /* Set up pointers to PCI-specific functions */ uhci->reset_hc = uhci_pci_reset_hc; -- GitLab