aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:23:16 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:56:48 -0400
commit43fe3a99d9caf10b25f9c596e9854cdae30db418 (patch)
tree596812dcd61ba9cbffe0e837d53dd3a2232ad214 /drivers/usb/host/ehci-hcd.c
parentc4f3476436f7452b97c8accb5dd7d53219a11a3f (diff)
USB: EHCI: resolve some unlikely races
This patch (as1589) resolves some unlikely races involving system shutdown or controller death in ehci-hcd: Shutdown races with both root-hub resume and controller resume. Controller death races with root-hub suspend. A new bitflag is added to indicate that the controller has been shut down (whether for system shutdown or because it died). Tests are added in the suspend and resume pathways to avoid reactivating the controller after any sort of shutdown. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r--drivers/usb/host/ehci-hcd.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ac4c8ddde20a..e44ca5453aa2 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -343,6 +343,7 @@ static void ehci_shutdown(struct usb_hcd *hcd)
343 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 343 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
344 344
345 spin_lock_irq(&ehci->lock); 345 spin_lock_irq(&ehci->lock);
346 ehci->shutdown = true;
346 ehci->rh_state = EHCI_RH_STOPPING; 347 ehci->rh_state = EHCI_RH_STOPPING;
347 ehci->enabled_hrtimer_events = 0; 348 ehci->enabled_hrtimer_events = 0;
348 spin_unlock_irq(&ehci->lock); 349 spin_unlock_irq(&ehci->lock);
@@ -823,6 +824,7 @@ dead:
823 usb_hc_died(hcd); 824 usb_hc_died(hcd);
824 825
825 /* Don't let the controller do anything more */ 826 /* Don't let the controller do anything more */
827 ehci->shutdown = true;
826 ehci->rh_state = EHCI_RH_STOPPING; 828 ehci->rh_state = EHCI_RH_STOPPING;
827 ehci->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); 829 ehci->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
828 ehci_writel(ehci, ehci->command, &ehci->regs->command); 830 ehci_writel(ehci, ehci->command, &ehci->regs->command);
@@ -1129,6 +1131,9 @@ static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
1129 /* Mark hardware accessible again as we are back to full power by now */ 1131 /* Mark hardware accessible again as we are back to full power by now */
1130 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 1132 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
1131 1133
1134 if (ehci->shutdown)
1135 return 0; /* Controller is dead */
1136
1132 /* 1137 /*
1133 * If CF is still set and we aren't resuming from hibernation 1138 * If CF is still set and we aren't resuming from hibernation
1134 * then we maintained suspend power. 1139 * then we maintained suspend power.
@@ -1139,10 +1144,17 @@ static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
1139 int mask = INTR_MASK; 1144 int mask = INTR_MASK;
1140 1145
1141 ehci_prepare_ports_for_controller_resume(ehci); 1146 ehci_prepare_ports_for_controller_resume(ehci);
1147
1148 spin_lock_irq(&ehci->lock);
1149 if (ehci->shutdown)
1150 goto skip;
1151
1142 if (!hcd->self.root_hub->do_remote_wakeup) 1152 if (!hcd->self.root_hub->do_remote_wakeup)
1143 mask &= ~STS_PCD; 1153 mask &= ~STS_PCD;
1144 ehci_writel(ehci, mask, &ehci->regs->intr_enable); 1154 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
1145 ehci_readl(ehci, &ehci->regs->intr_enable); 1155 ehci_readl(ehci, &ehci->regs->intr_enable);
1156 skip:
1157 spin_unlock_irq(&ehci->lock);
1146 return 0; 1158 return 0;
1147 } 1159 }
1148 1160
@@ -1154,14 +1166,20 @@ static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
1154 (void) ehci_halt(ehci); 1166 (void) ehci_halt(ehci);
1155 (void) ehci_reset(ehci); 1167 (void) ehci_reset(ehci);
1156 1168
1169 spin_lock_irq(&ehci->lock);
1170 if (ehci->shutdown)
1171 goto skip;
1172
1157 ehci_writel(ehci, ehci->command, &ehci->regs->command); 1173 ehci_writel(ehci, ehci->command, &ehci->regs->command);
1158 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); 1174 ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
1159 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ 1175 ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
1160 1176
1177 ehci->rh_state = EHCI_RH_SUSPENDED;
1178 spin_unlock_irq(&ehci->lock);
1179
1161 /* here we "know" root ports should always stay powered */ 1180 /* here we "know" root ports should always stay powered */
1162 ehci_port_power(ehci, 1); 1181 ehci_port_power(ehci, 1);
1163 1182
1164 ehci->rh_state = EHCI_RH_SUSPENDED;
1165 return 1; 1183 return 1;
1166} 1184}
1167 1185