From dccf4a48d47120a42382ba526f1a0848c13ba2a4 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 17:58:46 -0500 Subject: [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 Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 65 ++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 24 deletions(-) (limited to 'drivers/usb/host/uhci-hcd.c') diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index dfe121d3588..1ff4b880637 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -54,7 +54,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v2.3" +#define DRIVER_VERSION "v3.0" #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \ Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \ Alan Stern" @@ -489,15 +489,11 @@ static int uhci_start(struct usb_hcd *hcd) uhci->fsbrtimeout = 0; spin_lock_init(&uhci->lock); - INIT_LIST_HEAD(&uhci->qh_remove_list); INIT_LIST_HEAD(&uhci->td_remove_list); - - INIT_LIST_HEAD(&uhci->urb_remove_list); - INIT_LIST_HEAD(&uhci->urb_list); - INIT_LIST_HEAD(&uhci->complete_list); + INIT_LIST_HEAD(&uhci->idle_qh_list); init_waitqueue_head(&uhci->waitqh); @@ -540,7 +536,7 @@ static int uhci_start(struct usb_hcd *hcd) } for (i = 0; i < UHCI_NUM_SKELQH; i++) { - uhci->skelqh[i] = uhci_alloc_qh(uhci); + uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL); if (!uhci->skelqh[i]) { dev_err(uhci_dev(uhci), "unable to allocate QH\n"); goto err_alloc_skelqh; @@ -557,13 +553,17 @@ static int uhci_start(struct usb_hcd *hcd) uhci->skel_int16_qh->link = uhci->skel_int8_qh->link = uhci->skel_int4_qh->link = - uhci->skel_int2_qh->link = - cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH; - - uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH; + uhci->skel_int2_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_int1_qh->dma_handle); + + uhci->skel_int1_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_ls_control_qh->dma_handle); + uhci->skel_ls_control_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_fs_control_qh->dma_handle); + uhci->skel_fs_control_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_bulk_qh->dma_handle); + uhci->skel_bulk_qh->link = UHCI_PTR_QH | + cpu_to_le32(uhci->skel_term_qh->dma_handle); /* This dummy TD is to work around a bug in Intel PIIX controllers */ uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | @@ -589,15 +589,15 @@ static int uhci_start(struct usb_hcd *hcd) /* * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc. - * ffs > 6 => not on any high-period queue, so use - * skel_int1_qh = skelqh[7]. + * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], + * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * ffs >= 7 => not on any high-period queue, so use + * skel_int1_qh = skelqh[9]. * Add UHCI_NUMFRAMES to insure at least one bit is set. */ - irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES); - if (irq < 0) - irq = 7; + irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); + if (irq <= 1) + irq = 9; /* Only place we don't use the frame list routines */ uhci->frame[i] = UHCI_PTR_QH | @@ -767,13 +767,30 @@ static int uhci_resume(struct usb_hcd *hcd) } #endif -/* Wait until all the URBs for a particular device/endpoint are gone */ +/* Wait until a particular device/endpoint's QH is idle, and free it */ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) + struct usb_host_endpoint *hep) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); + struct uhci_qh *qh; + + spin_lock_irq(&uhci->lock); + qh = (struct uhci_qh *) hep->hcpriv; + if (qh == NULL) + goto done; - wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list)); + while (qh->state != QH_STATE_IDLE) { + ++uhci->num_waiting; + spin_unlock_irq(&uhci->lock); + wait_event_interruptible(uhci->waitqh, + qh->state == QH_STATE_IDLE); + spin_lock_irq(&uhci->lock); + --uhci->num_waiting; + } + + uhci_free_qh(uhci, qh); +done: + spin_unlock_irq(&uhci->lock); } static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) -- cgit v1.2.3-70-g09d2 From 0ed8fee1c1d38a62e981025ba40b5eba30c4ce2a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 18:02:38 -0500 Subject: [PATCH] UHCI: remove main list of URBs As part of reorienting uhci-hcd away from URBs and toward endpoint queues, this patch (as625) eliminates the driver's main list of URBs. The list wsa used mainly in checking for URB completions; now the driver goes through the list of active endpoints and checks the members of the queues. As a side effect, I had to remove the code that looks for FSBR timeouts. For now, FSBR will remain on so long as any URBs on a full-speed control or bulk queue request it, even if the queue isn't advancing. A later patch can add more intelligent handling. This isn't a huge drawback; it's pretty rare for an URB to get stuck for more than a fraction of a second. (And it will help the people trying to use those insane HP USB devices.) Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 1 - drivers/usb/host/uhci-hcd.c | 2 - drivers/usb/host/uhci-hcd.h | 15 +- drivers/usb/host/uhci-q.c | 631 ++++++++++++++++++------------------------ 4 files changed, 279 insertions(+), 370 deletions(-) (limited to 'drivers/usb/host/uhci-hcd.c') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 6814783adf9..f2f5f8ce171 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -114,7 +114,6 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) } out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : "")); - out += sprintf(out, "%s", (urbp->fsbr_timeout ? " FSBR_TO" : "")); if (urbp->urb->status != -EINPROGRESS) out += sprintf(out, " Status=%d", urbp->urb->status); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 1ff4b880637..9865f303d3f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -491,8 +491,6 @@ static int uhci_start(struct usb_hcd *hcd) spin_lock_init(&uhci->lock); INIT_LIST_HEAD(&uhci->td_remove_list); - INIT_LIST_HEAD(&uhci->urb_list); - INIT_LIST_HEAD(&uhci->complete_list); INIT_LIST_HEAD(&uhci->idle_qh_list); init_waitqueue_head(&uhci->waitqh); diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index c057956667b..7e96bef2e88 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -132,6 +132,10 @@ struct uhci_qh { unsigned int unlink_frame; /* When the QH was unlinked */ int state; /* QH_STATE_xxx; see above */ + + unsigned int initial_toggle:1; /* Endpoint's current toggle value */ + unsigned int needs_fixup:1; /* Must fix the TD toggle values */ + unsigned int is_stopped:1; /* Queue was stopped by an error */ } __attribute__((aligned(16))); /* @@ -384,6 +388,7 @@ struct uhci_hcd { struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */ + struct uhci_qh *next_qh; /* Next QH to scan */ spinlock_t lock; @@ -413,16 +418,10 @@ struct uhci_hcd { unsigned long resuming_ports; unsigned long ports_timeout; /* Time to stop signalling */ - /* Main list of URBs currently controlled by this HC */ - struct list_head urb_list; - /* List of TDs that are done, but waiting to be freed (race) */ struct list_head td_remove_list; unsigned int td_remove_age; /* Age in frames */ - /* List of URBs awaiting completion callback */ - struct list_head complete_list; - struct list_head idle_qh_list; /* Where the idle QHs live */ int rh_numports; /* Number of root-hub ports */ @@ -448,7 +447,6 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) * Private per-URB data */ struct urb_priv { - struct list_head urb_list; struct list_head node; /* Node in the QH's urbp list */ struct urb *urb; @@ -456,10 +454,7 @@ struct urb_priv { struct uhci_qh *qh; /* QH for this URB */ struct list_head td_list; - unsigned long fsbrtime; /* In jiffies */ - unsigned fsbr : 1; /* URB turned on FSBR */ - unsigned fsbr_timeout : 1; /* URB timed out on FSBR */ unsigned short_transfer : 1; /* URB got a short transfer, no * need to rescan */ }; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index c4194182dcc..44bba9a6d19 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -151,53 +151,6 @@ static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) wmb(); } -/* - * Remove an URB's TDs from the hardware schedule - */ -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; - - /* Isochronous TDs get unlinked directly from the frame list */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - uhci_unlink_isochronous_tds(uhci, urb); - return; - } - - /* 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; - } - - /* 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, struct usb_device *udev, struct usb_host_endpoint *hep) { @@ -250,6 +203,90 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } +/* + * When the currently executing URB is dequeued, save its current toggle value + */ +static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) +{ + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; + struct uhci_td *td; + + /* If the QH element pointer is UHCI_PTR_TERM then then currently + * executing URB has already been unlinked, so this one isn't it. */ + if (qh_element(qh) == UHCI_PTR_TERM || + qh->queue.next != &urbp->node) + return; + qh->element = UHCI_PTR_TERM; + + /* Only bulk and interrupt pipes have to worry about toggles */ + if (!(usb_pipetype(urb->pipe) == PIPE_BULK || + usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) + return; + + /* Find the first active TD; that's the device's toggle state */ + list_for_each_entry(td, &urbp->td_list, list) { + if (td_status(td) & TD_CTRL_ACTIVE) { + qh->needs_fixup = 1; + qh->initial_toggle = uhci_toggle(td_token(td)); + return; + } + } + + WARN_ON(1); +} + +/* + * 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 uhci_qh *qh, int skip_first) +{ + struct urb_priv *urbp = NULL; + struct uhci_td *td; + unsigned int toggle = qh->initial_toggle; + unsigned int pipe; + + /* Fixups for a short transfer start with the second URB in the + * queue (the short URB is the first). */ + if (skip_first) + urbp = list_entry(qh->queue.next, struct urb_priv, node); + + /* When starting with the first URB, if the QH element pointer is + * still valid then we know the URB's toggles are okay. */ + else if (qh_element(qh) != UHCI_PTR_TERM) + toggle = 2; + + /* Fix up the toggle for the URBs in the queue. Normally this + * loop won't run more than once: When an error or short transfer + * occurs, the queue usually gets emptied. */ + list_prepare_entry(urbp, &qh->queue, node); + list_for_each_entry_continue(urbp, &qh->queue, node) { + + /* If the first TD has the right toggle value, we don't + * need to change any toggles in this URB */ + td = list_entry(urbp->td_list.next, struct uhci_td, list); + if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) { + td = list_entry(urbp->td_list.next, struct uhci_td, + list); + toggle = uhci_toggle(td_token(td)) ^ 1; + + /* Otherwise all the toggles in the URB have to be switched */ + } else { + list_for_each_entry(td, &urbp->td_list, list) { + td->token ^= __constant_cpu_to_le32( + TD_TOKEN_TOGGLE); + toggle ^= 1; + } + } + } + + wmb(); + pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe; + usb_settoggle(qh->udev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), toggle); + qh->needs_fixup = 0; +} + /* * Put a QH on the schedule in both hardware and software */ @@ -276,6 +313,9 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) /* Move the QH from its old list to the end of the appropriate * skeleton's list */ + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move_tail(&qh->node, &qh->skel->node); /* Link it into the schedule */ @@ -310,6 +350,9 @@ static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) uhci_set_next_interrupt(uhci); /* Move the QH from its old list to the end of the unlinking list */ + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move_tail(&qh->node, &uhci->skel_unlink_qh->node); } @@ -323,6 +366,9 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) { WARN_ON(qh->state == QH_STATE_ACTIVE); + if (qh == uhci->next_qh) + uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, + node); list_move(&qh->node, &uhci->idle_qh_list); qh->state = QH_STATE_IDLE; @@ -344,11 +390,9 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, urbp->urb = urb; urb->hcpriv = urbp; - urbp->fsbrtime = jiffies; INIT_LIST_HEAD(&urbp->node); INIT_LIST_HEAD(&urbp->td_list); - INIT_LIST_HEAD(&urbp->urb_list); return urbp; } @@ -373,9 +417,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, { struct uhci_td *td, *tmp; - if (!list_empty(&urbp->urb_list)) - 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); @@ -452,71 +493,6 @@ static int uhci_map_status(int status, int dir_out) return 0; } -/* - * 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 */ @@ -765,6 +741,9 @@ err: } } + /* Note that the queue has stopped */ + urbp->qh->element = UHCI_PTR_TERM; + urbp->qh->is_stopped = 1; return ret; } @@ -927,7 +906,10 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) */ if (!urbp->short_transfer) { urbp->short_transfer = 1; - uhci_fixup_toggles(urb); + urbp->qh->initial_toggle = + uhci_toggle(td_token(td)) ^ 1; + uhci_fixup_toggles(urbp->qh, 1); + td = list_entry(urbp->td_list.prev, struct uhci_td, list); urbp->qh->element = td->link; @@ -962,6 +944,13 @@ err: } } #endif + + /* Note that the queue has stopped and save the next toggle value */ + urbp->qh->element = UHCI_PTR_TERM; + urbp->qh->is_stopped = 1; + urbp->qh->needs_fixup = 1; + urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^ + (ret == -EREMOTEIO); return ret; } @@ -995,76 +984,39 @@ static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, /* * Isochronous transfers */ -static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) -{ - struct urb *last_urb = NULL; - struct urb_priv *up; - int ret = 0; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - /* look for pending URBs with identical pipe handle */ - if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && - (u->status == -EINPROGRESS) && (u != urb)) { - if (!last_urb) - *start = u->start_frame; - last_urb = u; - } - } - - if (last_urb) { - *end = (last_urb->start_frame + last_urb->number_of_packets * - last_urb->interval) & (UHCI_NUMFRAMES-1); - ret = 0; - } else - ret = -1; /* no previous urb found */ - - return ret; -} - -static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb) +static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, + struct uhci_qh *qh) { - int limits; - unsigned int start = 0, end = 0; + struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ + int i, frame; + unsigned long destination, status; + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; if (urb->number_of_packets > 900) /* 900? Why? */ return -EFBIG; - limits = isochronous_find_limits(uhci, urb, &start, &end); + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; + destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); + /* Figure out the starting frame number */ if (urb->transfer_flags & URB_ISO_ASAP) { - if (limits) { + if (list_empty(&qh->queue)) { uhci_get_current_frame_number(uhci); - urb->start_frame = (uhci->frame_number + 10) - & (UHCI_NUMFRAMES - 1); - } else - urb->start_frame = end; + urb->start_frame = (uhci->frame_number + 10); + + } else { /* Go right after the last one */ + struct urb *last_urb; + + last_urb = list_entry(qh->queue.prev, + struct urb_priv, node)->urb; + urb->start_frame = (last_urb->start_frame + + last_urb->number_of_packets * + last_urb->interval); + } } else { - urb->start_frame &= (UHCI_NUMFRAMES - 1); /* FIXME: Sanity check */ } - - return 0; -} - -/* - * Isochronous transfers - */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, ret, frame; - unsigned long destination, status; - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - - status = TD_CTRL_ACTIVE | TD_CTRL_IOS; - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - - ret = isochronous_find_start(uhci, urb); - if (ret) - return ret; + urb->start_frame &= (UHCI_NUMFRAMES - 1); for (i = 0; i < urb->number_of_packets; i++) { td = uhci_alloc_td(uhci); @@ -1203,7 +1155,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, /* Add this URB to the QH */ urbp->qh = qh; list_add_tail(&urbp->node, &qh->queue); - list_add_tail(&urbp->urb_list, &uhci->urb_list); /* If the new URB is the first and only one on this QH then either * the QH is new and idle or else it's unlinked and waiting to @@ -1224,49 +1175,66 @@ done: return ret; } +static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + struct uhci_hcd *uhci = hcd_to_uhci(hcd); + unsigned long flags; + struct urb_priv *urbp; + + spin_lock_irqsave(&uhci->lock, flags); + urbp = urb->hcpriv; + if (!urbp) /* URB was never linked! */ + goto done; + + /* Remove Isochronous TDs from the frame list ASAP */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + uhci_unlink_isochronous_tds(uhci, urb); + uhci_unlink_qh(uhci, urbp->qh); + +done: + spin_unlock_irqrestore(&uhci->lock, flags); + return 0; +} + /* - * Return the result of a transfer + * Finish unlinking an URB and give it back */ -static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) +static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, + struct urb *urb, struct pt_regs *regs) +__releases(uhci->lock) +__acquires(uhci->lock) { - int status; - int okay_to_giveback = 0; struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - status = uhci_result_control(uhci, urb); - break; - case PIPE_ISOCHRONOUS: - status = uhci_result_isochronous(uhci, urb); - break; - default: /* PIPE_BULK or PIPE_INTERRUPT */ - status = uhci_result_common(uhci, urb); - break; - } + /* Isochronous TDs get unlinked directly from the frame list */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + uhci_unlink_isochronous_tds(uhci, urb); - spin_lock(&urb->lock); - if (urb->status == -EINPROGRESS) { /* Not yet dequeued */ - if (status != -EINPROGRESS) { /* URB has completed */ - urb->status = status; + /* If the URB isn't first on its queue, adjust the link pointer + * of the last TD in the previous URB. */ + else if (qh->queue.next != &urbp->node) { + struct urb_priv *purbp; + struct uhci_td *ptd, *ltd; - /* If the URB got a real error (as opposed to - * simply being dequeued), we don't have to - * unlink the QH. Fix this later... */ - if (status < 0) - uhci_unlink_qh(uhci, urbp->qh); - else - okay_to_giveback = 1; - } - } else { /* Already dequeued */ - if (urbp->qh->state == QH_STATE_UNLINKING && - uhci->frame_number + uhci->is_stopped != - urbp->qh->unlink_frame) - okay_to_giveback = 1; + 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; } - spin_unlock(&urb->lock); - if (!okay_to_giveback) - return; + + /* Take the URB off the QH's queue. If the queue is now empty, + * this is a perfect time for a toggle fixup. */ + list_del_init(&urbp->node); + if (list_empty(&qh->queue) && qh->needs_fixup) { + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), qh->initial_toggle); + qh->needs_fixup = 0; + } + + uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + uhci_free_urb_priv(uhci, urbp); switch (usb_pipetype(urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -1277,122 +1245,107 @@ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) case PIPE_INTERRUPT: /* Release bandwidth for Interrupt or Isoc. transfers */ /* Make sure we don't release if we have a queued URB */ - if (list_empty(&urbp->qh->queue) && urb->bandwidth) + if (list_empty(&qh->queue) && urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); else /* bandwidth was passed on to queued URB, */ /* so don't let usb_unlink_urb() release it */ urb->bandwidth = 0; - /* Falls through */ - case PIPE_BULK: - if (status < 0) - uhci_fixup_toggles(urb); - break; - default: /* PIPE_CONTROL */ break; } - /* Take the URB's TDs off the hardware schedule */ - uhci_remove_tds_from_schedule(uhci, urb, status); - - /* Take the URB off the QH's queue and see if the QH is now unused */ - list_del_init(&urbp->node); - if (list_empty(&urbp->qh->queue)) - uhci_unlink_qh(uhci, urbp->qh); + spin_unlock(&uhci->lock); + usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs); + spin_lock(&uhci->lock); - uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ + /* If the queue is now empty, we can unlink the QH and give up its + * reserved bandwidth. */ + if (list_empty(&qh->queue)) { + uhci_unlink_qh(uhci, qh); - /* Queue it for giving back */ - list_move_tail(&urbp->urb_list, &uhci->complete_list); + /* Bandwidth stuff not yet implemented */ + } } /* - * Check out the QHs waiting to be fully unlinked + * Scan the URBs in a QH's queue */ -static void uhci_scan_unlinking_qhs(struct uhci_hcd *uhci) -{ - struct uhci_qh *qh, *tmp; +#define QH_FINISHED_UNLINKING(qh) \ + (qh->state == QH_STATE_UNLINKING && \ + uhci->frame_number + uhci->is_stopped != qh->unlink_frame) - list_for_each_entry_safe(qh, tmp, &uhci->skel_unlink_qh->node, node) { - - /* If the queue is empty and the QH is fully unlinked then - * it can become IDLE. */ - if (list_empty(&qh->queue)) { - if (uhci->frame_number + uhci->is_stopped != - qh->unlink_frame) - uhci_make_qh_idle(uhci, qh); - - /* If none of the QH's URBs have been dequeued then the QH - * should be re-activated. */ - } else { - struct urb_priv *urbp; - int any_dequeued = 0; - - list_for_each_entry(urbp, &qh->queue, node) { - if (urbp->urb->status != -EINPROGRESS) { - any_dequeued = 1; - break; - } - } - if (!any_dequeued) - uhci_activate_qh(uhci, qh); - } - } -} - -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, + struct pt_regs *regs) { - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; struct urb_priv *urbp; + struct urb *urb; + int status; - spin_lock_irqsave(&uhci->lock, flags); - urbp = urb->hcpriv; - if (!urbp) /* URB was never linked! */ - goto done; + while (!list_empty(&qh->queue)) { + urbp = list_entry(qh->queue.next, struct urb_priv, node); + urb = urbp->urb; - /* Remove Isochronous TDs from the frame list ASAP */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - uhci_unlink_isochronous_tds(uhci, urb); - uhci_unlink_qh(uhci, urbp->qh); + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + status = uhci_result_control(uhci, urb); + break; + case PIPE_ISOCHRONOUS: + status = uhci_result_isochronous(uhci, urb); + break; + default: /* PIPE_BULK or PIPE_INTERRUPT */ + status = uhci_result_common(uhci, urb); + break; + } + if (status == -EINPROGRESS) + break; -done: - spin_unlock_irqrestore(&uhci->lock, flags); - return 0; -} + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) /* Not dequeued */ + urb->status = status; + else + status = -ECONNRESET; + spin_unlock(&urb->lock); -static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head; - struct uhci_td *td; - int count = 0; + /* Dequeued but completed URBs can't be given back unless + * the QH is stopped or has finished unlinking. */ + if (status == -ECONNRESET && + !(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) + return; - uhci_dec_fsbr(uhci, urb); + uhci_giveback_urb(uhci, qh, urb, regs); + if (qh->is_stopped) + break; + } - urbp->fsbr_timeout = 1; + /* If the QH is neither stopped nor finished unlinking (normal case), + * our work here is done. */ + restart: + if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) + return; - /* - * Ideally we would want to fix qh->element as well, but it's - * read/write by the HC, so that can introduce a race. It's not - * really worth the hassle - */ + /* Otherwise give back each of the dequeued URBs */ + list_for_each_entry(urbp, &qh->queue, node) { + urb = urbp->urb; + if (urb->status != -EINPROGRESS) { + uhci_save_toggle(qh, urb); + uhci_giveback_urb(uhci, qh, urb, regs); + goto restart; + } + } + qh->is_stopped = 0; - head = &urbp->td_list; - list_for_each_entry(td, head, list) { - /* - * Make sure we don't do the last one (since it'll have the - * TERM bit set) as well as we skip every so many TDs to - * make sure it doesn't hog the bandwidth - */ - if (td->list.next != head && (count % DEPTH_INTERVAL) == - (DEPTH_INTERVAL - 1)) - td->link |= UHCI_PTR_DEPTH; - - count++; + /* There are no more dequeued URBs. If there are still URBs on the + * queue, the QH can now be re-activated. */ + if (!list_empty(&qh->queue)) { + if (qh->needs_fixup) + uhci_fixup_toggles(qh, 0); + uhci_activate_qh(uhci, qh); } - return 0; + /* The queue is empty. The QH can become idle if it is fully + * unlinked. */ + else if (QH_FINISHED_UNLINKING(qh)) + uhci_make_qh_idle(uhci, qh); } static void uhci_free_pending_tds(struct uhci_hcd *uhci) @@ -1406,36 +1359,13 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci) } } -static void -uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) -__releases(uhci->lock) -__acquires(uhci->lock) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - uhci_free_urb_priv(uhci, (struct urb_priv *) (urb->hcpriv)); - - spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(hcd, urb, regs); - spin_lock(&uhci->lock); -} - -static void uhci_finish_completion(struct uhci_hcd *uhci, struct pt_regs *regs) -{ - struct urb_priv *urbp, *tmp; - - list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) { - struct urb *urb = urbp->urb; - - list_del_init(&urbp->urb_list); - uhci_finish_urb(uhci_to_hcd(uhci), urb, regs); - } -} - -/* Process events in the schedule, but only in one thread at a time */ +/* + * Process events in the schedule, but only in one thread at a time + */ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) { - struct urb_priv *urbp, *tmp; + int i; + struct uhci_qh *qh; /* Don't allow re-entrant calls */ if (uhci->scan_in_progress) { @@ -1452,26 +1382,24 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) uhci_free_pending_tds(uhci); - /* Walk the list of pending URBs to see which ones completed - * (must be _safe because uhci_transfer_result() dequeues URBs) */ - list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { - struct urb *urb = urbp->urb; - - /* Checks the status and does all of the magic necessary */ - uhci_transfer_result(uhci, urb); + /* Go through all the QH queues and process the URBs in each one */ + for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { + uhci->next_qh = list_entry(uhci->skelqh[i]->node.next, + struct uhci_qh, node); + while ((qh = uhci->next_qh) != uhci->skelqh[i]) { + uhci->next_qh = list_entry(qh->node.next, + struct uhci_qh, node); + uhci_scan_qh(uhci, qh, regs); + } } - uhci_finish_completion(uhci, regs); - - /* If the controller is stopped, we can finish these off right now */ - if (uhci->is_stopped) - uhci_free_pending_tds(uhci); if (uhci->need_rescan) goto rescan; uhci->scan_in_progress = 0; - /* Check out the QHs waiting for unlinking */ - uhci_scan_unlinking_qhs(uhci); + /* If the controller is stopped, we can finish these off right now */ + if (uhci->is_stopped) + uhci_free_pending_tds(uhci); if (list_empty(&uhci->td_remove_list) && list_empty(&uhci->skel_unlink_qh->node)) @@ -1482,19 +1410,8 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) static void check_fsbr(struct uhci_hcd *uhci) { - struct urb_priv *up; - - list_for_each_entry(up, &uhci->urb_list, urb_list) { - struct urb *u = up->urb; - - spin_lock(&u->lock); - - /* Check if the FSBR timed out */ - if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) - uhci_fsbr_timeout(uhci, u); - - spin_unlock(&u->lock); - } + /* For now, don't scan URBs for FSBR timeouts. + * Add it back in later... */ /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { -- cgit v1.2.3-70-g09d2 From 8d402e1ae03656c1ad215514f8885ef4793f0948 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Sat, 17 Dec 2005 18:03:37 -0500 Subject: [PATCH] UHCI: improve debugging code This patch (as626) makes some improvements to the debugging code in uhci-hcd. The main change is that now the code won't get compiled if CONFIG_USB_DEBUG isn't set. But there are other changes too, like adding a missing .owner field and printing a debugging dump if the controller dies. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-debug.c | 36 +++++++++++++++++++++----- drivers/usb/host/uhci-hcd.c | 60 ++++++++++++++++++++++++++++--------------- drivers/usb/host/uhci-hcd.h | 1 + drivers/usb/host/uhci-q.c | 12 +-------- 4 files changed, 70 insertions(+), 39 deletions(-) (limited to 'drivers/usb/host/uhci-hcd.c') diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index f2f5f8ce171..e1239319655 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -17,10 +17,13 @@ #include "uhci-hcd.h" -static struct dentry *uhci_debugfs_root = NULL; +#define uhci_debug_operations (* (struct file_operations *) NULL) +static struct dentry *uhci_debugfs_root; + +#ifdef DEBUG /* Handle REALLY large printks so we don't overflow buffers */ -static inline void lprintk(char *buf) +static void lprintk(char *buf) { char *p; @@ -196,7 +199,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) return out - buf; } -#ifdef CONFIG_PROC_FS static const char * const qh_names[] = { "skel_unlink_qh", "skel_iso_qh", "skel_int128_qh", "skel_int64_qh", @@ -393,12 +395,13 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) return out - buf; } +#ifdef CONFIG_DEBUG_FS + #define MAX_OUTPUT (64 * 1024) struct uhci_debug { int size; char *data; - struct uhci_hcd *uhci; }; static int uhci_debug_open(struct inode *inode, struct file *file) @@ -419,8 +422,10 @@ static int uhci_debug_open(struct inode *inode, struct file *file) goto out; } + up->size = 0; spin_lock_irqsave(&uhci->lock, flags); - up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); + if (uhci->is_initialized) + up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); spin_unlock_irqrestore(&uhci->lock, flags); file->private_data = up; @@ -472,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file) return 0; } +#undef uhci_debug_operations static struct file_operations uhci_debug_operations = { + .owner = THIS_MODULE, .open = uhci_debug_open, .llseek = uhci_debug_lseek, .read = uhci_debug_read, .release = uhci_debug_release, }; -#else /* CONFIG_DEBUG_FS */ +#endif /* CONFIG_DEBUG_FS */ -#define uhci_debug_operations (* (struct file_operations *) NULL) +#else /* DEBUG */ + +static inline void lprintk(char *buf) +{} + +static inline int uhci_show_qh(struct uhci_qh *qh, char *buf, + int len, int space) +{ + return 0; +} + +static inline int uhci_sprint_schedule(struct uhci_hcd *uhci, + char *buf, int len) +{ + return 0; +} #endif diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 9865f303d3f..4edb8330c44 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -68,12 +68,16 @@ Alan Stern" * debug = 3, show all TDs in URBs when dumping */ #ifdef DEBUG +#define DEBUG_CONFIGURED 1 static int debug = 1; -#else -static int debug = 0; -#endif module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); + +#else +#define DEBUG_CONFIGURED 0 +#define debug 0 +#endif + static char *errbuf; #define ERRBUF_LEN (32 * 1024) @@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); + if (debug > 1 && errbuf) { + /* Print the schedule for debugging */ + uhci_sprint_schedule(uhci, + errbuf, ERRBUF_LEN); + lprintk(errbuf); + } hc_died(uhci); /* Force a callback in case there are @@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci) { int i; + if (DEBUG_CONFIGURED) { + spin_lock_irq(&uhci->lock); + uhci->is_initialized = 0; + spin_unlock_irq(&uhci->lock); + + debugfs_remove(uhci->dentry); + } + for (i = 0; i < UHCI_NUM_SKELQH; i++) uhci_free_qh(uhci, uhci->skelqh[i]); @@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd *uhci) dma_free_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), uhci->frame, uhci->frame_dma_handle); - - debugfs_remove(uhci->dentry); } static int uhci_reset(struct usb_hcd *hcd) @@ -474,17 +490,6 @@ static int uhci_start(struct usb_hcd *hcd) hcd->uses_new_polling = 1; - dentry = debugfs_create_file(hcd->self.bus_name, - S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, - &uhci_debug_operations); - if (!dentry) { - dev_err(uhci_dev(uhci), - "couldn't create uhci debugfs entry\n"); - retval = -ENOMEM; - goto err_create_debug_entry; - } - uhci->dentry = dentry; - uhci->fsbr = 0; uhci->fsbrtimeout = 0; @@ -495,6 +500,19 @@ static int uhci_start(struct usb_hcd *hcd) init_waitqueue_head(&uhci->waitqh); + if (DEBUG_CONFIGURED) { + dentry = debugfs_create_file(hcd->self.bus_name, + S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, + uhci, &uhci_debug_operations); + if (!dentry) { + dev_err(uhci_dev(uhci), "couldn't create uhci " + "debugfs entry\n"); + retval = -ENOMEM; + goto err_create_debug_entry; + } + uhci->dentry = dentry; + } + uhci->frame = dma_alloc_coherent(uhci_dev(uhci), UHCI_NUMFRAMES * sizeof(*uhci->frame), &uhci->frame_dma_handle, 0); @@ -609,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd) mb(); configure_hc(uhci); + uhci->is_initialized = 1; start_rh(uhci); return 0; @@ -872,16 +891,15 @@ static int __init uhci_hcd_init(void) if (usb_disabled()) return -ENODEV; - if (debug) { + if (DEBUG_CONFIGURED) { errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) goto errbuf_failed; + uhci_debugfs_root = debugfs_create_dir("uhci", NULL); + if (!uhci_debugfs_root) + goto debug_failed; } - uhci_debugfs_root = debugfs_create_dir("uhci", NULL); - if (!uhci_debugfs_root) - goto debug_failed; - uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL, NULL); if (!uhci_up_cachep) diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 7e96bef2e88..4a69c7eb09b 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -411,6 +411,7 @@ struct uhci_hcd { unsigned int hc_inaccessible:1; /* HC is suspended or dead */ unsigned int working_RD:1; /* Suspended root hub doesn't need to be polled */ + unsigned int is_initialized:1; /* Data structure is usable */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 44bba9a6d19..5d6c4f75d0d 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -736,7 +736,6 @@ err: if (errbuf) { /* Print the chain for debugging purposes */ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - lprintk(errbuf); } } @@ -924,26 +923,17 @@ td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); err: - /* - * Enable this chunk of code if you want to see some more debugging. - * But be careful, it has the tendancy to starve out khubd and prevent - * disconnects from happening successfully if you have a slow debug - * log interface (like a serial console. - */ -#if 0 if ((debug == 1 && ret != -EPIPE) || debug > 1) { /* Some debugging code */ dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", __FUNCTION__, status); - if (errbuf) { + if (debug > 1 && errbuf) { /* Print the chain for debugging purposes */ uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); - lprintk(errbuf); } } -#endif /* Note that the queue has stopped and save the next toggle value */ urbp->qh->element = UHCI_PTR_TERM; -- cgit v1.2.3-70-g09d2