aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorStuart_Hayes@Dell.com <Stuart_Hayes@Dell.com>2007-05-03 11:58:49 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:29:45 -0400
commit196705c9bbc03540429b0f7cf9ee35c2f928a534 (patch)
tree37ddc23737bced60a8defc52f643f362e2744908 /drivers/usb/host
parentec22559e0b7a05283a3413bda5d177e42c950e23 (diff)
USB: EHCI cpufreq fix
EHCI controllers that don't cache enough microframes can get MMF errors when CPU frequency changes occur between the start and completion of split interrupt transactions, due to delays in reading main memory (caused by CPU cache snoop delays). This patch adds a cpufreq notifier to the EHCI driver that will inactivate split interrupt transactions during frequency transitions. It was tested on Intel ICH7 and Serverworks/Broadcom HT1000 EHCI controllers. Signed-off-by: Stuart Hayes <stuart_hayes@dell.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c67
-rw-r--r--drivers/usb/host/ehci-mem.c3
-rw-r--r--drivers/usb/host/ehci-q.c4
-rw-r--r--drivers/usb/host/ehci-sched.c129
-rw-r--r--drivers/usb/host/ehci.h11
5 files changed, 214 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 099aff64f536..566badb05b34 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -273,6 +273,58 @@ static void ehci_work(struct ehci_hcd *ehci);
273 273
274/*-------------------------------------------------------------------------*/ 274/*-------------------------------------------------------------------------*/
275 275
276#ifdef CONFIG_CPU_FREQ
277
278#include <linux/cpufreq.h>
279
280static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
281{
282 unsigned long flags;
283
284 spin_lock_irqsave(&ehci->lock, flags);
285 if (!ehci->cpufreq_changing++)
286 qh_inactivate_split_intr_qhs(ehci);
287 spin_unlock_irqrestore(&ehci->lock, flags);
288}
289
290static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
291{
292 unsigned long flags;
293
294 spin_lock_irqsave(&ehci->lock, flags);
295 if (!--ehci->cpufreq_changing)
296 qh_reactivate_split_intr_qhs(ehci);
297 spin_unlock_irqrestore(&ehci->lock, flags);
298}
299
300/*
301 * ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
302 * EHCI controllers that don't cache many uframes get delayed trying to
303 * read main memory during CPU frequency transitions. This can cause
304 * split interrupt transactions to not be completed in the required uframe.
305 * This has been observed on the Broadcom/ServerWorks HT1000 controller.
306 */
307static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
308 void *data)
309{
310 struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
311 cpufreq_transition);
312
313 switch (val) {
314 case CPUFREQ_PRECHANGE:
315 ehci_cpufreq_pause(ehci);
316 break;
317 case CPUFREQ_POSTCHANGE:
318 ehci_cpufreq_unpause(ehci);
319 break;
320 }
321 return 0;
322}
323
324#endif
325
326/*-------------------------------------------------------------------------*/
327
276static void ehci_watchdog (unsigned long param) 328static void ehci_watchdog (unsigned long param)
277{ 329{
278 struct ehci_hcd *ehci = (struct ehci_hcd *) param; 330 struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@@ -404,6 +456,10 @@ static void ehci_stop (struct usb_hcd *hcd)
404 ehci_writel(ehci, 0, &ehci->regs->intr_enable); 456 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
405 spin_unlock_irq(&ehci->lock); 457 spin_unlock_irq(&ehci->lock);
406 458
459#ifdef CONFIG_CPU_FREQ
460 cpufreq_unregister_notifier(&ehci->cpufreq_transition,
461 CPUFREQ_TRANSITION_NOTIFIER);
462#endif
407 /* let companion controllers work when we aren't */ 463 /* let companion controllers work when we aren't */
408 ehci_writel(ehci, 0, &ehci->regs->configured_flag); 464 ehci_writel(ehci, 0, &ehci->regs->configured_flag);
409 465
@@ -509,6 +565,17 @@ static int ehci_init(struct usb_hcd *hcd)
509 } 565 }
510 ehci->command = temp; 566 ehci->command = temp;
511 567
568#ifdef CONFIG_CPU_FREQ
569 INIT_LIST_HEAD(&ehci->split_intr_qhs);
570 /*
571 * If the EHCI controller caches enough uframes, this probably
572 * isn't needed unless there are so many low/full speed devices
573 * that the controller's can't cache it all.
574 */
575 ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
576 cpufreq_register_notifier(&ehci->cpufreq_transition,
577 CPUFREQ_TRANSITION_NOTIFIER);
578#endif
512 return 0; 579 return 0;
513} 580}
514 581
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index a8ba2e1497a4..5cff6bace5e5 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -94,6 +94,9 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
94 qh->qh_dma = dma; 94 qh->qh_dma = dma;
95 // INIT_LIST_HEAD (&qh->qh_list); 95 // INIT_LIST_HEAD (&qh->qh_list);
96 INIT_LIST_HEAD (&qh->qtd_list); 96 INIT_LIST_HEAD (&qh->qtd_list);
97#ifdef CONFIG_CPU_FREQ
98 INIT_LIST_HEAD (&qh->split_intr_qhs);
99#endif
97 100
98 /* dummy td enables safe urb queuing */ 101 /* dummy td enables safe urb queuing */
99 qh->dummy = ehci_qtd_alloc (ehci, flags); 102 qh->dummy = ehci_qtd_alloc (ehci, flags);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e7fbbd00e7cd..903510beb299 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -311,6 +311,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
311 struct urb *urb; 311 struct urb *urb;
312 u32 token = 0; 312 u32 token = 0;
313 313
314 /* ignore QHs that are currently inactive */
315 if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
316 break;
317
314 qtd = list_entry (entry, struct ehci_qtd, qtd_list); 318 qtd = list_entry (entry, struct ehci_qtd, qtd_list);
315 urb = qtd->urb; 319 urb = qtd->urb;
316 320
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 7b5ae7111f23..500aebbaa741 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -473,6 +473,111 @@ static int disable_periodic (struct ehci_hcd *ehci)
473} 473}
474 474
475/*-------------------------------------------------------------------------*/ 475/*-------------------------------------------------------------------------*/
476#ifdef CONFIG_CPU_FREQ
477
478/* ignore/inactivate bit in QH hw_info1 */
479#define INACTIVATE_BIT __constant_cpu_to_le32(QH_INACTIVATE)
480
481#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
482#define ACTIVE_BIT __constant_cpu_to_le32(QTD_STS_ACTIVE)
483#define STATUS_BIT __constant_cpu_to_le32(QTD_STS_STS)
484
485static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
486{
487 int now; /* current (frame * 8) + uframe */
488 int prev_start, next_start; /* uframes from/to split start */
489 int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
490 int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
491 int split_duration = end_uframe - start_uframe;
492
493 now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
494
495 next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now) %
496 (qh->period << 3);
497 prev_start = (qh->period << 3) - next_start;
498
499 /*
500 * Make sure there will be at least one uframe when qh is safe.
501 */
502 if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
503 /* never safe */
504 return -EINVAL;
505
506 /*
507 * Wait 1 uframe after transaction should have started, to make
508 * sure controller has time to write back overlay, so we can
509 * check QTD_STS_STS to see if transaction is in progress.
510 */
511 if ((next_start > ehci->i_thresh) && (prev_start > 1))
512 /* safe to set "i" bit if split isn't in progress */
513 return (qh->hw_token & STATUS_BIT) ? 0 : 1;
514 else
515 return 0;
516}
517
518/* Set inactivate bit for all the split interrupt QHs. */
519static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
520{
521 struct ehci_qh *qh;
522 int not_done, safe;
523
524 do {
525 not_done = 0;
526 list_for_each_entry(qh, &ehci->split_intr_qhs,
527 split_intr_qhs) {
528 if (qh->hw_info1 & INACTIVATE_BIT)
529 /* already off */
530 continue;
531 /*
532 * To avoid setting "I" after the start split happens,
533 * don't set it if the QH might be cached in the
534 * controller. Some HCs (Broadcom/ServerWorks HT1000)
535 * will stop in the middle of a split transaction when
536 * the "I" bit is set.
537 */
538 safe = safe_to_modify_i(ehci, qh);
539 if (safe == 0) {
540 not_done = 1;
541 } else if (safe > 0) {
542 qh->was_active = qh->hw_token & ACTIVE_BIT;
543 qh->hw_info1 |= INACTIVATE_BIT;
544 }
545 }
546 } while (not_done);
547 wmb();
548}
549
550static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
551{
552 struct ehci_qh *qh;
553 u32 token;
554 int not_done, safe;
555
556 do {
557 not_done = 0;
558 list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
559 if (!(qh->hw_info1 & INACTIVATE_BIT)) /* already on */
560 continue;
561 /*
562 * Don't reactivate if cached, or controller might
563 * overwrite overlay after we modify it!
564 */
565 safe = safe_to_modify_i(ehci, qh);
566 if (safe == 0) {
567 not_done = 1;
568 } else if (safe > 0) {
569 /* See EHCI 1.0 section 4.15.2.4. */
570 token = qh->hw_token;
571 qh->hw_token = (token | HALT_BIT) & ~ACTIVE_BIT;
572 wmb();
573 qh->hw_info1 &= ~INACTIVATE_BIT;
574 wmb();
575 qh->hw_token = (token & ~HALT_BIT) | qh->was_active;
576 }
577 }
578 } while (not_done);
579}
580#endif
476 581
477/* periodic schedule slots have iso tds (normal or split) first, then a 582/* periodic schedule slots have iso tds (normal or split) first, then a
478 * sparse tree for active interrupt transfers. 583 * sparse tree for active interrupt transfers.
@@ -490,6 +595,17 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
490 period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), 595 period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
491 qh, qh->start, qh->usecs, qh->c_usecs); 596 qh, qh->start, qh->usecs, qh->c_usecs);
492 597
598#ifdef CONFIG_CPU_FREQ
599 /*
600 * If low/full speed interrupt QHs are inactive (because of
601 * cpufreq changing processor speeds), start QH with I flag set--
602 * it will automatically be cleared when cpufreq is done.
603 */
604 if (ehci->cpufreq_changing)
605 if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
606 qh->hw_info1 |= INACTIVATE_BIT;
607#endif
608
493 /* high bandwidth, or otherwise every microframe */ 609 /* high bandwidth, or otherwise every microframe */
494 if (period == 0) 610 if (period == 0)
495 period = 1; 611 period = 1;
@@ -538,6 +654,12 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
538 ? ((qh->usecs + qh->c_usecs) / qh->period) 654 ? ((qh->usecs + qh->c_usecs) / qh->period)
539 : (qh->usecs * 8); 655 : (qh->usecs * 8);
540 656
657#ifdef CONFIG_CPU_FREQ
658 /* add qh to list of low/full speed interrupt QHs, if applicable */
659 if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
660 list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
661 }
662#endif
541 /* maybe enable periodic schedule processing */ 663 /* maybe enable periodic schedule processing */
542 if (!ehci->periodic_sched++) 664 if (!ehci->periodic_sched++)
543 return enable_periodic (ehci); 665 return enable_periodic (ehci);
@@ -557,6 +679,13 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
557 // THEN 679 // THEN
558 // qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */); 680 // qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
559 681
682#ifdef CONFIG_CPU_FREQ
683 /* remove qh from list of low/full speed interrupt QHs */
684 if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
685 list_del_init(&qh->split_intr_qhs);
686 }
687#endif
688
560 /* high bandwidth, or otherwise part of every microframe */ 689 /* high bandwidth, or otherwise part of every microframe */
561 if ((period = qh->period) == 0) 690 if ((period = qh->period) == 0)
562 period = 1; 691 period = 1;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 46fa57a520d0..a9ba5d28cdc2 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -55,6 +55,12 @@ struct ehci_hcd { /* one per controller */
55 __u32 hcs_params; /* cached register copy */ 55 __u32 hcs_params; /* cached register copy */
56 spinlock_t lock; 56 spinlock_t lock;
57 57
58#ifdef CONFIG_CPU_FREQ
59 struct notifier_block cpufreq_transition;
60 int cpufreq_changing;
61 struct list_head split_intr_qhs;
62#endif
63
58 /* async schedule support */ 64 /* async schedule support */
59 struct ehci_qh *async; 65 struct ehci_qh *async;
60 struct ehci_qh *reclaim; 66 struct ehci_qh *reclaim;
@@ -395,6 +401,7 @@ struct ehci_qh {
395 __le32 hw_next; /* see EHCI 3.6.1 */ 401 __le32 hw_next; /* see EHCI 3.6.1 */
396 __le32 hw_info1; /* see EHCI 3.6.2 */ 402 __le32 hw_info1; /* see EHCI 3.6.2 */
397#define QH_HEAD 0x00008000 403#define QH_HEAD 0x00008000
404#define QH_INACTIVATE 0x00000080
398 __le32 hw_info2; /* see EHCI 3.6.2 */ 405 __le32 hw_info2; /* see EHCI 3.6.2 */
399#define QH_SMASK 0x000000ff 406#define QH_SMASK 0x000000ff
400#define QH_CMASK 0x0000ff00 407#define QH_CMASK 0x0000ff00
@@ -437,6 +444,10 @@ struct ehci_qh {
437 unsigned short start; /* where polling starts */ 444 unsigned short start; /* where polling starts */
438#define NO_FRAME ((unsigned short)~0) /* pick new start */ 445#define NO_FRAME ((unsigned short)~0) /* pick new start */
439 struct usb_device *dev; /* access to TT */ 446 struct usb_device *dev; /* access to TT */
447#ifdef CONFIG_CPU_FREQ
448 struct list_head split_intr_qhs; /* list of split qhs */
449 __le32 was_active; /* active bit before "i" set */
450#endif
440} __attribute__ ((aligned (32))); 451} __attribute__ ((aligned (32)));
441 452
442/*-------------------------------------------------------------------------*/ 453/*-------------------------------------------------------------------------*/