aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-12 11:19:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:11 -0400
commit59e29ed91cff90b27d393c7a3d3ac9c3fcaea7dd (patch)
tree5003afaca5960954fe25a2fe6401f43fef48f8bb /drivers/usb/host
parentb1869000a60b0c72022811f24110a52d3e300b1e (diff)
[PATCH] UHCI: Remove non-iso TDs as they are used
This patch (as680) frees non-isochronous TDs as they are used, rather than all at once when an URB is complete. Although not a terribly important change in itself, it opens the door to a later enhancement that will reduce storage requirements by allocating only a limited number of TDs at any time for each endpoint queue. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-debug.c1
-rw-r--r--drivers/usb/host/uhci-hcd.h5
-rw-r--r--drivers/usb/host/uhci-q.c78
3 files changed, 45 insertions, 39 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 28c1c51ec475..6bbd33db9358 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -119,6 +119,7 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
119 } 119 }
120 120
121 out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); 121 out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
122 out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
122 123
123 if (urbp->urb->status != -EINPROGRESS) 124 if (urbp->urb->status != -EINPROGRESS)
124 out += sprintf(out, " Status=%d", urbp->urb->status); 125 out += sprintf(out, " Status=%d", urbp->urb->status);
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 8e5778650493..3093ca250942 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -129,6 +129,7 @@ struct uhci_qh {
129 struct list_head queue; /* Queue of urbps for this QH */ 129 struct list_head queue; /* Queue of urbps for this QH */
130 struct uhci_qh *skel; /* Skeleton for this QH */ 130 struct uhci_qh *skel; /* Skeleton for this QH */
131 struct uhci_td *dummy_td; /* Dummy TD to end the queue */ 131 struct uhci_td *dummy_td; /* Dummy TD to end the queue */
132 struct uhci_td *post_td; /* Last TD completed */
132 133
133 unsigned int unlink_frame; /* When the QH was unlinked */ 134 unsigned int unlink_frame; /* When the QH was unlinked */
134 int state; /* QH_STATE_xxx; see above */ 135 int state; /* QH_STATE_xxx; see above */
@@ -136,7 +137,7 @@ struct uhci_qh {
136 137
137 unsigned int initial_toggle:1; /* Endpoint's current toggle value */ 138 unsigned int initial_toggle:1; /* Endpoint's current toggle value */
138 unsigned int needs_fixup:1; /* Must fix the TD toggle values */ 139 unsigned int needs_fixup:1; /* Must fix the TD toggle values */
139 unsigned int is_stopped:1; /* Queue was stopped by an error */ 140 unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
140} __attribute__((aligned(16))); 141} __attribute__((aligned(16)));
141 142
142/* 143/*
@@ -456,8 +457,6 @@ struct urb_priv {
456 struct list_head td_list; 457 struct list_head td_list;
457 458
458 unsigned fsbr : 1; /* URB turned on FSBR */ 459 unsigned fsbr : 1; /* URB turned on FSBR */
459 unsigned short_transfer : 1; /* URB got a short transfer, no
460 * need to rescan */
461}; 460};
462 461
463 462
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30e36031fe21..888938d78230 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -161,6 +161,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
161 if (!qh) 161 if (!qh)
162 return NULL; 162 return NULL;
163 163
164 memset(qh, 0, sizeof(*qh));
164 qh->dma_handle = dma_handle; 165 qh->dma_handle = dma_handle;
165 166
166 qh->element = UHCI_PTR_TERM; 167 qh->element = UHCI_PTR_TERM;
@@ -183,7 +184,6 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
183 184
184 } else { /* Skeleton QH */ 185 } else { /* Skeleton QH */
185 qh->state = QH_STATE_ACTIVE; 186 qh->state = QH_STATE_ACTIVE;
186 qh->udev = NULL;
187 qh->type = -1; 187 qh->type = -1;
188 } 188 }
189 return qh; 189 return qh;
@@ -223,16 +223,10 @@ static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb)
223 qh->type == USB_ENDPOINT_XFER_INT)) 223 qh->type == USB_ENDPOINT_XFER_INT))
224 return; 224 return;
225 225
226 /* Find the first active TD; that's the device's toggle state */ 226 WARN_ON(list_empty(&urbp->td_list));
227 list_for_each_entry(td, &urbp->td_list, list) { 227 td = list_entry(urbp->td_list.next, struct uhci_td, list);
228 if (td_status(td) & TD_CTRL_ACTIVE) { 228 qh->needs_fixup = 1;
229 qh->needs_fixup = 1; 229 qh->initial_toggle = uhci_toggle(td_token(td));
230 qh->initial_toggle = uhci_toggle(td_token(td));
231 return;
232 }
233 }
234
235 WARN_ON(1);
236} 230}
237 231
238/* 232/*
@@ -372,6 +366,12 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
372 list_move(&qh->node, &uhci->idle_qh_list); 366 list_move(&qh->node, &uhci->idle_qh_list);
373 qh->state = QH_STATE_IDLE; 367 qh->state = QH_STATE_IDLE;
374 368
369 /* Now that the QH is idle, its post_td isn't being used */
370 if (qh->post_td) {
371 uhci_free_td(uhci, qh->post_td);
372 qh->post_td = NULL;
373 }
374
375 /* If anyone is waiting for a QH to become idle, wake them up */ 375 /* If anyone is waiting for a QH to become idle, wake them up */
376 if (uhci->num_waiting) 376 if (uhci->num_waiting)
377 wake_up_all(&uhci->waitqh); 377 wake_up_all(&uhci->waitqh);
@@ -610,6 +610,8 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
610 qh->skel = uhci->skel_fs_control_qh; 610 qh->skel = uhci->skel_fs_control_qh;
611 uhci_inc_fsbr(uhci, urb); 611 uhci_inc_fsbr(uhci, urb);
612 } 612 }
613
614 urb->actual_length = -8; /* Account for the SETUP packet */
613 return 0; 615 return 0;
614 616
615nomem: 617nomem:
@@ -767,34 +769,46 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
767 * Fix up the data structures following a short transfer 769 * Fix up the data structures following a short transfer
768 */ 770 */
769static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, 771static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
770 struct uhci_qh *qh, struct urb_priv *urbp, 772 struct uhci_qh *qh, struct urb_priv *urbp)
771 struct uhci_td *short_td)
772{ 773{
773 struct uhci_td *td; 774 struct uhci_td *td;
774 int ret = 0; 775 struct list_head *tmp;
776 int ret;
775 777
776 td = list_entry(urbp->td_list.prev, struct uhci_td, list); 778 td = list_entry(urbp->td_list.prev, struct uhci_td, list);
777 if (qh->type == USB_ENDPOINT_XFER_CONTROL) { 779 if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
778 urbp->short_transfer = 1;
779 780
780 /* When a control transfer is short, we have to restart 781 /* When a control transfer is short, we have to restart
781 * the queue at the status stage transaction, which is 782 * the queue at the status stage transaction, which is
782 * the last TD. */ 783 * the last TD. */
784 WARN_ON(list_empty(&urbp->td_list));
783 qh->element = cpu_to_le32(td->dma_handle); 785 qh->element = cpu_to_le32(td->dma_handle);
786 tmp = td->list.prev;
784 ret = -EINPROGRESS; 787 ret = -EINPROGRESS;
785 788
786 } else if (!urbp->short_transfer) { 789 } else {
787 urbp->short_transfer = 1;
788 790
789 /* When a bulk/interrupt transfer is short, we have to 791 /* When a bulk/interrupt transfer is short, we have to
790 * fix up the toggles of the following URBs on the queue 792 * fix up the toggles of the following URBs on the queue
791 * before restarting the queue at the next URB. */ 793 * before restarting the queue at the next URB. */
792 qh->initial_toggle = uhci_toggle(td_token(short_td)) ^ 1; 794 qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1;
793 uhci_fixup_toggles(qh, 1); 795 uhci_fixup_toggles(qh, 1);
794 796
797 if (list_empty(&urbp->td_list))
798 td = qh->post_td;
795 qh->element = td->link; 799 qh->element = td->link;
800 tmp = urbp->td_list.prev;
801 ret = 0;
796 } 802 }
797 803
804 /* Remove all the TDs we skipped over, from tmp back to the start */
805 while (tmp != &urbp->td_list) {
806 td = list_entry(tmp, struct uhci_td, list);
807 tmp = tmp->prev;
808
809 uhci_remove_td_from_urb(td);
810 list_add(&td->remove_list, &uhci->td_remove_list);
811 }
798 return ret; 812 return ret;
799} 813}
800 814
@@ -805,29 +819,14 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
805{ 819{
806 struct urb_priv *urbp = urb->hcpriv; 820 struct urb_priv *urbp = urb->hcpriv;
807 struct uhci_qh *qh = urbp->qh; 821 struct uhci_qh *qh = urbp->qh;
808 struct uhci_td *td; 822 struct uhci_td *td, *tmp;
809 struct list_head *tmp;
810 unsigned status; 823 unsigned status;
811 int ret = 0; 824 int ret = 0;
812 825
813 tmp = urbp->td_list.next; 826 list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
814
815 if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
816 if (urbp->short_transfer)
817 tmp = urbp->td_list.prev;
818 else
819 urb->actual_length = -8; /* SETUP packet */
820 } else
821 urb->actual_length = 0;
822
823
824 while (tmp != &urbp->td_list) {
825 unsigned int ctrlstat; 827 unsigned int ctrlstat;
826 int len; 828 int len;
827 829
828 td = list_entry(tmp, struct uhci_td, list);
829 tmp = tmp->next;
830
831 ctrlstat = td_status(td); 830 ctrlstat = td_status(td);
832 status = uhci_status_bits(ctrlstat); 831 status = uhci_status_bits(ctrlstat);
833 if (status & TD_CTRL_ACTIVE) 832 if (status & TD_CTRL_ACTIVE)
@@ -862,6 +861,12 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
862 ret = 1; 861 ret = 1;
863 } 862 }
864 863
864 uhci_remove_td_from_urb(td);
865 if (qh->post_td)
866 list_add(&qh->post_td->remove_list,
867 &uhci->td_remove_list);
868 qh->post_td = td;
869
865 if (ret != 0) 870 if (ret != 0)
866 goto err; 871 goto err;
867 } 872 }
@@ -882,7 +887,7 @@ err:
882 (ret == -EREMOTEIO); 887 (ret == -EREMOTEIO);
883 888
884 } else /* Short packet received */ 889 } else /* Short packet received */
885 ret = uhci_fixup_short_transfer(uhci, qh, urbp, td); 890 ret = uhci_fixup_short_transfer(uhci, qh, urbp);
886 return ret; 891 return ret;
887} 892}
888 893
@@ -1123,6 +1128,7 @@ __acquires(uhci->lock)
1123 struct uhci_td *ptd, *ltd; 1128 struct uhci_td *ptd, *ltd;
1124 1129
1125 purbp = list_entry(urbp->node.prev, struct urb_priv, node); 1130 purbp = list_entry(urbp->node.prev, struct urb_priv, node);
1131 WARN_ON(list_empty(&purbp->td_list));
1126 ptd = list_entry(purbp->td_list.prev, struct uhci_td, 1132 ptd = list_entry(purbp->td_list.prev, struct uhci_td,
1127 list); 1133 list);
1128 ltd = list_entry(urbp->td_list.prev, struct uhci_td, 1134 ltd = list_entry(urbp->td_list.prev, struct uhci_td,