diff options
author | Alek Du <alek.du@intel.com> | 2009-07-13 19:23:29 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 09:46:29 -0400 |
commit | 3807e26d69b9ad3864fe03224ebebc9610d5802e (patch) | |
tree | 3c85a5cb0686a7e72255c523b963942bbfc60b7f /drivers/usb/host/ehci-sched.c | |
parent | 403dbd36739e344d2d25f56ebbe342248487bd48 (diff) |
USB: EHCI: split ehci_qh into hw and sw parts
The ehci_qh structure merged hw and sw together which is not good:
1. More and more items are being added into ehci_qh, the ehci_qh software
part are unnecessary to be allocated in DMA qh_pool.
2. If HCD has local SRAM, the sw part will consume it too, and it won't
bring any benefit.
3. For non-cache-coherence system, the entire ehci_qh is uncachable, actually
we only need the hw part to be uncacheable. Spliting them will let the sw
part to be cacheable.
Signed-off-by: Alek Du <alek.du@intel.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
CC: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index edd61ee90323..327437af2122 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -60,6 +60,20 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic, | |||
60 | } | 60 | } |
61 | } | 61 | } |
62 | 62 | ||
63 | static __hc32 * | ||
64 | shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic, | ||
65 | __hc32 tag) | ||
66 | { | ||
67 | switch (hc32_to_cpu(ehci, tag)) { | ||
68 | /* our ehci_shadow.qh is actually software part */ | ||
69 | case Q_TYPE_QH: | ||
70 | return &periodic->qh->hw->hw_next; | ||
71 | /* others are hw parts */ | ||
72 | default: | ||
73 | return periodic->hw_next; | ||
74 | } | ||
75 | } | ||
76 | |||
63 | /* caller must hold ehci->lock */ | 77 | /* caller must hold ehci->lock */ |
64 | static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) | 78 | static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) |
65 | { | 79 | { |
@@ -71,7 +85,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) | |||
71 | while (here.ptr && here.ptr != ptr) { | 85 | while (here.ptr && here.ptr != ptr) { |
72 | prev_p = periodic_next_shadow(ehci, prev_p, | 86 | prev_p = periodic_next_shadow(ehci, prev_p, |
73 | Q_NEXT_TYPE(ehci, *hw_p)); | 87 | Q_NEXT_TYPE(ehci, *hw_p)); |
74 | hw_p = here.hw_next; | 88 | hw_p = shadow_next_periodic(ehci, &here, |
89 | Q_NEXT_TYPE(ehci, *hw_p)); | ||
75 | here = *prev_p; | 90 | here = *prev_p; |
76 | } | 91 | } |
77 | /* an interrupt entry (at list end) could have been shared */ | 92 | /* an interrupt entry (at list end) could have been shared */ |
@@ -83,7 +98,7 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) | |||
83 | */ | 98 | */ |
84 | *prev_p = *periodic_next_shadow(ehci, &here, | 99 | *prev_p = *periodic_next_shadow(ehci, &here, |
85 | Q_NEXT_TYPE(ehci, *hw_p)); | 100 | Q_NEXT_TYPE(ehci, *hw_p)); |
86 | *hw_p = *here.hw_next; | 101 | *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); |
87 | } | 102 | } |
88 | 103 | ||
89 | /* how many of the uframe's 125 usecs are allocated? */ | 104 | /* how many of the uframe's 125 usecs are allocated? */ |
@@ -93,18 +108,20 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) | |||
93 | __hc32 *hw_p = &ehci->periodic [frame]; | 108 | __hc32 *hw_p = &ehci->periodic [frame]; |
94 | union ehci_shadow *q = &ehci->pshadow [frame]; | 109 | union ehci_shadow *q = &ehci->pshadow [frame]; |
95 | unsigned usecs = 0; | 110 | unsigned usecs = 0; |
111 | struct ehci_qh_hw *hw; | ||
96 | 112 | ||
97 | while (q->ptr) { | 113 | while (q->ptr) { |
98 | switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { | 114 | switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { |
99 | case Q_TYPE_QH: | 115 | case Q_TYPE_QH: |
116 | hw = q->qh->hw; | ||
100 | /* is it in the S-mask? */ | 117 | /* is it in the S-mask? */ |
101 | if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) | 118 | if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) |
102 | usecs += q->qh->usecs; | 119 | usecs += q->qh->usecs; |
103 | /* ... or C-mask? */ | 120 | /* ... or C-mask? */ |
104 | if (q->qh->hw_info2 & cpu_to_hc32(ehci, | 121 | if (hw->hw_info2 & cpu_to_hc32(ehci, |
105 | 1 << (8 + uframe))) | 122 | 1 << (8 + uframe))) |
106 | usecs += q->qh->c_usecs; | 123 | usecs += q->qh->c_usecs; |
107 | hw_p = &q->qh->hw_next; | 124 | hw_p = &hw->hw_next; |
108 | q = &q->qh->qh_next; | 125 | q = &q->qh->qh_next; |
109 | break; | 126 | break; |
110 | // case Q_TYPE_FSTN: | 127 | // case Q_TYPE_FSTN: |
@@ -237,10 +254,10 @@ periodic_tt_usecs ( | |||
237 | continue; | 254 | continue; |
238 | case Q_TYPE_QH: | 255 | case Q_TYPE_QH: |
239 | if (same_tt(dev, q->qh->dev)) { | 256 | if (same_tt(dev, q->qh->dev)) { |
240 | uf = tt_start_uframe(ehci, q->qh->hw_info2); | 257 | uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); |
241 | tt_usecs[uf] += q->qh->tt_usecs; | 258 | tt_usecs[uf] += q->qh->tt_usecs; |
242 | } | 259 | } |
243 | hw_p = &q->qh->hw_next; | 260 | hw_p = &q->qh->hw->hw_next; |
244 | q = &q->qh->qh_next; | 261 | q = &q->qh->qh_next; |
245 | continue; | 262 | continue; |
246 | case Q_TYPE_SITD: | 263 | case Q_TYPE_SITD: |
@@ -375,6 +392,7 @@ static int tt_no_collision ( | |||
375 | for (; frame < ehci->periodic_size; frame += period) { | 392 | for (; frame < ehci->periodic_size; frame += period) { |
376 | union ehci_shadow here; | 393 | union ehci_shadow here; |
377 | __hc32 type; | 394 | __hc32 type; |
395 | struct ehci_qh_hw *hw; | ||
378 | 396 | ||
379 | here = ehci->pshadow [frame]; | 397 | here = ehci->pshadow [frame]; |
380 | type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); | 398 | type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); |
@@ -385,17 +403,18 @@ static int tt_no_collision ( | |||
385 | here = here.itd->itd_next; | 403 | here = here.itd->itd_next; |
386 | continue; | 404 | continue; |
387 | case Q_TYPE_QH: | 405 | case Q_TYPE_QH: |
406 | hw = here.qh->hw; | ||
388 | if (same_tt (dev, here.qh->dev)) { | 407 | if (same_tt (dev, here.qh->dev)) { |
389 | u32 mask; | 408 | u32 mask; |
390 | 409 | ||
391 | mask = hc32_to_cpu(ehci, | 410 | mask = hc32_to_cpu(ehci, |
392 | here.qh->hw_info2); | 411 | hw->hw_info2); |
393 | /* "knows" no gap is needed */ | 412 | /* "knows" no gap is needed */ |
394 | mask |= mask >> 8; | 413 | mask |= mask >> 8; |
395 | if (mask & uf_mask) | 414 | if (mask & uf_mask) |
396 | break; | 415 | break; |
397 | } | 416 | } |
398 | type = Q_NEXT_TYPE(ehci, here.qh->hw_next); | 417 | type = Q_NEXT_TYPE(ehci, hw->hw_next); |
399 | here = here.qh->qh_next; | 418 | here = here.qh->qh_next; |
400 | continue; | 419 | continue; |
401 | case Q_TYPE_SITD: | 420 | case Q_TYPE_SITD: |
@@ -498,7 +517,8 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
498 | 517 | ||
499 | dev_dbg (&qh->dev->dev, | 518 | dev_dbg (&qh->dev->dev, |
500 | "link qh%d-%04x/%p start %d [%d/%d us]\n", | 519 | "link qh%d-%04x/%p start %d [%d/%d us]\n", |
501 | period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), | 520 | period, hc32_to_cpup(ehci, &qh->hw->hw_info2) |
521 | & (QH_CMASK | QH_SMASK), | ||
502 | qh, qh->start, qh->usecs, qh->c_usecs); | 522 | qh, qh->start, qh->usecs, qh->c_usecs); |
503 | 523 | ||
504 | /* high bandwidth, or otherwise every microframe */ | 524 | /* high bandwidth, or otherwise every microframe */ |
@@ -517,7 +537,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
517 | if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) | 537 | if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) |
518 | break; | 538 | break; |
519 | prev = periodic_next_shadow(ehci, prev, type); | 539 | prev = periodic_next_shadow(ehci, prev, type); |
520 | hw_p = &here.qh->hw_next; | 540 | hw_p = shadow_next_periodic(ehci, &here, type); |
521 | here = *prev; | 541 | here = *prev; |
522 | } | 542 | } |
523 | 543 | ||
@@ -528,14 +548,14 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
528 | if (qh->period > here.qh->period) | 548 | if (qh->period > here.qh->period) |
529 | break; | 549 | break; |
530 | prev = &here.qh->qh_next; | 550 | prev = &here.qh->qh_next; |
531 | hw_p = &here.qh->hw_next; | 551 | hw_p = &here.qh->hw->hw_next; |
532 | here = *prev; | 552 | here = *prev; |
533 | } | 553 | } |
534 | /* link in this qh, unless some earlier pass did that */ | 554 | /* link in this qh, unless some earlier pass did that */ |
535 | if (qh != here.qh) { | 555 | if (qh != here.qh) { |
536 | qh->qh_next = here; | 556 | qh->qh_next = here; |
537 | if (here.qh) | 557 | if (here.qh) |
538 | qh->hw_next = *hw_p; | 558 | qh->hw->hw_next = *hw_p; |
539 | wmb (); | 559 | wmb (); |
540 | prev->qh = qh; | 560 | prev->qh = qh; |
541 | *hw_p = QH_NEXT (ehci, qh->qh_dma); | 561 | *hw_p = QH_NEXT (ehci, qh->qh_dma); |
@@ -581,7 +601,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
581 | dev_dbg (&qh->dev->dev, | 601 | dev_dbg (&qh->dev->dev, |
582 | "unlink qh%d-%04x/%p start %d [%d/%d us]\n", | 602 | "unlink qh%d-%04x/%p start %d [%d/%d us]\n", |
583 | qh->period, | 603 | qh->period, |
584 | hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), | 604 | hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), |
585 | qh, qh->start, qh->usecs, qh->c_usecs); | 605 | qh, qh->start, qh->usecs, qh->c_usecs); |
586 | 606 | ||
587 | /* qh->qh_next still "live" to HC */ | 607 | /* qh->qh_next still "live" to HC */ |
@@ -596,6 +616,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
596 | static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) | 616 | static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) |
597 | { | 617 | { |
598 | unsigned wait; | 618 | unsigned wait; |
619 | struct ehci_qh_hw *hw = qh->hw; | ||
599 | 620 | ||
600 | qh_unlink_periodic (ehci, qh); | 621 | qh_unlink_periodic (ehci, qh); |
601 | 622 | ||
@@ -606,14 +627,14 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
606 | */ | 627 | */ |
607 | if (list_empty (&qh->qtd_list) | 628 | if (list_empty (&qh->qtd_list) |
608 | || (cpu_to_hc32(ehci, QH_CMASK) | 629 | || (cpu_to_hc32(ehci, QH_CMASK) |
609 | & qh->hw_info2) != 0) | 630 | & hw->hw_info2) != 0) |
610 | wait = 2; | 631 | wait = 2; |
611 | else | 632 | else |
612 | wait = 55; /* worst case: 3 * 1024 */ | 633 | wait = 55; /* worst case: 3 * 1024 */ |
613 | 634 | ||
614 | udelay (wait); | 635 | udelay (wait); |
615 | qh->qh_state = QH_STATE_IDLE; | 636 | qh->qh_state = QH_STATE_IDLE; |
616 | qh->hw_next = EHCI_LIST_END(ehci); | 637 | hw->hw_next = EHCI_LIST_END(ehci); |
617 | wmb (); | 638 | wmb (); |
618 | } | 639 | } |
619 | 640 | ||
@@ -739,14 +760,15 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
739 | unsigned uframe; | 760 | unsigned uframe; |
740 | __hc32 c_mask; | 761 | __hc32 c_mask; |
741 | unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ | 762 | unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ |
763 | struct ehci_qh_hw *hw = qh->hw; | ||
742 | 764 | ||
743 | qh_refresh(ehci, qh); | 765 | qh_refresh(ehci, qh); |
744 | qh->hw_next = EHCI_LIST_END(ehci); | 766 | hw->hw_next = EHCI_LIST_END(ehci); |
745 | frame = qh->start; | 767 | frame = qh->start; |
746 | 768 | ||
747 | /* reuse the previous schedule slots, if we can */ | 769 | /* reuse the previous schedule slots, if we can */ |
748 | if (frame < qh->period) { | 770 | if (frame < qh->period) { |
749 | uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK); | 771 | uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK); |
750 | status = check_intr_schedule (ehci, frame, --uframe, | 772 | status = check_intr_schedule (ehci, frame, --uframe, |
751 | qh, &c_mask); | 773 | qh, &c_mask); |
752 | } else { | 774 | } else { |
@@ -784,11 +806,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
784 | qh->start = frame; | 806 | qh->start = frame; |
785 | 807 | ||
786 | /* reset S-frame and (maybe) C-frame masks */ | 808 | /* reset S-frame and (maybe) C-frame masks */ |
787 | qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); | 809 | hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); |
788 | qh->hw_info2 |= qh->period | 810 | hw->hw_info2 |= qh->period |
789 | ? cpu_to_hc32(ehci, 1 << uframe) | 811 | ? cpu_to_hc32(ehci, 1 << uframe) |
790 | : cpu_to_hc32(ehci, QH_SMASK); | 812 | : cpu_to_hc32(ehci, QH_SMASK); |
791 | qh->hw_info2 |= c_mask; | 813 | hw->hw_info2 |= c_mask; |
792 | } else | 814 | } else |
793 | ehci_dbg (ehci, "reused qh %p schedule\n", qh); | 815 | ehci_dbg (ehci, "reused qh %p schedule\n", qh); |
794 | 816 | ||
@@ -2188,7 +2210,7 @@ restart: | |||
2188 | case Q_TYPE_QH: | 2210 | case Q_TYPE_QH: |
2189 | /* handle any completions */ | 2211 | /* handle any completions */ |
2190 | temp.qh = qh_get (q.qh); | 2212 | temp.qh = qh_get (q.qh); |
2191 | type = Q_NEXT_TYPE(ehci, q.qh->hw_next); | 2213 | type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); |
2192 | q = q.qh->qh_next; | 2214 | q = q.qh->qh_next; |
2193 | modified = qh_completions (ehci, temp.qh); | 2215 | modified = qh_completions (ehci, temp.qh); |
2194 | if (unlikely (list_empty (&temp.qh->qtd_list))) | 2216 | if (unlikely (list_empty (&temp.qh->qtd_list))) |