Commit a448e4dc25303fe551e4dafe16c8c7c34f1b9d82
Committed by
Greg Kroah-Hartman
1 parent
879d38e6bc
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
EHCI: keep track of ports being resumed and indicate in hub_status_data
This patch (as1537) adds a bit-array to ehci-hcd for keeping track of which ports are undergoing a resume transition. If any of the bits are set when ehci_hub_status_data() is called, the routine will return a nonzero value even if no ports have any status changes pending. This will allow usbcore to handle races between root-hub suspend and port wakeup. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Sarah Sharp <sarah.a.sharp@linux.intel.com> CC: Chen Peter-B29397 <B29397@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 4 changed files with 23 additions and 15 deletions Side-by-side Diff
drivers/usb/host/ehci-hcd.c
... | ... | @@ -347,6 +347,8 @@ |
347 | 347 | if (ehci->debug) |
348 | 348 | dbgp_external_startup(); |
349 | 349 | |
350 | + ehci->port_c_suspend = ehci->suspended_ports = | |
351 | + ehci->resuming_ports = 0; | |
350 | 352 | return retval; |
351 | 353 | } |
352 | 354 | |
... | ... | @@ -939,6 +941,7 @@ |
939 | 941 | * like usb_port_resume() does. |
940 | 942 | */ |
941 | 943 | ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); |
944 | + set_bit(i, &ehci->resuming_ports); | |
942 | 945 | ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); |
943 | 946 | mod_timer(&hcd->rh_timer, ehci->reset_done[i]); |
944 | 947 | } |
drivers/usb/host/ehci-hub.c
... | ... | @@ -223,15 +223,10 @@ |
223 | 223 | * remote wakeup, we must fail the suspend. |
224 | 224 | */ |
225 | 225 | if (hcd->self.root_hub->do_remote_wakeup) { |
226 | - port = HCS_N_PORTS(ehci->hcs_params); | |
227 | - while (port--) { | |
228 | - if (ehci->reset_done[port] != 0) { | |
229 | - spin_unlock_irq(&ehci->lock); | |
230 | - ehci_dbg(ehci, "suspend failed because " | |
231 | - "port %d is resuming\n", | |
232 | - port + 1); | |
233 | - return -EBUSY; | |
234 | - } | |
226 | + if (ehci->resuming_ports) { | |
227 | + spin_unlock_irq(&ehci->lock); | |
228 | + ehci_dbg(ehci, "suspend failed because a port is resuming\n"); | |
229 | + return -EBUSY; | |
235 | 230 | } |
236 | 231 | } |
237 | 232 | |
238 | 233 | |
... | ... | @@ -554,16 +549,12 @@ |
554 | 549 | ehci_hub_status_data (struct usb_hcd *hcd, char *buf) |
555 | 550 | { |
556 | 551 | struct ehci_hcd *ehci = hcd_to_ehci (hcd); |
557 | - u32 temp, status = 0; | |
552 | + u32 temp, status; | |
558 | 553 | u32 mask; |
559 | 554 | int ports, i, retval = 1; |
560 | 555 | unsigned long flags; |
561 | 556 | u32 ppcd = 0; |
562 | 557 | |
563 | - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ | |
564 | - if (ehci->rh_state != EHCI_RH_RUNNING) | |
565 | - return 0; | |
566 | - | |
567 | 558 | /* init status to no-changes */ |
568 | 559 | buf [0] = 0; |
569 | 560 | ports = HCS_N_PORTS (ehci->hcs_params); |
... | ... | @@ -572,6 +563,11 @@ |
572 | 563 | retval++; |
573 | 564 | } |
574 | 565 | |
566 | + /* Inform the core about resumes-in-progress by returning | |
567 | + * a non-zero value even if there are no status changes. | |
568 | + */ | |
569 | + status = ehci->resuming_ports; | |
570 | + | |
575 | 571 | /* Some boards (mostly VIA?) report bogus overcurrent indications, |
576 | 572 | * causing massive log spam unless we completely ignore them. It |
577 | 573 | * may be relevant that VIA VT8235 controllers, where PORT_POWER is |
... | ... | @@ -846,6 +842,7 @@ |
846 | 842 | ehci_writel(ehci, |
847 | 843 | temp & ~(PORT_RWC_BITS | PORT_RESUME), |
848 | 844 | status_reg); |
845 | + clear_bit(wIndex, &ehci->resuming_ports); | |
849 | 846 | retval = handshake(ehci, status_reg, |
850 | 847 | PORT_RESUME, 0, 2000 /* 2msec */); |
851 | 848 | if (retval != 0) { |
... | ... | @@ -864,6 +861,7 @@ |
864 | 861 | ehci->reset_done[wIndex])) { |
865 | 862 | status |= USB_PORT_STAT_C_RESET << 16; |
866 | 863 | ehci->reset_done [wIndex] = 0; |
864 | + clear_bit(wIndex, &ehci->resuming_ports); | |
867 | 865 | |
868 | 866 | /* force reset to complete */ |
869 | 867 | ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), |
870 | 868 | |
... | ... | @@ -884,8 +882,10 @@ |
884 | 882 | ehci_readl(ehci, status_reg)); |
885 | 883 | } |
886 | 884 | |
887 | - if (!(temp & (PORT_RESUME|PORT_RESET))) | |
885 | + if (!(temp & (PORT_RESUME|PORT_RESET))) { | |
888 | 886 | ehci->reset_done[wIndex] = 0; |
887 | + clear_bit(wIndex, &ehci->resuming_ports); | |
888 | + } | |
889 | 889 | |
890 | 890 | /* transfer dedicated ports to the companion hc */ |
891 | 891 | if ((temp & PORT_CONNECT) && |
... | ... | @@ -920,6 +920,7 @@ |
920 | 920 | status |= USB_PORT_STAT_SUSPEND; |
921 | 921 | } else if (test_bit(wIndex, &ehci->suspended_ports)) { |
922 | 922 | clear_bit(wIndex, &ehci->suspended_ports); |
923 | + clear_bit(wIndex, &ehci->resuming_ports); | |
923 | 924 | ehci->reset_done[wIndex] = 0; |
924 | 925 | if (temp & PORT_PE) |
925 | 926 | set_bit(wIndex, &ehci->port_c_suspend); |
drivers/usb/host/ehci-tegra.c
... | ... | @@ -224,6 +224,7 @@ |
224 | 224 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); |
225 | 225 | /* start resume signalling */ |
226 | 226 | ehci_writel(ehci, temp | PORT_RESUME, status_reg); |
227 | + set_bit(wIndex-1, &ehci->resuming_ports); | |
227 | 228 | |
228 | 229 | spin_unlock_irqrestore(&ehci->lock, flags); |
229 | 230 | msleep(20); |
... | ... | @@ -236,6 +237,7 @@ |
236 | 237 | pr_err("%s: timeout waiting for SUSPEND\n", __func__); |
237 | 238 | |
238 | 239 | ehci->reset_done[wIndex-1] = 0; |
240 | + clear_bit(wIndex-1, &ehci->resuming_ports); | |
239 | 241 | |
240 | 242 | tegra->port_resuming = 1; |
241 | 243 | goto done; |
drivers/usb/host/ehci.h
... | ... | @@ -117,6 +117,8 @@ |
117 | 117 | the change-suspend feature turned on */ |
118 | 118 | unsigned long suspended_ports; /* which ports are |
119 | 119 | suspended */ |
120 | + unsigned long resuming_ports; /* which ports have | |
121 | + started to resume */ | |
120 | 122 | |
121 | 123 | /* per-HC memory pools (could be per-bus, but ...) */ |
122 | 124 | struct dma_pool *qh_pool; /* qh per active urb */ |