diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2005-12-17 17:58:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-20 14:49:57 -0800 |
commit | dccf4a48d47120a42382ba526f1a0848c13ba2a4 (patch) | |
tree | 788a0a9f491d1a42df1dee1781156ccfc363b6ef /drivers/usb/host/uhci-q.c | |
parent | 499003e815344304c7b0c93aad923ddf644d24e0 (diff) |
[PATCH] UHCI: use one QH per endpoint, not per URB
This patch (as623) changes the uhci-hcd driver to make it use one QH per
device endpoint, instead of a QH per URB as it does now. Numerous areas
of the code are affected by this. For example, the distinction between
"queued" URBs and non-"queued" URBs no longer exists; all URBs belong to
a queue and some just happen to be at the queue's head.
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-q.c')
-rw-r--r-- | drivers/usb/host/uhci-q.c | 985 |
1 files changed, 456 insertions, 529 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 782398045f9..b1b551a3d14 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -13,13 +13,9 @@ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu + * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu */ -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); -static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb); -static void uhci_remove_pending_urbps(struct uhci_hcd *uhci); -static void uhci_free_pending_qhs(struct uhci_hcd *uhci); static void uhci_free_pending_tds(struct uhci_hcd *uhci); /* @@ -30,7 +26,7 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); * games with the FSBR code to make sure we get the correct order in all * the cases. I don't think it's worth the effort */ -static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) +static void uhci_set_next_interrupt(struct uhci_hcd *uhci) { if (uhci->is_stopped) mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); @@ -42,12 +38,6 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); } -static inline void uhci_moveto_complete(struct uhci_hcd *uhci, - struct urb_priv *urbp) -{ - list_move_tail(&urbp->urb_list, &uhci->complete_list); -} - static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) { dma_addr_t dma_handle; @@ -71,6 +61,18 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) return td; } +static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) +{ + if (!list_empty(&td->list)) + dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); + if (!list_empty(&td->remove_list)) + dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); + if (!list_empty(&td->fl_list)) + dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); + + dma_pool_free(uhci->td_pool, td, td->dma_handle); +} + static inline void uhci_fill_td(struct uhci_td *td, u32 status, u32 token, u32 buffer) { @@ -82,7 +84,8 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status, /* * We insert Isochronous URBs directly into the frame list at the beginning */ -static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) +static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci, + struct uhci_td *td, unsigned framenum) { framenum &= (UHCI_NUMFRAMES - 1); @@ -108,7 +111,7 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, } } -static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, +static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, struct uhci_td *td) { /* If it's not inserted, don't remove it */ @@ -139,48 +142,68 @@ static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci, td->frame = -1; } -static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) +/* + * Remove all the TDs for an Isochronous URB from the frame list + */ +static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; struct uhci_td *td; list_for_each_entry(td, &urbp->td_list, list) - uhci_remove_td_frame_list(uhci, td); + uhci_remove_td_from_frame_list(uhci, td); wmb(); } /* - * Inserts a td list into qh. + * Remove an URB's TDs from the hardware schedule */ -static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth) +static void uhci_remove_tds_from_schedule(struct uhci_hcd *uhci, + struct urb *urb, int status) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - __le32 *plink; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - /* Ordering isn't important here yet since the QH hasn't been */ - /* inserted into the schedule yet */ - plink = &qh->element; - list_for_each_entry(td, &urbp->td_list, list) { - *plink = cpu_to_le32(td->dma_handle) | breadth; - plink = &td->link; + /* Isochronous TDs get unlinked directly from the frame list */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + uhci_unlink_isochronous_tds(uhci, urb); + return; } - *plink = UHCI_PTR_TERM; -} -static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) -{ - if (!list_empty(&td->list)) - dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); - if (!list_empty(&td->remove_list)) - dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); - if (!list_empty(&td->fl_list)) - dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); + /* If the URB isn't first on its queue, adjust the link pointer + * of the last TD in the previous URB. */ + if (urbp->node.prev != &urbp->qh->queue) { + struct urb_priv *purbp; + struct uhci_td *ptd, *ltd; + + if (status == -EINPROGRESS) + status = 0; + purbp = list_entry(urbp->node.prev, struct urb_priv, node); + ptd = list_entry(purbp->td_list.prev, struct uhci_td, + list); + ltd = list_entry(urbp->td_list.prev, struct uhci_td, + list); + ptd->link = ltd->link; + } - dma_pool_free(uhci->td_pool, td, td->dma_handle); + /* If the URB completed with an error, then the QH element certainly + * points to one of the URB's TDs. If it completed normally then + * the QH element has certainly moved on to the next URB. And if + * the URB is still in progress then it must have been dequeued. + * The QH element either hasn't reached it yet or is somewhere in + * the middle. If the URB wasn't first we can assume that it + * hasn't started yet (see above): Otherwise all the preceding URBs + * would have completed and been removed from the queue, so this one + * _would_ be first. + * + * If the QH element is inside this URB, clear it. It will be + * set properly when the QH is activated. + */ + if (status < 0) + urbp->qh->element = UHCI_PTR_TERM; } -static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci) +static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, + struct usb_device *udev, struct usb_host_endpoint *hep) { dma_addr_t dma_handle; struct uhci_qh *qh; @@ -194,256 +217,120 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci) qh->element = UHCI_PTR_TERM; qh->link = UHCI_PTR_TERM; - qh->urbp = NULL; + INIT_LIST_HEAD(&qh->queue); + INIT_LIST_HEAD(&qh->node); - INIT_LIST_HEAD(&qh->list); - INIT_LIST_HEAD(&qh->remove_list); + if (udev) { /* Normal QH */ + qh->state = QH_STATE_IDLE; + qh->hep = hep; + qh->udev = udev; + hep->hcpriv = qh; + usb_get_dev(udev); + } else { /* Skeleton QH */ + qh->state = QH_STATE_ACTIVE; + qh->udev = NULL; + } return qh; } static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - if (!list_empty(&qh->list)) + WARN_ON(qh->state != QH_STATE_IDLE && qh->udev); + if (!list_empty(&qh->queue)) dev_warn(uhci_dev(uhci), "qh %p list not empty!\n", qh); - if (!list_empty(&qh->remove_list)) - dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh); + list_del(&qh->node); + if (qh->udev) { + qh->hep->hcpriv = NULL; + usb_put_dev(qh->udev); + } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } /* - * Append this urb's qh after the last qh in skelqh->list - * - * Note that urb_priv.queue_list doesn't have a separate queue head; - * it's a ring with every element "live". + * Put a QH on the schedule in both hardware and software */ -static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) +static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct urb_priv *turbp; - struct uhci_qh *lqh; + struct uhci_qh *pqh; - /* Grab the last QH */ - lqh = list_entry(skelqh->list.prev, struct uhci_qh, list); + WARN_ON(list_empty(&qh->queue)); - /* Point to the next skelqh */ - urbp->qh->link = lqh->link; - wmb(); /* Ordering is important */ + /* Set the element pointer if it isn't set already. + * This isn't needed for Isochronous queues, but it doesn't hurt. */ + if (qh_element(qh) == UHCI_PTR_TERM) { + struct urb_priv *urbp = list_entry(qh->queue.next, + struct urb_priv, node); + struct uhci_td *td = list_entry(urbp->td_list.next, + struct uhci_td, list); - /* - * Patch QHs for previous endpoint's queued URBs? HC goes - * here next, not to the next skelqh it now points to. - * - * lqh --> td ... --> qh ... --> td --> qh ... --> td - * | | | - * v v v - * +<----------------+-----------------+ - * v - * newqh --> td ... --> td - * | - * v - * ... - * - * The HC could see (and use!) any of these as we write them. - */ - lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - if (lqh->urbp) { - list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list) - turbp->qh->link = lqh->link; + qh->element = cpu_to_le32(td->dma_handle); } - list_add_tail(&urbp->qh->list, &skelqh->list); + if (qh->state == QH_STATE_ACTIVE) + return; + qh->state = QH_STATE_ACTIVE; + + /* Move the QH from its old list to the end of the appropriate + * skeleton's list */ + list_move_tail(&qh->node, &qh->skel->node); + + /* Link it into the schedule */ + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + qh->link = pqh->link; + wmb(); + pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle); } /* - * Start removal of QH from schedule; it finishes next frame. - * TDs should be unlinked before this is called. + * Take a QH off the hardware schedule */ -static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) +static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; - __le32 newlink; - if (!qh) + if (qh->state == QH_STATE_UNLINKING) return; + WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev); + qh->state = QH_STATE_UNLINKING; - /* - * Only go through the hoops if it's actually linked in - */ - if (!list_empty(&qh->list)) { - - /* If our queue is nonempty, make the next URB the head */ - if (!list_empty(&qh->urbp->queue_list)) { - struct urb_priv *nurbp; - - nurbp = list_entry(qh->urbp->queue_list.next, - struct urb_priv, queue_list); - nurbp->queued = 0; - list_add(&nurbp->qh->list, &qh->list); - newlink = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - } else - newlink = qh->link; - - /* Fix up the previous QH's queue to link to either - * the new head of this queue or the start of the - * next endpoint's queue. */ - pqh = list_entry(qh->list.prev, struct uhci_qh, list); - pqh->link = newlink; - if (pqh->urbp) { - struct urb_priv *turbp; - - list_for_each_entry(turbp, &pqh->urbp->queue_list, - queue_list) - turbp->qh->link = newlink; - } - wmb(); - - /* Leave qh->link in case the HC is on the QH now, it will */ - /* continue the rest of the schedule */ - qh->element = UHCI_PTR_TERM; - - list_del_init(&qh->list); - } - - list_del_init(&qh->urbp->queue_list); - qh->urbp = NULL; + /* Unlink the QH from the schedule and record when we did it */ + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + pqh->link = qh->link; + mb(); uhci_get_current_frame_number(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) { - uhci_free_pending_qhs(uhci); - uhci->qh_remove_age = uhci->frame_number; - } + qh->unlink_frame = uhci->frame_number; - /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the QH */ - if (list_empty(&uhci->qh_remove_list)) + /* Force an interrupt so we know when the QH is fully unlinked */ + if (list_empty(&uhci->skel_unlink_qh->node)) uhci_set_next_interrupt(uhci); - list_add(&qh->remove_list, &uhci->qh_remove_list); + /* Move the QH from its old list to the end of the unlinking list */ + list_move_tail(&qh->node, &uhci->skel_unlink_qh->node); } -static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td; - - list_for_each_entry(td, &urbp->td_list, list) { - if (toggle) - td->token |= cpu_to_le32(TD_TOKEN_TOGGLE); - else - td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE); - - toggle ^= 1; - } - - return toggle; -} - -/* This function will append one URB's QH to another URB's QH. This is for */ -/* queuing interrupt, control or bulk transfers */ -static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb) -{ - struct urb_priv *eurbp, *urbp, *furbp, *lurbp; - struct uhci_td *lltd; - - eurbp = eurb->hcpriv; - urbp = urb->hcpriv; - - /* Find the first URB in the queue */ - furbp = eurbp; - if (eurbp->queued) { - list_for_each_entry(furbp, &eurbp->queue_list, queue_list) - if (!furbp->queued) - break; - } - - lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); - - lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); - - /* Control transfers always start with toggle 0 */ - if (!usb_pipecontrol(urb->pipe)) - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), - uhci_fixup_toggle(urb, - uhci_toggle(td_token(lltd)) ^ 1)); - - /* All qhs in the queue need to link to the next queue */ - urbp->qh->link = eurbp->qh->link; - - wmb(); /* Make sure we flush everything */ - - lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; - - list_add_tail(&urbp->queue_list, &furbp->queue_list); - - urbp->queued = 1; -} - -static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) +/* + * When we and the controller are through with a QH, it becomes IDLE. + * This happens when a QH has been off the schedule (on the unlinking + * list) for more than one frame, or when an error occurs while adding + * the first URB onto a new QH. + */ +static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) { - struct urb_priv *urbp, *nurbp, *purbp, *turbp; - struct uhci_td *pltd; - unsigned int toggle; - - urbp = urb->hcpriv; - - if (list_empty(&urbp->queue_list)) - return; - - nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); - - /* - * Fix up the toggle for the following URBs in the queue. - * Only needed for bulk and interrupt: control and isochronous - * endpoints don't propagate toggles between messages. - */ - if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) { - if (!urbp->queued) - /* We just set the toggle in uhci_unlink_generic */ - toggle = usb_gettoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - else { - /* If we're in the middle of the queue, grab the */ - /* toggle from the TD previous to us */ - purbp = list_entry(urbp->queue_list.prev, - struct urb_priv, queue_list); - pltd = list_entry(purbp->td_list.prev, - struct uhci_td, list); - toggle = uhci_toggle(td_token(pltd)) ^ 1; - } - - list_for_each_entry(turbp, &urbp->queue_list, queue_list) { - if (!turbp->queued) - break; - toggle = uhci_fixup_toggle(turbp->urb, toggle); - } + WARN_ON(qh->state == QH_STATE_ACTIVE); - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), toggle); - } - - if (urbp->queued) { - /* We're somewhere in the middle (or end). The case where - * we're at the head is handled in uhci_remove_qh(). */ - purbp = list_entry(urbp->queue_list.prev, struct urb_priv, - queue_list); - - pltd = list_entry(purbp->td_list.prev, struct uhci_td, list); - if (nurbp->queued) - pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - else - /* The next URB happens to be the beginning, so */ - /* we're the last, end the chain */ - pltd->link = UHCI_PTR_TERM; - } + list_move(&qh->node, &uhci->idle_qh_list); + qh->state = QH_STATE_IDLE; - /* urbp->queue_list is handled in uhci_remove_qh() */ + /* If anyone is waiting for a QH to become idle, wake them up */ + if (uhci->num_waiting) + wake_up_all(&uhci->waitqh); } -static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) +static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, + struct urb *urb) { struct urb_priv *urbp; @@ -453,17 +340,14 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u memset((void *)urbp, 0, sizeof(*urbp)); - urbp->fsbrtime = jiffies; urbp->urb = urb; + urb->hcpriv = urbp; + urbp->fsbrtime = jiffies; + INIT_LIST_HEAD(&urbp->node); INIT_LIST_HEAD(&urbp->td_list); - INIT_LIST_HEAD(&urbp->queue_list); INIT_LIST_HEAD(&urbp->urb_list); - list_add_tail(&urbp->urb_list, &uhci->urb_list); - - urb->hcpriv = urbp; - return urbp; } @@ -482,18 +366,17 @@ static void uhci_remove_td_from_urb(struct uhci_td *td) list_del_init(&td->list); } -static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) +static void uhci_free_urb_priv(struct uhci_hcd *uhci, + struct urb_priv *urbp) { struct uhci_td *td, *tmp; - struct urb_priv *urbp; - - urbp = (struct urb_priv *)urb->hcpriv; - if (!urbp) - return; if (!list_empty(&urbp->urb_list)) - dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " - "or uhci->remove_list!\n", urb); + dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list!\n", + urbp->urb); + if (!list_empty(&urbp->node)) + dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", + urbp->urb); uhci_get_current_frame_number(uhci); if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) { @@ -502,7 +385,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) } /* Check to see if the remove list is empty. Set the IOC bit */ - /* to force an interrupt so we can remove the TDs*/ + /* to force an interrupt so we can remove the TDs. */ if (list_empty(&uhci->td_remove_list)) uhci_set_next_interrupt(uhci); @@ -511,7 +394,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) list_add(&td->remove_list, &uhci->td_remove_list); } - urb->hcpriv = NULL; + urbp->urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } @@ -568,17 +451,82 @@ static int uhci_map_status(int status, int dir_out) } /* + * Fix up the data toggles for URBs in a queue, when one of them + * terminates early (short transfer, error, or dequeued). + */ +static void uhci_fixup_toggles(struct urb *urb) +{ + struct list_head *head; + struct uhci_td *td; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + int prevactive = 0; + unsigned int toggle = 0; + struct urb_priv *turbp, *list_end; + + /* + * We need to find out what the last successful toggle was so + * we can update the data toggles for the following transfers. + * + * There are 2 ways the last successful completed TD is found: + * + * 1) The TD is NOT active and the actual length < expected length + * 2) The TD is NOT active and it's the last TD in the chain + * + * and a third way the first uncompleted TD is found: + * + * 3) The TD is active and the previous TD is NOT active + */ + head = &urbp->td_list; + list_for_each_entry(td, head, list) { + unsigned int ctrlstat = td_status(td); + + if (!(ctrlstat & TD_CTRL_ACTIVE) && + (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td)) || + td->list.next == head)) + toggle = uhci_toggle(td_token(td)) ^ 1; + else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) + toggle = uhci_toggle(td_token(td)); + + prevactive = ctrlstat & TD_CTRL_ACTIVE; + } + + /* + * Fix up the toggle for the following URBs in the queue. + * + * We can stop as soon as we find an URB with toggles set correctly, + * because then all the following URBs will be correct also. + */ + list_end = list_entry(&urbp->qh->queue, struct urb_priv, node); + turbp = urbp; + while ((turbp = list_entry(turbp->node.next, struct urb_priv, node)) + != list_end) { + td = list_entry(turbp->td_list.next, struct uhci_td, list); + if (uhci_toggle(td_token(td)) == toggle) + return; + + list_for_each_entry(td, &turbp->td_list, list) { + td->token ^= __constant_cpu_to_le32(TD_TOKEN_TOGGLE); + toggle ^= 1; + } + } + + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), toggle); +} + +/* * Control transfers */ -static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - struct uhci_qh *qh, *skelqh; unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int len = urb->transfer_buffer_length; dma_addr_t data = urb->transfer_dma; + __le32 *plink; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -597,7 +545,8 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(8), - urb->setup_dma); + urb->setup_dma); + plink = &td->link; /* * If direction is "send", change the packet ID from SETUP (0x2D) @@ -615,21 +564,20 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur * Build the DATA TDs */ while (len > 0) { - int pktsze = len; - - if (pktsze > maxsze) - pktsze = maxsze; + int pktsze = min(len, maxsze); td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); /* Alternate Data0/1 (start with Data1) */ destination ^= TD_TOKEN_TOGGLE; uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(pktsze), - data); + data); + plink = &td->link; data += pktsze; len -= pktsze; @@ -641,6 +589,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); /* * It's IN if the pipe is an output pipe or we're not expecting @@ -658,16 +607,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status | TD_CTRL_IOC, - destination | uhci_explen(0), 0); - - qh = uhci_alloc_qh(uhci); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; - - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); + destination | uhci_explen(0), 0); /* Low-speed transfers get a different queue, and won't hog the bus. * Also, some devices enumerate better without FSBR; the easiest way @@ -675,18 +615,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur * isn't in the CONFIGURED state. */ if (urb->dev->speed == USB_SPEED_LOW || urb->dev->state != USB_STATE_CONFIGURED) - skelqh = uhci->skel_ls_control_qh; + qh->skel = uhci->skel_ls_control_qh; else { - skelqh = uhci->skel_fs_control_qh; + qh->skel = uhci->skel_fs_control_qh; uhci_inc_fsbr(uhci, urb); } - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; + return 0; } /* @@ -703,7 +638,7 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - urbp->short_control_packet = 1; + urbp->short_transfer = 1; td = list_entry(urbp->td_list.prev, struct uhci_td, list); urbp->qh->element = cpu_to_le32(td->dma_handle); @@ -720,16 +655,14 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) unsigned int status; int ret = 0; - if (list_empty(&urbp->td_list)) - return -EINVAL; - head = &urbp->td_list; - - if (urbp->short_control_packet) { + if (urbp->short_transfer) { tmp = head->prev; goto status_stage; } + urb->actual_length = 0; + tmp = head->next; td = list_entry(tmp, struct uhci_td, list); @@ -742,8 +675,6 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) if (status) goto td_error; - urb->actual_length = 0; - /* The rest of the TDs (but the last) are data */ tmp = tmp->next; while (tmp != head && tmp->next != head) { @@ -770,10 +701,7 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) goto err; } - if (uhci_packetid(td_token(td)) == USB_PID_IN) - return usb_control_retrigger_status(uhci, urb); - else - return 0; + return usb_control_retrigger_status(uhci, urb); } } @@ -825,15 +753,15 @@ err: /* * Common submit for bulk and interrupt */ -static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh) +static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { struct uhci_td *td; - struct uhci_qh *qh; unsigned long destination, status; - int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize); int len = urb->transfer_buffer_length; - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; dma_addr_t data = urb->transfer_dma; + __le32 *plink, fake_link; if (len < 0) return -EINVAL; @@ -841,7 +769,8 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - status = uhci_maxerr(3) | TD_CTRL_ACTIVE; + /* 3 errors */ + status = TD_CTRL_ACTIVE | uhci_maxerr(3); if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; if (usb_pipein(urb->pipe)) @@ -850,10 +779,11 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb /* * Build the DATA TDs */ + plink = &fake_link; do { /* Allow zero length packets */ int pktsze = maxsze; - if (pktsze >= len) { + if (len <= pktsze) { /* The last packet */ pktsze = len; if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) status &= ~TD_CTRL_SPD; @@ -862,12 +792,15 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(pktsze) | + uhci_fill_td(td, status, + destination | uhci_explen(pktsze) | (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT), data); + plink = &td->link; data += pktsze; len -= maxsze; @@ -883,11 +816,13 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb * however, if transfer_length == 0, the zero packet was already * prepared above. */ - if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) && - !len && urb->transfer_buffer_length) { + if ((urb->transfer_flags & URB_ZERO_PACKET) && + usb_pipeout(urb->pipe) && len == 0 && + urb->transfer_buffer_length > 0) { td = uhci_alloc_td(uhci); if (!td) return -ENOMEM; + *plink = cpu_to_le32(td->dma_handle); uhci_add_td_to_urb(urb, td); uhci_fill_td(td, status, destination | uhci_explen(0) | @@ -905,24 +840,9 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb * fast side but not enough to justify delaying an interrupt * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT * flag setting. */ - td->status |= cpu_to_le32(TD_CTRL_IOC); - - qh = uhci_alloc_qh(uhci); - if (!qh) - return -ENOMEM; - - urbp->qh = qh; - qh->urbp = urbp; + td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); - /* Always breadth first */ - uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); - - if (eurb) - uhci_append_queued_urb(uhci, eurb, urb); - else - uhci_insert_qh(uhci, skelqh, urb); - - return -EINPROGRESS; + return 0; } /* @@ -954,8 +874,24 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; - } else - return 0; + } + + /* + * This URB stopped short of its end. We have to + * fix up the toggles of the following URBs on the + * queue and restart the queue. + * + * Do this only the first time we encounter the + * short URB. + */ + if (!urbp->short_transfer) { + urbp->short_transfer = 1; + uhci_fixup_toggles(urb); + td = list_entry(urbp->td_list.prev, + struct uhci_td, list); + urbp->qh->element = td->link; + } + break; } } @@ -988,7 +924,8 @@ err: return ret; } -static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { int ret; @@ -996,21 +933,22 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struc if (urb->dev->speed == USB_SPEED_LOW) return -EINVAL; - ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh); - if (ret == -EINPROGRESS) + qh->skel = uhci->skel_bulk_qh; + ret = uhci_submit_common(uhci, urb, qh); + if (ret == 0) uhci_inc_fsbr(uhci, urb); - return ret; } -static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb) +static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - /* USB 1.1 interrupt transfers only involve one packet per interval; - * that's the uhci_submit_common() "breadth first" policy. Drivers - * can submit urbs of any length, but longer ones might need many - * intervals to complete. + /* USB 1.1 interrupt transfers only involve one packet per interval. + * Drivers can submit URBs of any length, but longer ones will need + * multiple intervals to complete. */ - return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]); + qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)]; + return uhci_submit_common(uhci, urb, qh); } /* @@ -1072,11 +1010,12 @@ static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) /* * Isochronous transfers */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) +static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - struct uhci_td *td; + struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ int i, ret, frame; - int status, destination; + unsigned long destination, status; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; status = TD_CTRL_ACTIVE | TD_CTRL_IOS; @@ -1092,20 +1031,25 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb) return -ENOMEM; uhci_add_td_to_urb(urb, td); - uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length), - urb->transfer_dma + urb->iso_frame_desc[i].offset); - - if (i + 1 >= urb->number_of_packets) - td->status |= cpu_to_le32(TD_CTRL_IOC); + uhci_fill_td(td, status, destination | + uhci_explen(urb->iso_frame_desc[i].length), + urb->transfer_dma + + urb->iso_frame_desc[i].offset); } + /* Set the interrupt-on-completion flag on the last packet. */ + td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); + + qh->skel = uhci->skel_iso_qh; + + /* Add the TDs to the frame list */ frame = urb->start_frame; list_for_each_entry(td, &urbp->td_list, list) { - uhci_insert_td_frame_list(uhci, td, frame); + uhci_insert_td_in_frame_list(uhci, td, frame); frame += urb->interval; } - return -EINPROGRESS; + return 0; } static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) @@ -1139,80 +1083,67 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) i++; } - unlink_isochronous_tds(uhci, urb); return ret; } -static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *up; - - /* We don't match Isoc transfers since they are special */ - if (usb_pipeisoc(urb->pipe)) - return NULL; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - if (u->dev == urb->dev && u->status == -EINPROGRESS) { - /* For control, ignore the direction */ - if (usb_pipecontrol(urb->pipe) && - (u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN)) - return u; - else if (u->pipe == urb->pipe) - return u; - } - } - - return NULL; -} - static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct usb_host_endpoint *ep, + struct usb_host_endpoint *hep, struct urb *urb, gfp_t mem_flags) { int ret; struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long flags; - struct urb *eurb; + struct urb_priv *urbp; + struct uhci_qh *qh; int bustime; spin_lock_irqsave(&uhci-> |