Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Fix ehci infinite suspend-resume loop issue in zhaoxin

In zhaoxin platform, some ehci projects will latch a wakeup signal
internal when plug in a device on port during system S0. This wakeup
signal will turn on when ehci runtime suspend, which will trigger a
system control interrupt that will resume ehci back to D0. As no
device connect, ehci will be set to runtime suspend and turn on the
internal latched wakeup signal again. It will cause a suspend-resume
loop and generate system control interrupt continuously.

Fixed this issue by clear wakeup signal latched in ehci internal when
ehci resume callback is called.

Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Weitao Wang <WeitaoWang-oc@zhaoxin.com>
Link: https://lore.kernel.org/r/20220324121735.3803-1-WeitaoWang-oc@zhaoxin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Weitao Wango and committed by
Greg Kroah-Hartman
f085bd4b 8d084b2e

+28
+23
drivers/usb/host/ehci-hcd.c
··· 1103 1103 1104 1104 #ifdef CONFIG_PM 1105 1105 1106 + /* Clear wakeup signal locked in zhaoxin platform when device plug in. */ 1107 + static void ehci_zx_wakeup_clear(struct ehci_hcd *ehci) 1108 + { 1109 + u32 __iomem *reg = &ehci->regs->port_status[4]; 1110 + u32 t1 = ehci_readl(ehci, reg); 1111 + 1112 + t1 &= (u32)~0xf0000; 1113 + t1 |= PORT_TEST_FORCE; 1114 + ehci_writel(ehci, t1, reg); 1115 + t1 = ehci_readl(ehci, reg); 1116 + msleep(1); 1117 + t1 &= (u32)~0xf0000; 1118 + ehci_writel(ehci, t1, reg); 1119 + ehci_readl(ehci, reg); 1120 + msleep(1); 1121 + t1 = ehci_readl(ehci, reg); 1122 + ehci_writel(ehci, t1 | PORT_CSC, reg); 1123 + ehci_readl(ehci, reg); 1124 + } 1125 + 1106 1126 /* suspend/resume, section 4.3 */ 1107 1127 1108 1128 /* These routines handle the generic parts of controller suspend/resume */ ··· 1173 1153 1174 1154 if (ehci->shutdown) 1175 1155 return 0; /* Controller is dead */ 1156 + 1157 + if (ehci->zx_wakeup_clear_needed) 1158 + ehci_zx_wakeup_clear(ehci); 1176 1159 1177 1160 /* 1178 1161 * If CF is still set and reset isn't forced
+4
drivers/usb/host/ehci-pci.c
··· 231 231 ehci->is_aspeed = 1; 232 232 } 233 233 break; 234 + case PCI_VENDOR_ID_ZHAOXIN: 235 + if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x90) 236 + ehci->zx_wakeup_clear_needed = 1; 237 + break; 234 238 } 235 239 236 240 /* optional debug port, normally in the first BAR */
+1
drivers/usb/host/ehci.h
··· 220 220 unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ 221 221 unsigned spurious_oc:1; 222 222 unsigned is_aspeed:1; 223 + unsigned zx_wakeup_clear_needed:1; 223 224 224 225 /* required for usb32 quirk */ 225 226 #define OHCI_CTRL_HCFS (3 << 6)