This is a minor cleanup to let per-request memory allocations block, when the caller allows (it provided the bitmask). The driver used to work that way until something like 2.4.3; an update (a few months back) to how the "dma_addr_t" hashes to a "struct ohci_td *" lets us simplify things again. Another benfit: it blocks irqs for less time on the submit path. (The ehci driver already acts this way.)
- Dave
--- ./drivers/usb-dist/host/ohci-mem.c Wed Jan 22 15:01:49 2003 +++ ./drivers/usb/host/ohci-mem.c Wed Jan 22 18:13:13 2003 @@ -97,17 +97,11 @@ td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); if (td) { - int hash; - /* in case hc fetches it, make it look dead */ memset (td, 0, sizeof *td); td->hwNextTD = cpu_to_le32 (dma); td->td_dma = dma; - - /* hash it for later reverse mapping */ - hash = TD_HASH_FUNC (dma); - td->td_hash = hc->td_hash [hash]; - hc->td_hash [hash] = td; + /* hashed in td_fill */ } return td; } --- ./drivers/usb-dist/host/ohci-hcd.c Wed Jan 22 15:01:49 2003 +++ ./drivers/usb/host/ohci-hcd.c Wed Jan 22 18:13:13 2003 @@ -203,28 +203,28 @@ return -ENOMEM; memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); - spin_lock_irqsave (&ohci->lock, flags); - - /* don't submit to a dead HC */ - if (ohci->disabled || ohci->sleeping) { - retval = -ENODEV; - goto fail; - } - /* fill the private part of the URB */ urb_priv->length = size; urb_priv->ed = ed; - /* allocate the TDs (updating hash chains) */ + /* allocate the TDs (deferring hash chain updates) */ for (i = 0; i < size; i++) { - urb_priv->td [i] = td_alloc (ohci, SLAB_ATOMIC); + urb_priv->td [i] = td_alloc (ohci, mem_flags); if (!urb_priv->td [i]) { urb_priv->length = i; - retval = -ENOMEM; - goto fail; + urb_free_priv (ohci, urb_priv); + return -ENOMEM; } } + spin_lock_irqsave (&ohci->lock, flags); + + /* don't submit to a dead HC */ + if (ohci->disabled || ohci->sleeping) { + retval = -ENODEV; + goto fail; + } + /* schedule the ed if needed */ if (ed->state == ED_IDLE) { retval = ed_schedule (ohci, ed); --- ./drivers/usb-dist/host/ohci-q.c Wed Jan 22 15:01:49 2003 +++ ./drivers/usb/host/ohci-q.c Wed Jan 22 18:13:13 2003 @@ -463,13 +463,14 @@ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ static void -td_fill (unsigned int info, +td_fill (struct ohci_hcd *ohci, u32 info, dma_addr_t data, int len, struct urb *urb, int index) { struct td *td, *td_pt; struct urb_priv *urb_priv = urb->hcpriv; int is_iso = info & TD_ISO; + int hash; // ASSERT (index < urb_priv->length); @@ -516,11 +517,16 @@ td->hwBE = 0; td->hwNextTD = cpu_to_le32 (td_pt->td_dma); - /* HC might read the TD right after we link it ... */ - wmb (); - /* append to queue */ list_add_tail (&td->td_list, &td->ed->td_list); + + /* hash it for later reverse mapping */ + hash = TD_HASH_FUNC (td->td_dma); + td->td_hash = ohci->td_hash [hash]; + ohci->td_hash [hash] = td; + + /* HC might read the TD (or cachelines) right away ... */ + wmb (); td->ed->hwTailP = td->hwNextTD; } @@ -578,7 +584,7 @@ : 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); + td_fill (ohci, info, data, 4096, urb, cnt); data += 4096; data_len -= 4096; cnt++; @@ -586,11 +592,11 @@ /* 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); + td_fill (ohci, info, data, data_len, urb, cnt); cnt++; if ((urb->transfer_flags & URB_ZERO_PACKET) && cnt < urb_priv->length) { - td_fill (info, 0, 0, urb, cnt); + td_fill (ohci, info, 0, 0, urb, cnt); cnt++; } /* maybe kickstart bulk list */ @@ -605,17 +611,17 @@ */ case PIPE_CONTROL: info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (info, urb->setup_dma, 8, urb, cnt++); + td_fill (ohci, info, urb->setup_dma, 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++); + 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 (info, data, 0, urb, cnt++); + td_fill (ohci, info, data, 0, urb, cnt++); /* maybe kickstart control list */ wmb (); writel (OHCI_CLF, &ohci->regs->cmdstatus); @@ -634,7 +640,7 @@ // 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, + td_fill (ohci, TD_CC | TD_ISO | frame, data + urb->iso_frame_desc [cnt].offset, urb->iso_frame_desc [cnt].length, urb, cnt); }