aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ohci-hcd.c12
-rw-r--r--drivers/usb/host/ohci-hub.c6
-rw-r--r--drivers/usb/host/ohci-q.c109
-rw-r--r--drivers/usb/host/ohci.h1
4 files changed, 70 insertions, 58 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 52829276a44e..3112799bba7f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -780,24 +780,21 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
780 usb_hcd_resume_root_hub(hcd); 780 usb_hcd_resume_root_hub(hcd);
781 } 781 }
782 782
783 if (ints & OHCI_INTR_WDH) { 783 spin_lock(&ohci->lock);
784 spin_lock (&ohci->lock); 784 if (ints & OHCI_INTR_WDH)
785 dl_done_list (ohci); 785 update_done_list(ohci);
786 spin_unlock (&ohci->lock);
787 }
788 786
789 /* could track INTR_SO to reduce available PCI/... bandwidth */ 787 /* could track INTR_SO to reduce available PCI/... bandwidth */
790 788
791 /* handle any pending URB/ED unlinks, leaving INTR_SF enabled 789 /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
792 * when there's still unlinking to be done (next frame). 790 * when there's still unlinking to be done (next frame).
793 */ 791 */
794 spin_lock (&ohci->lock); 792 process_done_list(ohci);
795 if (ohci->ed_rm_list) 793 if (ohci->ed_rm_list)
796 finish_unlinks (ohci, ohci_frame_no(ohci)); 794 finish_unlinks (ohci, ohci_frame_no(ohci));
797 if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list 795 if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
798 && ohci->rh_state == OHCI_RH_RUNNING) 796 && ohci->rh_state == OHCI_RH_RUNNING)
799 ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable); 797 ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
800 spin_unlock (&ohci->lock);
801 798
802 if (ohci->rh_state == OHCI_RH_RUNNING) { 799 if (ohci->rh_state == OHCI_RH_RUNNING) {
803 ohci_writel (ohci, ints, &regs->intrstatus); 800 ohci_writel (ohci, ints, &regs->intrstatus);
@@ -805,6 +802,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
805 // flush those writes 802 // flush those writes
806 (void) ohci_readl (ohci, &ohci->regs->control); 803 (void) ohci_readl (ohci, &ohci->regs->control);
807 } 804 }
805 spin_unlock(&ohci->lock);
808 806
809 return IRQ_HANDLED; 807 return IRQ_HANDLED;
810} 808}
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index b4940de1eba3..dccb90edd66e 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -39,7 +39,8 @@
39#define OHCI_SCHED_ENABLES \ 39#define OHCI_SCHED_ENABLES \
40 (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) 40 (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
41 41
42static void dl_done_list (struct ohci_hcd *); 42static void update_done_list(struct ohci_hcd *);
43static void process_done_list(struct ohci_hcd *);
43static void finish_unlinks (struct ohci_hcd *, u16); 44static void finish_unlinks (struct ohci_hcd *, u16);
44 45
45#ifdef CONFIG_PM 46#ifdef CONFIG_PM
@@ -87,7 +88,8 @@ __acquires(ohci->lock)
87 msleep (8); 88 msleep (8);
88 spin_lock_irq (&ohci->lock); 89 spin_lock_irq (&ohci->lock);
89 } 90 }
90 dl_done_list (ohci); 91 update_done_list(ohci);
92 process_done_list(ohci);
91 finish_unlinks (ohci, ohci_frame_no(ohci)); 93 finish_unlinks (ohci, ohci_frame_no(ohci));
92 94
93 /* 95 /*
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index a9f4f04c3fad..f36b2fa0ee2f 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -892,13 +892,41 @@ static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
892 } 892 }
893} 893}
894 894
895/* replies to the request have to be on a FIFO basis so 895/* Add a TD to the done list */
896 * we unreverse the hc-reversed done-list 896static void add_to_done_list(struct ohci_hcd *ohci, struct td *td)
897 */ 897{
898static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) 898 struct td *td2, *td_prev;
899 struct ed *ed;
900
901 if (td->next_dl_td)
902 return; /* Already on the list */
903
904 /* Add all the TDs going back until we reach one that's on the list */
905 ed = td->ed;
906 td2 = td_prev = td;
907 list_for_each_entry_continue_reverse(td2, &ed->td_list, td_list) {
908 if (td2->next_dl_td)
909 break;
910 td2->next_dl_td = td_prev;
911 td_prev = td2;
912 }
913
914 if (ohci->dl_end)
915 ohci->dl_end->next_dl_td = td_prev;
916 else
917 ohci->dl_start = td_prev;
918
919 /*
920 * Make td->next_dl_td point to td itself, to mark the fact
921 * that td is on the done list.
922 */
923 ohci->dl_end = td->next_dl_td = td;
924}
925
926/* Get the entries on the hardware done queue and put them on our list */
927static void update_done_list(struct ohci_hcd *ohci)
899{ 928{
900 u32 td_dma; 929 u32 td_dma;
901 struct td *td_rev = NULL;
902 struct td *td = NULL; 930 struct td *td = NULL;
903 931
904 td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head); 932 td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head);
@@ -906,7 +934,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
906 wmb(); 934 wmb();
907 935
908 /* get TD from hc's singly linked list, and 936 /* get TD from hc's singly linked list, and
909 * prepend to ours. ed->td_list changes later. 937 * add to ours. ed->td_list changes later.
910 */ 938 */
911 while (td_dma) { 939 while (td_dma) {
912 int cc; 940 int cc;
@@ -928,11 +956,9 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
928 && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) 956 && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
929 ed_halted(ohci, td, cc); 957 ed_halted(ohci, td, cc);
930 958
931 td->next_dl_td = td_rev;
932 td_rev = td;
933 td_dma = hc32_to_cpup (ohci, &td->hwNextTD); 959 td_dma = hc32_to_cpup (ohci, &td->hwNextTD);
960 add_to_done_list(ohci, td);
934 } 961 }
935 return td_rev;
936} 962}
937 963
938/*-------------------------------------------------------------------------*/ 964/*-------------------------------------------------------------------------*/
@@ -956,26 +982,27 @@ rescan_all:
956 /* only take off EDs that the HC isn't using, accounting for 982 /* only take off EDs that the HC isn't using, accounting for
957 * frame counter wraps and EDs with partially retired TDs 983 * frame counter wraps and EDs with partially retired TDs
958 */ 984 */
959 if (likely(ohci->rh_state == OHCI_RH_RUNNING)) { 985 if (likely(ohci->rh_state == OHCI_RH_RUNNING) &&
960 if (tick_before (tick, ed->tick)) { 986 tick_before(tick, ed->tick)) {
961skip_ed: 987skip_ed:
962 last = &ed->ed_next; 988 last = &ed->ed_next;
963 continue; 989 continue;
964 } 990 }
991 if (!list_empty(&ed->td_list)) {
992 struct td *td;
993 u32 head;
965 994
966 if (!list_empty (&ed->td_list)) { 995 td = list_first_entry(&ed->td_list, struct td, td_list);
967 struct td *td;
968 u32 head;
969 996
970 td = list_entry (ed->td_list.next, struct td, 997 /* INTR_WDH may need to clean up first */
971 td_list); 998 head = hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK;
972 head = hc32_to_cpu (ohci, ed->hwHeadP) & 999 if (td->td_dma != head &&
973 TD_MASK; 1000 ohci->rh_state == OHCI_RH_RUNNING)
1001 goto skip_ed;
974 1002
975 /* INTR_WDH may need to clean up first */ 1003 /* Don't mess up anything already on the done list */
976 if (td->td_dma != head) 1004 if (td->next_dl_td)
977 goto skip_ed; 1005 goto skip_ed;
978 }
979 } 1006 }
980 1007
981 /* ED's now officially unlinked, hc doesn't see */ 1008 /* ED's now officially unlinked, hc doesn't see */
@@ -1161,33 +1188,17 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
1161 * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, 1188 * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
1162 * instead of scanning the (re-reversed) donelist as this does. 1189 * instead of scanning the (re-reversed) donelist as this does.
1163 */ 1190 */
1164static void 1191static void process_done_list(struct ohci_hcd *ohci)
1165dl_done_list (struct ohci_hcd *ohci)
1166{ 1192{
1167 struct td *td = dl_reverse_done_list (ohci); 1193 struct td *td;
1168
1169 while (td) {
1170 struct td *td_next = td->next_dl_td;
1171 struct ed *ed = td->ed;
1172 1194
1173 /* 1195 while (ohci->dl_start) {
1174 * Some OHCI controllers (NVIDIA for sure, maybe others) 1196 td = ohci->dl_start;
1175 * occasionally forget to add TDs to the done queue. Since 1197 if (td == ohci->dl_end)
1176 * TDs for a given endpoint are always processed in order, 1198 ohci->dl_start = ohci->dl_end = NULL;
1177 * if we find a TD on the donelist then all of its 1199 else
1178 * predecessors must be finished as well. 1200 ohci->dl_start = td->next_dl_td;
1179 */
1180 for (;;) {
1181 struct td *td2;
1182
1183 td2 = list_first_entry(&ed->td_list, struct td,
1184 td_list);
1185 if (td2 == td)
1186 break;
1187 takeback_td(ohci, td2);
1188 }
1189 1201
1190 takeback_td(ohci, td); 1202 takeback_td(ohci, td);
1191 td = td_next;
1192 } 1203 }
1193} 1204}
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 392932dd6318..a8259bc6fd8b 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -380,6 +380,7 @@ struct ohci_hcd {
380 struct dma_pool *td_cache; 380 struct dma_pool *td_cache;
381 struct dma_pool *ed_cache; 381 struct dma_pool *ed_cache;
382 struct td *td_hash [TD_HASH_SIZE]; 382 struct td *td_hash [TD_HASH_SIZE];
383 struct td *dl_start, *dl_end; /* the done list */
383 struct list_head pending; 384 struct list_head pending;
384 385
385 /* 386 /*