# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.484 -> 1.485 # drivers/usb/host/ohci-hcd.c 1.21 -> 1.22 # drivers/usb/host/ohci-hub.c 1.7 -> 1.8 # drivers/usb/host/ohci-dbg.c 1.8 -> 1.9 # drivers/usb/host/ohci-q.c 1.15 -> 1.16 # drivers/usb/host/ohci.h 1.10 -> 1.11 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/07/26 david-b@pacbell.net 1.485 # [PATCH] ohci-hcd cardbus unplug, remove interrupt length limit, # # * handle another cardbus unplug misbehavior # - root hub kept polling, never stopped # - starts to update hcd->state to match internal state # * code to count/queue TDs for interrupt/bulk is now shared # - removes (low level) interrupt transfer size limitation # - both types already handled urb queueing # - re-indents some TD queuing code (most of patch, by volume) # * cleanup # - use new container_of() macro, not list_entry() # - report a previously unreported error (control data >4K) # - simplify intr/bulk toggle reset # - tweak TD debug dump # - more object code shrinkage (often fits in 3 pages) # # Note that the control data size error is just a long-standing # limitation of this driver, not a USB limitation! It could be # fixed, if anyone starts to run into it. # -------------------------------------------- # diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c --- a/drivers/usb/host/ohci-dbg.c Fri Jul 26 13:47:24 2002 +++ b/drivers/usb/host/ohci-dbg.c Fri Jul 26 13:47:24 2002 @@ -281,16 +281,21 @@ cbp ? (be + 1 - cbp) : 0); } else { unsigned i; - dbg (" info %08x CC=%x DI=%d START=%04x", tmp, - TD_CC_GET(tmp), /* FC, */ + dbg (" info %08x CC=%x FC=%d DI=%d SF=%04x", tmp, + TD_CC_GET(tmp), + (tmp >> 24) & 0x07, (tmp & TD_DI) >> 21, tmp & 0x0000ffff); dbg (" bp0 %08x be %08x", le32_to_cpup (&td->hwCBP) & ~0x0fff, le32_to_cpup (&td->hwBE)); for (i = 0; i < MAXPSW; i++) { - dbg (" psw [%d] = %2x", i, - le16_to_cpu (td->hwPSW [i])); + u16 psw = le16_to_cpup (&td->hwPSW [i]); + int cc = (psw >> 12) & 0x0f; + dbg (" psw [%d] = %2x, CC=%x %s=%d", i, + psw, cc, + (cc >= 0x0e) ? "OFFSET" : "SIZE", + psw & 0x0fff); } } } diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Fri Jul 26 13:47:24 2002 +++ b/drivers/usb/host/ohci-hcd.c Fri Jul 26 13:47:24 2002 @@ -125,6 +125,12 @@ #include "ohci.h" +static inline void disable (struct ohci_hcd *ohci) +{ + ohci->disabled = 1; + ohci->hcd.state = USB_STATE_HALT; +} + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -158,12 +164,18 @@ return -ENOMEM; /* for the private part of the URB we need the number of TDs (size) */ - switch (usb_pipetype (pipe)) { + switch (ed->type) { case PIPE_CONTROL: + /* td_submit_urb() doesn't yet handle these */ + if (urb->transfer_buffer_length > 4096) + return -EMSGSIZE; + /* 1 TD for setup, 1 for ACK, plus ... */ size = 2; /* FALLTHROUGH */ - case PIPE_BULK: + // case PIPE_INTERRUPT: + // case PIPE_BULK: + default: /* one TD for every 4096 Bytes (can be upto 8K) */ size += urb->transfer_buffer_length / 4096; /* ... and for any remaining bytes ... */ @@ -187,9 +199,6 @@ urb->iso_frame_desc [i].status = -EXDEV; } break; - case PIPE_INTERRUPT: /* one TD */ - size = 1; - break; } /* allocate the private part of the URB */ @@ -242,9 +251,8 @@ bustime = usb_check_bandwidth (urb->dev, urb); } if (bustime < 0) { - urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&ohci->lock, flags); - return bustime; + retval = bustime; + goto fail; } usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); @@ -259,7 +267,7 @@ /* fill the TDs and link them to the ed; and * enable that part of the schedule, if needed */ - td_submit_urb (urb); + td_submit_urb (ohci, urb); fail: if (retval) @@ -513,7 +521,7 @@ ohci->hcd.self.root_hub = udev = usb_alloc_dev (NULL, &ohci->hcd.self); ohci->hcd.state = USB_STATE_READY; if (!udev) { - ohci->disabled = 1; + disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; writel (ohci->hc_control, &ohci->regs->control); return -ENOMEM; @@ -523,7 +531,7 @@ udev->speed = USB_SPEED_FULL; if (usb_register_root_hub (udev, ohci->parent_dev) != 0) { usb_free_dev (udev); - ohci->disabled = 1; + disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; writel (ohci->hc_control, &ohci->regs->control); return -ENODEV; @@ -549,8 +557,8 @@ /* cardbus/... hardware gone before remove() */ } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { - ohci->disabled++; - err ("%s device removed!", hcd->self.bus_name); + disable (ohci); + dbg ("%s device removed!", hcd->self.bus_name); return; /* interrupt for some other device? */ @@ -562,7 +570,7 @@ // dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); if (ints & OHCI_INTR_UE) { - ohci->disabled++; + disable (ohci); err ("OHCI Unrecoverable Error, %s disabled", hcd->self.bus_name); // e.g. due to PCI Master/Target Abort diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c --- a/drivers/usb/host/ohci-hub.c Fri Jul 26 13:47:24 2002 +++ b/drivers/usb/host/ohci-hub.c Fri Jul 26 13:47:24 2002 @@ -22,7 +22,9 @@ */ #define read_roothub(hc, register, mask) ({ \ u32 temp = readl (&hc->regs->roothub.register); \ - if (hc->flags & OHCI_QUIRK_AMD756) \ + if (temp == -1) \ + disable (hc); \ + else if (hc->flags & OHCI_QUIRK_AMD756) \ while (temp & mask) \ temp = readl (&hc->regs->roothub.register); \ temp; }) @@ -71,8 +73,10 @@ ports = roothub_a (ohci) & RH_A_NDP; if (ports > MAX_ROOT_PORTS) { - err ("%s: bogus NDP=%d", hcd->self.bus_name, ports); - err ("rereads as NDP=%d", + if (ohci->disabled) + return -ESHUTDOWN; + err ("%s bogus NDP=%d, rereads as NDP=%d", + hcd->self.bus_name, ports, readl (&ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ return 0; diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Fri Jul 26 13:47:24 2002 +++ b/drivers/usb/host/ohci-q.c Fri Jul 26 13:47:24 2002 @@ -77,12 +77,12 @@ usb_hcd_giveback_urb (&ohci->hcd, urb); } -static void td_submit_urb (struct urb *urb); +static void td_submit_urb (struct ohci_hcd *ohci, struct urb *urb); /* Report interrupt transfer completion, maybe reissue */ -static void intr_resub (struct ohci_hcd *hc, struct urb *urb) +static inline void intr_resub (struct ohci_hcd *hc, struct urb *urb) { - urb_priv_t *urb_priv = urb->hcpriv; + struct urb_priv *urb_priv = urb->hcpriv; unsigned long flags; // FIXME rewrite this resubmit path. use pci_dma_sync_single() @@ -120,7 +120,7 @@ spin_unlock (&urb->lock); spin_lock (&hc->lock); - td_submit_urb (urb); + td_submit_urb (hc, urb); spin_unlock_irqrestore (&hc->lock, flags); } @@ -518,12 +518,12 @@ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ static void -td_fill (struct ohci_hcd *ohci, unsigned int info, +td_fill (unsigned int info, dma_addr_t data, int len, struct urb *urb, int index) { struct td *td, *td_pt; - urb_priv_t *urb_priv = urb->hcpriv; + struct urb_priv *urb_priv = urb->hcpriv; int is_iso = info & TD_ISO; if (index >= urb_priv->length) { @@ -582,28 +582,30 @@ /*-------------------------------------------------------------------------*/ -/* prepare all TDs of a transfer */ - -static void td_submit_urb (struct urb *urb) -{ - urb_priv_t *urb_priv = urb->hcpriv; - struct ohci_hcd *ohci = hcd_to_ohci (urb->dev->bus->hcpriv); +/* Prepare all TDs of a transfer, and queue them onto the ED. + * Caller guarantees HC is active. + * Usually the ED is already on the schedule, so TDs might be + * processed as soon as they're queued. + */ +static void td_submit_urb ( + struct ohci_hcd *ohci, + struct urb *urb +) { + struct urb_priv *urb_priv = urb->hcpriv; dma_addr_t data; int data_len = urb->transfer_buffer_length; - int cnt = 0; - __u32 info = 0; - unsigned int toggle = 0; + int cnt = 0; + u32 info = 0; int is_out = usb_pipeout (urb->pipe); - /* OHCI handles the DATA-toggles itself, we just use the - * USB-toggle bits for resetting + /* OHCI handles the bulk/interrupt data toggles itself. We just + * 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)) { - toggle = TD_T_TOGGLE; - } else { - toggle = TD_T_DATA0; + 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 &= ~ED_C; } urb_priv->td_cnt = 0; @@ -619,91 +621,88 @@ /* NOTE: TD_CC is set so we can tell which TDs the HC processed by * using TD_CC_GET, as well as by seeing them on the done list. + * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) */ - switch (usb_pipetype (urb->pipe)) { - case PIPE_BULK: - info = is_out - ? TD_CC | TD_DP_OUT - : TD_CC | TD_DP_IN ; - /* TDs _could_ transfer up to 8K each */ - while (data_len > 4096) { - td_fill (ohci, - info | (cnt? TD_T_TOGGLE:toggle), - data, 4096, urb, cnt); - data += 4096; data_len -= 4096; cnt++; - } - /* maybe avoid ED halt on final TD short read */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - info |= TD_R; - td_fill (ohci, info | (cnt ? TD_T_TOGGLE : toggle), - data, data_len, urb, cnt); + switch (urb_priv->ed->type) { + + /* Bulk and interrupt are identical except for where in the schedule + * their EDs live. + */ + // case PIPE_BULK: + // case PIPE_INTERRUPT: + default: + info = is_out + ? TD_T_TOGGLE | TD_CC | TD_DP_OUT + : TD_T_TOGGLE | TD_CC | TD_DP_IN; + /* TDs _could_ transfer up to 8K each */ + while (data_len > 4096) { + td_fill (info, data, 4096, urb, cnt); + data += 4096; + data_len -= 4096; cnt++; - if ((urb->transfer_flags & USB_ZERO_PACKET) - && cnt < urb_priv->length) { - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), - 0, 0, urb, cnt); - cnt++; - } - /* start bulk list */ - if (!ohci->sleeping) { - wmb (); - writel (OHCI_BLF, &ohci->regs->cmdstatus); - } - break; + } + /* maybe avoid ED halt on final TD short read */ + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + info |= TD_R; + td_fill (info, data, data_len, urb, cnt); + cnt++; + if ((urb->transfer_flags & USB_ZERO_PACKET) + && cnt < urb_priv->length) { + td_fill (info, 0, 0, urb, cnt); + cnt++; + } + /* maybe kickstart bulk list */ + if (urb_priv->ed->type == PIPE_BULK) { + wmb (); + writel (OHCI_BLF, &ohci->regs->cmdstatus); + } + break; - case PIPE_INTERRUPT: - /* current policy: only one TD per request. - * otherwise identical to bulk, except for BLF - */ - info = TD_CC | toggle; - info |= is_out - ? TD_DP_OUT - : TD_R | TD_DP_IN; - td_fill (ohci, info, data, data_len, urb, cnt++); - break; - - case PIPE_CONTROL: - /* control requests don't use toggle state */ - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (ohci, info, - pci_map_single (ohci->hcd.pdev, - urb->setup_packet, 8, - PCI_DMA_TODEVICE), - 8, urb, cnt++); - if (data_len > 0) { - info = TD_CC | TD_R | TD_T_DATA1; - info |= is_out ? TD_DP_OUT : TD_DP_IN; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, - urb, cnt++); - } - info = is_out - ? TD_CC | TD_DP_IN | TD_T_DATA1 - : TD_CC | TD_DP_OUT | TD_T_DATA1; - td_fill (ohci, info, data, 0, urb, cnt++); - /* start control list */ - if (!ohci->sleeping) { - wmb (); - writel (OHCI_CLF, &ohci->regs->cmdstatus); - } - break; + /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, + * any DATA phase works normally, and the STATUS ack is special. + */ + case PIPE_CONTROL: + info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + td_fill (info, + pci_map_single (ohci->hcd.pdev, + urb->setup_packet, 8, + PCI_DMA_TODEVICE), + 8, urb, cnt++); + if (data_len > 0) { + info = TD_CC | TD_R | TD_T_DATA1; + info |= is_out ? TD_DP_OUT : TD_DP_IN; + /* NOTE: mishandles transfers >8K, some >4K */ + td_fill (info, data, data_len, urb, cnt++); + } + info = is_out + ? TD_CC | TD_DP_IN | TD_T_DATA1 + : TD_CC | TD_DP_OUT | TD_T_DATA1; + td_fill (info, data, 0, urb, cnt++); + /* maybe kickstart control list */ + wmb (); + writel (OHCI_CLF, &ohci->regs->cmdstatus); + break; - case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { - int frame = urb->start_frame; - - // FIXME scheduling should handle frame counter - // roll-around ... exotic case (and OHCI has - // a 2^16 iso range, vs other HCs max of 2^10) - frame += cnt * urb->interval; - frame &= 0xffff; - td_fill (ohci, TD_CC | TD_ISO | frame, - data + urb->iso_frame_desc [cnt].offset, - urb->iso_frame_desc [cnt].length, urb, cnt); - } - break; - } - if (urb_priv->length != cnt) + /* ISO has no retransmit, so no toggle; and it uses special TDs. + * Each TD could handle multiple consecutive frames (interval 1); + * we could often reduce the number of TDs here. + */ + case PIPE_ISOCHRONOUS: + for (cnt = 0; cnt < urb->number_of_packets; cnt++) { + int frame = urb->start_frame; + + // FIXME scheduling should handle frame counter + // roll-around ... exotic case (and OHCI has + // a 2^16 iso range, vs other HCs max of 2^10) + frame += cnt * urb->interval; + frame &= 0xffff; + td_fill (TD_CC | TD_ISO | frame, + data + urb->iso_frame_desc [cnt].offset, + urb->iso_frame_desc [cnt].length, urb, cnt); + } + break; + } + if (urb_priv->length != cnt) dbg ("TD LENGTH %d != CNT %d", urb_priv->length, cnt); } @@ -724,8 +723,10 @@ u16 tdPSW = le16_to_cpu (td->hwPSW [0]); int dlen = 0; + /* NOTE: assumes FC in tdINFO == 0 (and MAXPSW == 1) */ + cc = (tdPSW >> 12) & 0xF; - if (cc >= 0x0E) /* hc didn't touch? */ + if (tdINFO & TD_CC) /* hc didn't touch? */ return; if (usb_pipeout (urb->pipe)) diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h --- a/drivers/usb/host/ohci.h Fri Jul 26 13:47:24 2002 +++ b/drivers/usb/host/ohci.h Fri Jul 26 13:47:24 2002 @@ -401,5 +401,5 @@ struct usb_hcd hcd; }; -#define hcd_to_ohci(hcd_ptr) list_entry(hcd_ptr, struct ohci_hcd, hcd) +#define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)