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 ( ...@@ -203,28 +203,28 @@ static int ohci_urb_enqueue (
return -ENOMEM; return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *)); 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 */ /* fill the private part of the URB */
urb_priv->length = size; urb_priv->length = size;
urb_priv->ed = ed; urb_priv->ed = ed;
/* allocate the TDs (updating hash chains) */ /* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) { 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]) { if (!urb_priv->td [i]) {
urb_priv->length = i; urb_priv->length = i;
retval = -ENOMEM; urb_free_priv (ohci, urb_priv);
goto fail; 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 */ /* schedule the ed if needed */
if (ed->state == ED_IDLE) { if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed); retval = ed_schedule (ohci, ed);
......
...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) ...@@ -97,17 +97,11 @@ td_alloc (struct ohci_hcd *hc, int mem_flags)
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) { if (td) {
int hash;
/* in case hc fetches it, make it look dead */ /* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td); memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma); td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma; td->td_dma = dma;
/* hashed in td_fill */
/* hash it for later reverse mapping */
hash = TD_HASH_FUNC (dma);
td->td_hash = hc->td_hash [hash];
hc->td_hash [hash] = td;
} }
return td; return td;
} }
......
...@@ -463,13 +463,14 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed) ...@@ -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) */ /* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
static void static void
td_fill (unsigned int info, td_fill (struct ohci_hcd *ohci, u32 info,
dma_addr_t data, int len, dma_addr_t data, int len,
struct urb *urb, int index) struct urb *urb, int index)
{ {
struct td *td, *td_pt; struct td *td, *td_pt;
struct urb_priv *urb_priv = urb->hcpriv; struct urb_priv *urb_priv = urb->hcpriv;
int is_iso = info & TD_ISO; int is_iso = info & TD_ISO;
int hash;
// ASSERT (index < urb_priv->length); // ASSERT (index < urb_priv->length);
...@@ -516,11 +517,16 @@ td_fill (unsigned int info, ...@@ -516,11 +517,16 @@ td_fill (unsigned int info,
td->hwBE = 0; td->hwBE = 0;
td->hwNextTD = cpu_to_le32 (td_pt->td_dma); td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
/* HC might read the TD right after we link it ... */
wmb ();
/* append to queue */ /* append to queue */
list_add_tail (&td->td_list, &td->ed->td_list); 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; td->ed->hwTailP = td->hwNextTD;
} }
...@@ -578,7 +584,7 @@ static void td_submit_urb ( ...@@ -578,7 +584,7 @@ static void td_submit_urb (
: TD_T_TOGGLE | TD_CC | TD_DP_IN; : TD_T_TOGGLE | TD_CC | TD_DP_IN;
/* TDs _could_ transfer up to 8K each */ /* TDs _could_ transfer up to 8K each */
while (data_len > 4096) { while (data_len > 4096) {
td_fill (info, data, 4096, urb, cnt); td_fill (ohci, info, data, 4096, urb, cnt);
data += 4096; data += 4096;
data_len -= 4096; data_len -= 4096;
cnt++; cnt++;
...@@ -586,11 +592,11 @@ static void td_submit_urb ( ...@@ -586,11 +592,11 @@ static void td_submit_urb (
/* maybe avoid ED halt on final TD short read */ /* maybe avoid ED halt on final TD short read */
if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
info |= TD_R; info |= TD_R;
td_fill (info, data, data_len, urb, cnt); td_fill (ohci, info, data, data_len, urb, cnt);
cnt++; cnt++;
if ((urb->transfer_flags & URB_ZERO_PACKET) if ((urb->transfer_flags & URB_ZERO_PACKET)
&& cnt < urb_priv->length) { && cnt < urb_priv->length) {
td_fill (info, 0, 0, urb, cnt); td_fill (ohci, info, 0, 0, urb, cnt);
cnt++; cnt++;
} }
/* maybe kickstart bulk list */ /* maybe kickstart bulk list */
...@@ -605,17 +611,17 @@ static void td_submit_urb ( ...@@ -605,17 +611,17 @@ static void td_submit_urb (
*/ */
case PIPE_CONTROL: case PIPE_CONTROL:
info = TD_CC | TD_DP_SETUP | TD_T_DATA0; 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) { if (data_len > 0) {
info = TD_CC | TD_R | TD_T_DATA1; info = TD_CC | TD_R | TD_T_DATA1;
info |= is_out ? TD_DP_OUT : TD_DP_IN; info |= is_out ? TD_DP_OUT : TD_DP_IN;
/* NOTE: mishandles transfers >8K, some >4K */ /* 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 info = is_out
? TD_CC | TD_DP_IN | TD_T_DATA1 ? TD_CC | TD_DP_IN | TD_T_DATA1
: TD_CC | TD_DP_OUT | 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 */ /* maybe kickstart control list */
wmb (); wmb ();
writel (OHCI_CLF, &ohci->regs->cmdstatus); writel (OHCI_CLF, &ohci->regs->cmdstatus);
...@@ -634,7 +640,7 @@ static void td_submit_urb ( ...@@ -634,7 +640,7 @@ static void td_submit_urb (
// a 2^16 iso range, vs other HCs max of 2^10) // a 2^16 iso range, vs other HCs max of 2^10)
frame += cnt * urb->interval; frame += cnt * urb->interval;
frame &= 0xffff; frame &= 0xffff;
td_fill (TD_CC | TD_ISO | frame, td_fill (ohci, TD_CC | TD_ISO | frame,
data + urb->iso_frame_desc [cnt].offset, data + urb->iso_frame_desc [cnt].offset,
urb->iso_frame_desc [cnt].length, urb, cnt); 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