Commit fb4b62ad authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB ohci-hcd, don't force SLAB_ATOMIC allocations

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.)
parent 1fda844a
......@@ -203,28 +203,28 @@ static int ohci_urb_enqueue (
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);
......
......@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
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;
}
......
......@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
/* 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_fill (unsigned int info,
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 @@ static void td_submit_urb (
: 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 @@ static void td_submit_urb (
/* 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 @@ static void td_submit_urb (
*/
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 @@ static void td_submit_urb (
// 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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment