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);
                }

Reply via email to