aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/uhci-hcd.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-04-09 17:27:32 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:43 -0400
commitc8f4fe4358c5e0a79b4bd47b814d19f1d1d06f21 (patch)
tree0c12fec97ac524e77489d3e8460bd9bb4817c0d5 /drivers/usb/host/uhci-hcd.c
parentf5946f8220a866dcdb8edc6abe23c1443e252425 (diff)
[PATCH] USB UHCI: Add root hub states
This patch starts making some serious changes to the UHCI driver. There's a set of private states for the root hub, and the internal routines for suspending and resuming work completely differently, with transitions based on the new states. Now the driver distinguishes between a privately auto-stopped state and a publicly suspended state, and it will properly suspend controllers with broken resume-detect interrupts instead of resetting them. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/uhci-hcd.c')
-rw-r--r--drivers/usb/host/uhci-hcd.c285
1 files changed, 149 insertions, 136 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index c17bd7ebc021..57b36dcea5d0 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -64,7 +64,7 @@
64/* 64/*
65 * Version Information 65 * Version Information
66 */ 66 */
67#define DRIVER_VERSION "v2.2" 67#define DRIVER_VERSION "v2.3"
68#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ 68#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
69Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ 69Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
70Alan Stern" 70Alan Stern"
@@ -109,33 +109,6 @@ static inline void restart_timer(struct uhci_hcd *uhci)
109#include "uhci-debug.c" 109#include "uhci-debug.c"
110#include "uhci-q.c" 110#include "uhci-q.c"
111 111
112static int suspend_allowed(struct uhci_hcd *uhci)
113{
114 unsigned long io_addr = uhci->io_addr;
115 int i;
116
117 if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
118 return 1;
119
120 /* Some of Intel's USB controllers have a bug that causes false
121 * resume indications if any port has an over current condition.
122 * To prevent problems, we will not allow a global suspend if
123 * any ports are OC.
124 *
125 * Some motherboards using Intel's chipsets (but not using all
126 * the USB ports) appear to hardwire the over current inputs active
127 * to disable the USB ports.
128 */
129
130 /* check for over current condition on any port */
131 for (i = 0; i < uhci->rh_numports; i++) {
132 if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC)
133 return 0;
134 }
135
136 return 1;
137}
138
139static void reset_hc(struct uhci_hcd *uhci) 112static void reset_hc(struct uhci_hcd *uhci)
140{ 113{
141 unsigned long io_addr = uhci->io_addr; 114 unsigned long io_addr = uhci->io_addr;
@@ -147,7 +120,6 @@ static void reset_hc(struct uhci_hcd *uhci)
147 outw(0, uhci->io_addr + USBINTR); 120 outw(0, uhci->io_addr + USBINTR);
148 121
149 /* Global reset for 50ms */ 122 /* Global reset for 50ms */
150 uhci->state = UHCI_RESET;
151 outw(USBCMD_GRESET, io_addr + USBCMD); 123 outw(USBCMD_GRESET, io_addr + USBCMD);
152 msleep(50); 124 msleep(50);
153 outw(0, io_addr + USBCMD); 125 outw(0, io_addr + USBCMD);
@@ -156,63 +128,130 @@ static void reset_hc(struct uhci_hcd *uhci)
156 msleep(10); 128 msleep(10);
157 uhci->resume_detect = 0; 129 uhci->resume_detect = 0;
158 uhci->is_stopped = UHCI_IS_STOPPED; 130 uhci->is_stopped = UHCI_IS_STOPPED;
131 uhci->rh_state = UHCI_RH_RESET;
159} 132}
160 133
161static void suspend_hc(struct uhci_hcd *uhci) 134static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
162{ 135{
163 unsigned long io_addr = uhci->io_addr; 136 int port;
164 137
165 dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); 138 switch (to_pci_dev(uhci_dev(uhci))->vendor) {
166 uhci->state = UHCI_SUSPENDED; 139 default:
167 uhci->resume_detect = 0; 140 break;
168 outw(USBCMD_EGSM, io_addr + USBCMD); 141
142 case PCI_VENDOR_ID_GENESYS:
143 /* Genesys Logic's GL880S controllers don't generate
144 * resume-detect interrupts.
145 */
146 return 1;
147
148 case PCI_VENDOR_ID_INTEL:
149 /* Some of Intel's USB controllers have a bug that causes
150 * resume-detect interrupts if any port has an over-current
151 * condition. To make matters worse, some motherboards
152 * hardwire unused USB ports' over-current inputs active!
153 * To prevent problems, we will not enable resume-detect
154 * interrupts if any ports are OC.
155 */
156 for (port = 0; port < uhci->rh_numports; ++port) {
157 if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
158 USBPORTSC_OC)
159 return 1;
160 }
161 break;
162 }
163 return 0;
164}
165
166static void suspend_hc(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
167__releases(uhci->lock)
168__acquires(uhci->lock)
169{
170 int auto_stop;
171 int int_enable;
172
173 auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
174 dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
175 (auto_stop ? " (auto-stop)" : ""));
176
177 /* If we get a suspend request when we're already auto-stopped
178 * then there's nothing to do.
179 */
180 if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
181 uhci->rh_state = new_state;
182 return;
183 }
184
185 /* Enable resume-detect interrupts if they work.
186 * Then enter Global Suspend mode, still configured.
187 */
188 int_enable = (resume_detect_interrupts_are_broken(uhci) ?
189 0 : USBINTR_RESUME);
190 outw(int_enable, uhci->io_addr + USBINTR);
191 outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
192 udelay(5);
193
194 /* If we're auto-stopping then no devices have been attached
195 * for a while, so there shouldn't be any active URBs and the
196 * controller should stop after a few microseconds. Otherwise
197 * we will give the controller one frame to stop.
198 */
199 if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
200 uhci->rh_state = UHCI_RH_SUSPENDING;
201 spin_unlock_irq(&uhci->lock);
202 msleep(1);
203 spin_lock_irq(&uhci->lock);
204 }
205 if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
206 dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
169 207
170 /* FIXME: Wait for the controller to actually stop */
171 uhci_get_current_frame_number(uhci); 208 uhci_get_current_frame_number(uhci);
209 smp_wmb();
210
211 uhci->rh_state = new_state;
172 uhci->is_stopped = UHCI_IS_STOPPED; 212 uhci->is_stopped = UHCI_IS_STOPPED;
213 uhci->resume_detect = 0;
173 214
174 uhci_scan_schedule(uhci, NULL); 215 uhci_scan_schedule(uhci, NULL);
175} 216}
176 217
177static void wakeup_hc(struct uhci_hcd *uhci) 218static void wakeup_hc(struct uhci_hcd *uhci)
219__releases(uhci->lock)
220__acquires(uhci->lock)
178{ 221{
179 unsigned long io_addr = uhci->io_addr; 222 dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
223 uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
224 " (auto-start)" : "");
180 225
181 switch (uhci->state) { 226 /* If we are auto-stopped then no devices are attached so there's
182 case UHCI_SUSPENDED: /* Start the resume */ 227 * no need for wakeup signals. Otherwise we send Global Resume
183 dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); 228 * for 20 ms.
184 229 */
185 /* Global resume for >= 20ms */ 230 if (uhci->rh_state == UHCI_RH_SUSPENDED) {
186 outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); 231 uhci->rh_state = UHCI_RH_RESUMING;
187 uhci->state = UHCI_RESUMING_1; 232 outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
188 uhci->state_end = jiffies + msecs_to_jiffies(20); 233 uhci->io_addr + USBCMD);
189 uhci->is_stopped = 0; 234 spin_unlock_irq(&uhci->lock);
190 break; 235 msleep(20);
236 spin_lock_irq(&uhci->lock);
191 237
192 case UHCI_RESUMING_1: /* End global resume */ 238 /* End Global Resume and wait for EOP to be sent */
193 uhci->state = UHCI_RESUMING_2; 239 outw(USBCMD_CF, uhci->io_addr + USBCMD);
194 outw(0, io_addr + USBCMD); 240 udelay(4);
195 /* Falls through */ 241 if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
196 242 dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
197 case UHCI_RESUMING_2: /* Wait for EOP to be sent */ 243 }
198 if (inw(io_addr + USBCMD) & USBCMD_FGR)
199 break;
200
201 /* Run for at least 1 second, and
202 * mark it configured with a 64-byte max packet */
203 uhci->state = UHCI_RUNNING_GRACE;
204 uhci->state_end = jiffies + HZ;
205 outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP,
206 io_addr + USBCMD);
207 break;
208 244
209 case UHCI_RUNNING_GRACE: /* Now allowed to suspend */ 245 uhci->rh_state = UHCI_RH_RUNNING;
210 uhci->state = UHCI_RUNNING; 246 uhci->is_stopped = 0;
211 break; 247 smp_wmb();
212 248
213 default: 249 /* Mark it configured and running with a 64-byte max packet.
214 break; 250 * All interrupts are enabled, even though RD won't do anything.
215 } 251 */
252 outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
253 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
254 uhci->io_addr + USBINTR);
216} 255}
217 256
218static int start_hc(struct uhci_hcd *uhci) 257static int start_hc(struct uhci_hcd *uhci)
@@ -249,49 +288,40 @@ static int start_hc(struct uhci_hcd *uhci)
249 outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); 288 outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
250 289
251 /* Run and mark it configured with a 64-byte max packet */ 290 /* Run and mark it configured with a 64-byte max packet */
252 uhci->state = UHCI_RUNNING_GRACE; 291 uhci->rh_state = UHCI_RH_RUNNING;
253 uhci->state_end = jiffies + HZ;
254 outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); 292 outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
255 uhci->is_stopped = 0; 293 uhci->is_stopped = 0;
256 294
257 return 0; 295 return 0;
258} 296}
259 297
260static void hc_state_transitions(struct uhci_hcd *uhci) 298static void rh_state_transitions(struct uhci_hcd *uhci)
261{ 299{
262 switch (uhci->state) { 300 switch (uhci->rh_state) {
263 case UHCI_RUNNING: 301 case UHCI_RH_RUNNING:
264 302 /* are any devices attached? */
265 /* global suspend if nothing connected for 1 second */ 303 if (!any_ports_active(uhci)) {
266 if (!any_ports_active(uhci) && suspend_allowed(uhci)) { 304 uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
267 uhci->state = UHCI_SUSPENDING_GRACE; 305 uhci->auto_stop_time = jiffies + HZ;
268 uhci->state_end = jiffies + HZ; 306 }
269 } 307 break;
270 break; 308
271 309 case UHCI_RH_RUNNING_NODEVS:
272 case UHCI_SUSPENDING_GRACE: 310 /* auto-stop if nothing connected for 1 second */
273 if (any_ports_active(uhci)) 311 if (any_ports_active(uhci))
274 uhci->state = UHCI_RUNNING; 312 uhci->rh_state = UHCI_RH_RUNNING;
275 else if (time_after_eq(jiffies, uhci->state_end)) 313 else if (time_after_eq(jiffies, uhci->auto_stop_time))
276 suspend_hc(uhci); 314 suspend_hc(uhci, UHCI_RH_AUTO_STOPPED);
277 break; 315 break;
278 316
279 case UHCI_SUSPENDED: 317 case UHCI_RH_AUTO_STOPPED:
280 318 /* wakeup if requested by a device */
281 /* wakeup if requested by a device */ 319 if (uhci->resume_detect)
282 if (uhci->resume_detect) 320 wakeup_hc(uhci);
283 wakeup_hc(uhci); 321 break;
284 break; 322
285 323 default:
286 case UHCI_RESUMING_1: 324 break;
287 case UHCI_RESUMING_2:
288 case UHCI_RUNNING_GRACE:
289 if (time_after_eq(jiffies, uhci->state_end))
290 wakeup_hc(uhci);
291 break;
292
293 default:
294 break;
295 } 325 }
296} 326}
297 327
@@ -305,8 +335,8 @@ static void stall_callback(unsigned long _uhci)
305 check_fsbr(uhci); 335 check_fsbr(uhci);
306 336
307 /* Poll for and perform state transitions */ 337 /* Poll for and perform state transitions */
308 hc_state_transitions(uhci); 338 rh_state_transitions(uhci);
309 if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) 339 if (unlikely(uhci->suspended_ports))
310 uhci_check_ports(uhci); 340 uhci_check_ports(uhci);
311 341
312 restart_timer(uhci); 342 restart_timer(uhci);
@@ -336,7 +366,8 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
336 if (status & USBSTS_HCPE) 366 if (status & USBSTS_HCPE)
337 dev_err(uhci_dev(uhci), "host controller process " 367 dev_err(uhci_dev(uhci), "host controller process "
338 "error, something bad happened!\n"); 368 "error, something bad happened!\n");
339 if ((status & USBSTS_HCH) && uhci->state > 0) { 369 if ((status & USBSTS_HCH) &&
370 uhci->rh_state >= UHCI_RH_RUNNING) {
340 dev_err(uhci_dev(uhci), "host controller halted, " 371 dev_err(uhci_dev(uhci), "host controller halted, "
341 "very bad!\n"); 372 "very bad!\n");
342 /* FIXME: Reset the controller, fix the offending TD */ 373 /* FIXME: Reset the controller, fix the offending TD */
@@ -683,17 +714,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
683 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 714 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
684 715
685 spin_lock_irq(&uhci->lock); 716 spin_lock_irq(&uhci->lock);
686 717 suspend_hc(uhci, UHCI_RH_SUSPENDED);
687 /* Don't try to suspend broken motherboards, reset instead */
688 if (suspend_allowed(uhci))
689 suspend_hc(uhci);
690 else {
691 spin_unlock_irq(&uhci->lock);
692 reset_hc(uhci);
693 spin_lock_irq(&uhci->lock);
694 uhci_scan_schedule(uhci, NULL);
695 }
696
697 spin_unlock_irq(&uhci->lock); 718 spin_unlock_irq(&uhci->lock);
698 return 0; 719 return 0;
699} 720}
@@ -701,13 +722,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
701static int uhci_resume(struct usb_hcd *hcd) 722static int uhci_resume(struct usb_hcd *hcd)
702{ 723{
703 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 724 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
704 int rc;
705
706 pci_set_master(to_pci_dev(uhci_dev(uhci)));
707 725
708 spin_lock_irq(&uhci->lock); 726 spin_lock_irq(&uhci->lock);
709 727 if (uhci->rh_state == UHCI_RH_SUSPENDED) {
710 if (uhci->state == UHCI_SUSPENDED) {
711 728
712 /* 729 /*
713 * Some systems don't maintain the UHCI register values 730 * Some systems don't maintain the UHCI register values
@@ -721,19 +738,13 @@ static int uhci_resume(struct usb_hcd *hcd)
721 outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); 738 outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
722 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | 739 outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
723 USBINTR_SP, uhci->io_addr + USBINTR); 740 USBINTR_SP, uhci->io_addr + USBINTR);
724 uhci->resume_detect = 1;
725 pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 741 pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
726 USBLEGSUP_DEFAULT); 742 USBLEGSUP_DEFAULT);
727 } else { 743 wakeup_hc(uhci);
728 spin_unlock_irq(&uhci->lock);
729 reset_hc(uhci);
730 if ((rc = start_hc(uhci)) != 0)
731 return rc;
732 spin_lock_irq(&uhci->lock);
733 } 744 }
734 hcd->state = HC_STATE_RUNNING;
735
736 spin_unlock_irq(&uhci->lock); 745 spin_unlock_irq(&uhci->lock);
746
747 hcd->state = HC_STATE_RUNNING;
737 return 0; 748 return 0;
738} 749}
739#endif 750#endif
@@ -750,13 +761,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
750static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) 761static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
751{ 762{
752 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 763 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
753 int frame_number;
754 unsigned long flags; 764 unsigned long flags;
765 int is_stopped;
766 int frame_number;
755 767
756 /* Minimize latency by avoiding the spinlock */ 768 /* Minimize latency by avoiding the spinlock */
757 local_irq_save(flags); 769 local_irq_save(flags);
758 rmb(); 770 is_stopped = uhci->is_stopped;
759 frame_number = (uhci->is_stopped ? uhci->frame_number : 771 smp_rmb();
772 frame_number = (is_stopped ? uhci->frame_number :
760 inw(uhci->io_addr + USBFRNUM)); 773 inw(uhci->io_addr + USBFRNUM));
761 local_irq_restore(flags); 774 local_irq_restore(flags);
762 return frame_number; 775 return frame_number;