X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fohci-q.c;h=51817322232b453a5f6c881809d542e9315e0f76;hb=4735b37cf434175c2b7b36b3b68f1e60e8ec8527;hp=fe1fe2f97cb5bbff22371cce9ca60dcf01842878;hpb=513b046c96cc2fbce730a3474f6f7ff0c4fdd05c;p=linux-2.6-omap-h63xx.git diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index fe1fe2f97cb..51817322232 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1,9 +1,9 @@ /* * OHCI HCD (Host Controller Driver) for USB. - * + * * (C) Copyright 1999 Roman Weissgaerber * (C) Copyright 2000-2002 David Brownell - * + * * This file is licenced under the GPL. */ @@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) * PRECONDITION: ohci lock held, irqs blocked. */ static void -finish_urb (struct ohci_hcd *ohci, struct urb *urb) +finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) __releases(ohci->lock) __acquires(ohci->lock) { // ASSERT (urb->hcpriv != 0); urb_free_priv (ohci, urb->hcpriv); - urb->hcpriv = NULL; - - spin_lock (&urb->lock); - if (likely (urb->status == -EINPROGRESS)) - urb->status = 0; - /* report short control reads right even though the data TD always - * has TD_R set. (much simpler, but creates the 1-td limit.) - */ - if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK) - && unlikely (usb_pipecontrol (urb->pipe)) - && urb->actual_length < urb->transfer_buffer_length - && usb_pipein (urb->pipe) - && urb->status == 0) { - urb->status = -EREMOTEIO; - } - spin_unlock (&urb->lock); + if (likely(status == -EINPROGRESS)) + status = 0; switch (usb_pipetype (urb->pipe)) { case PIPE_ISOCHRONOUS: @@ -70,12 +56,13 @@ __acquires(ohci->lock) } #ifdef OHCI_VERBOSE_DEBUG - urb_print (urb, "RET", usb_pipeout (urb->pipe)); + urb_print(urb, "RET", usb_pipeout (urb->pipe), status); #endif /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); spin_unlock (&ohci->lock); - usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb); + usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); spin_lock (&ohci->lock); /* stop periodic dma if it's not needed */ @@ -89,7 +76,7 @@ __acquires(ohci->lock) /*-------------------------------------------------------------------------* * ED handling functions - *-------------------------------------------------------------------------*/ + *-------------------------------------------------------------------------*/ /* search for the right schedule branch to use for a periodic ed. * does some load balancing; returns the branch, or negative errno. @@ -107,7 +94,6 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) */ for (i = 0; i < interval ; i++) { if (branch < 0 || ohci->load [branch] > ohci->load [i]) { -#if 1 /* CONFIG_USB_BANDWIDTH */ int j; /* usb 1.1 says 90% of one frame */ @@ -117,8 +103,7 @@ static int balance (struct ohci_hcd *ohci, int interval, int load) } if (j < NUM_INTS) continue; -#endif - branch = i; + branch = i; } } return branch; @@ -171,7 +156,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) /* link an ed into one of the HC chains */ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) -{ +{ int branch; if (ohci_to_hcd(ohci)->state == HC_STATE_QUIESCING) @@ -181,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) ed->ed_prev = NULL; ed->ed_next = NULL; ed->hwNextED = 0; + if (quirk_zfmicro(ohci) + && (ed->type == PIPE_INTERRUPT) + && !(ohci->eds_scheduled++)) + mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); wmb (); /* we care about rm_list when setting CLE/BLE in case the HC was at @@ -248,7 +237,7 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) } ed->branch = branch; periodic_link (ohci, ed); - } + } /* the HC may not see the schedule updates yet, but if it does * then they'll be properly ordered. @@ -277,7 +266,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) *prev = ed->ed_next; } ohci->load [i] -= ed->load; - } + } ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", @@ -285,7 +274,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) ed, ed->branch, ed->load, ed->interval); } -/* unlink an ed from one of the HC chains. +/* unlink an ed from one of the HC chains. * just the link to the ed is unlinked. * the link from the ed still points to another operational ed or 0 * so the HC can eventually finish the processing of the unlinked ed @@ -307,7 +296,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) * When finish_unlinks() runs later, after SOF interrupt, it will often * complete one or more URB unlinks before making that state change. */ -static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) +static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) { ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); @@ -397,7 +386,7 @@ static struct ed *ed_get ( unsigned int pipe, int interval ) { - struct ed *ed; + struct ed *ed; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); @@ -413,9 +402,9 @@ static struct ed *ed_get ( goto done; } - /* dummy td; end of td list for ed */ + /* dummy td; end of td list for ed */ td = td_alloc (ohci, GFP_ATOMIC); - if (!td) { + if (!td) { /* out of memory */ ed_free (ohci, ed); ed = NULL; @@ -462,7 +451,7 @@ static struct ed *ed_get ( done: spin_unlock_irqrestore (&ohci->lock, flags); - return ed; + return ed; } /*-------------------------------------------------------------------------*/ @@ -474,7 +463,7 @@ done: * and that ed->state is ED_OPER */ static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ +{ ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE); ed_deschedule (ohci, ed); @@ -541,7 +530,7 @@ td_fill (struct ohci_hcd *ohci, u32 info, td->ed = urb_priv->ed; td->next_dl_td = NULL; td->index = index; - td->urb = urb; + td->urb = urb; td->data_dma = data; if (!len) data = 0; @@ -553,8 +542,8 @@ td_fill (struct ohci_hcd *ohci, u32 info, (data & 0x0FFF) | 0xE000); td->ed->last_iso = info & 0xffff; } else { - td->hwCBP = cpu_to_hc32 (ohci, data); - } + td->hwCBP = cpu_to_hc32 (ohci, data); + } if (data) td->hwBE = cpu_to_hc32 (ohci, data + len - 1); else @@ -597,7 +586,7 @@ static void td_submit_urb ( * use the device toggle bits for resetting, and rely on the fact * that resetting toggle is meaningless if the endpoint is active. */ - if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { + if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out, 1); urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); @@ -710,28 +699,27 @@ static void td_submit_urb ( * Done List handling functions *-------------------------------------------------------------------------*/ -/* calculate transfer length/status and update the urb - * PRECONDITION: irqsafe (only for urb->status locking) - */ -static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) +/* calculate transfer length/status and update the urb */ +static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) { u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); int cc = 0; + int status = -EINPROGRESS; list_del (&td->td_list); /* ISO ... drivers see per-TD length/status */ - if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW (ohci, td, 0); + if (tdINFO & TD_ISO) { + u16 tdPSW = ohci_hwPSW(ohci, td, 0); int dlen = 0; /* NOTE: assumes FC in tdINFO == 0, and that * only the first of 0..MAXPSW psws is used. */ - cc = (tdPSW >> 12) & 0xF; - if (tdINFO & TD_CC) /* hc didn't touch? */ - return; + cc = (tdPSW >> 12) & 0xF; + if (tdINFO & TD_CC) /* hc didn't touch? */ + return status; if (usb_pipeout (urb->pipe)) dlen = urb->iso_frame_desc [td->index].length; @@ -758,18 +746,14 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) int type = usb_pipetype (urb->pipe); u32 tdBE = hc32_to_cpup (ohci, &td->hwBE); - cc = TD_CC_GET (tdINFO); + cc = TD_CC_GET (tdINFO); /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) { - spin_lock (&urb->lock); - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error [cc]; - spin_unlock (&urb->lock); - } + if (cc != TD_CC_NOERROR && cc < 0x0E) + status = cc_to_error[cc]; /* count all non-empty packets except control SETUP packet */ if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { @@ -787,15 +771,16 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) urb, td, 1 + td->index, cc, urb->actual_length, urb->transfer_buffer_length); - } + } + return status; } /*-------------------------------------------------------------------------*/ -static inline struct td * -ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) +static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) { - struct urb *urb = td->urb; + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; struct ed *ed = td->ed; struct list_head *tmp = td->td_list.next; __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); @@ -805,15 +790,14 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) */ ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); wmb (); - ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); + ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - /* put any later tds from this urb onto the donelist, after 'td', - * order won't matter here: no errors, and nothing was transferred. - * also patch the ed so it looks as if those tds completed normally. + /* Get rid of all later tds from this urb. We don't have + * to be careful: no errors and nothing was transferred. + * Also patch the ed so it looks as if those tds completed normally. */ while (tmp != &ed->td_list) { struct td *next; - __hc32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; @@ -828,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) * then we need to leave the control STATUS packet queued * and clear ED_SKIP. */ - info = next->hwINFO; - info |= cpu_to_hc32 (ohci, TD_DONE); - info &= ~cpu_to_hc32 (ohci, TD_CC); - next->hwINFO = info; - - next->next_dl_td = rev; - rev = next; + list_del(&next->td_list); + urb_priv->td_cnt++; ed->hwHeadP = next->hwNextTD | toggle; } @@ -861,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev) hc32_to_cpu (ohci, td->hwINFO), cc, cc_to_error [cc]); } - - return rev; } /* replies to the request have to be on a FIFO basis so @@ -881,8 +858,8 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) /* get TD from hc's singly linked list, and * prepend to ours. ed->td_list changes later. */ - while (td_dma) { - int cc; + while (td_dma) { + int cc; td = dma_to_td (ohci, td_dma); if (!td) { @@ -899,12 +876,12 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) */ if (cc != TD_CC_NOERROR && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - td_rev = ed_halted (ohci, td, cc, td_rev); + ed_halted(ohci, td, cc); - td->next_dl_td = td_rev; + td->next_dl_td = td_rev; td_rev = td; td_dma = hc32_to_cpup (ohci, &td->hwNextTD); - } + } return td_rev; } @@ -942,8 +919,12 @@ skip_ed: TD_MASK; /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) - goto skip_ed; + if (td->td_dma != head) { + if (ed == ohci->ed_to_check) + ohci->ed_to_check = NULL; + else + goto skip_ed; + } } } @@ -976,7 +957,7 @@ rescan_this: urb = td->urb; urb_priv = td->urb->hcpriv; - if (urb->status == -EINPROGRESS) { + if (!urb->unlinked) { prev = &td->hwNextTD; continue; } @@ -992,7 +973,7 @@ rescan_this: /* if URB is done, clean up */ if (urb_priv->td_cnt == urb_priv->length) { modified = completed = 1; - finish_urb (ohci, urb); + finish_urb(ohci, urb, 0); } } if (completed && !list_empty (&ed->td_list)) @@ -1000,6 +981,8 @@ rescan_this: /* ED's now officially unlinked, hc doesn't see */ ed->state = ED_IDLE; + if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) + ohci->eds_scheduled--; ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); ed->hwNextED = 0; wmb (); @@ -1013,9 +996,9 @@ rescan_this: if (modified) goto rescan_all; - } + } - /* maybe reenable control and bulk lists */ + /* maybe reenable control and bulk lists */ if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state) && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING && !ohci->ed_rm_list) { @@ -1023,7 +1006,7 @@ rescan_this: if (ohci->ed_controltail) { command |= OHCI_CLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_CLE)) { control |= OHCI_CTRL_CLE; @@ -1033,7 +1016,7 @@ rescan_this: } if (ohci->ed_bulktail) { command |= OHCI_BLF; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); if (!(ohci->hc_control & OHCI_CTRL_BLE)) { control |= OHCI_CTRL_BLE; @@ -1041,20 +1024,20 @@ rescan_this: &ohci->regs->ed_bulkcurrent); } } - + /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ if (control) { ohci->hc_control |= control; - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } + ohci_writel (ohci, ohci->hc_control, + &ohci->regs->control); + } if (command) { - if (ohci->flags & OHCI_QUIRK_ZFMICRO) + if (quirk_zfmicro(ohci)) mdelay(1); - ohci_writel (ohci, command, &ohci->regs->cmdstatus); - } + ohci_writel (ohci, command, &ohci->regs->cmdstatus); + } } } @@ -1062,57 +1045,70 @@ rescan_this: /*-------------------------------------------------------------------------*/ +/* + * Used to take back a TD from the host controller. This would normally be + * called from within dl_done_list, however it may be called directly if the + * HC no longer sees the TD and it has not appeared on the donelist (after + * two frames). This bug has been observed on ZF Micro systems. + */ +static void takeback_td(struct ohci_hcd *ohci, struct td *td) +{ + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + int status; + + /* update URB's length and status from TD */ + status = td_done(ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_cnt == urb_priv->length) + finish_urb(ohci, urb, status); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink(ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32(ohci, ED_SKIP)) { + td = list_entry(ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel(ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel(ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } +} + /* * Process normal completions (error or success) and clean the schedules. * * This is the main path for handing urbs back to drivers. The only other - * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of - * scanning the (re-reversed) donelist as this does. + * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, + * instead of scanning the (re-reversed) donelist as this does. There's + * an abnormal path too, handling a quirk in some Compaq silicon: URBs + * with TDs that appear to be orphaned are directly reclaimed. */ static void dl_done_list (struct ohci_hcd *ohci) { struct td *td = dl_reverse_done_list (ohci); - while (td) { + while (td) { struct td *td_next = td->next_dl_td; - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - - /* update URB's length and status from TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb (ohci, urb); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink (ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32 (ohci, ED_SKIP)) { - td = list_entry (ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel (ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel (ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } - - td = td_next; - } + takeback_td(ohci, td); + td = td_next; + } }