This is the latest snapshot of the net2280 code.  I'm sending
it for testing, since the last update turned up some issues
that were a surprise to me and so I think this should get
more testing than I've yet had a chance to do.

Pull from http://usb-gadget.bkbits.net/gadget-2.6 to get
the same code, with complete change history.

Notable changes:

- Fixes several DMA chaining bugs, mostly for OUT data

- Merges ISO updates from Mark Huang <[EMAIL PROTECTED]>

- Merges a shutdown fix from Alan Stern

- Fixes a minor locking goof found by "smatch"

 - Pays proper attention to the "selfpowered" and "remote
   wakeup" bits (so device status should be correct, and
   the host will need to enable remote wakeup).

 - USE_DMA_CHAINING became a module parameter, so that you
   can "modprobe net2280 use_dma_chaining=n" to kick in
   a less aggressive DMA mode.

- Is more paranoid about some dma errata

 - Removes some ancient dma workaround #ifdefs, and similar
   minor cleanup

If you're using this driver on 2.6, please let me know if
this breaks anything.

- Dave

--- a/drivers/usb/gadget/net2280.c      Fri Dec 19 14:48:57 2003
+++ b/drivers/usb/gadget/net2280.c      Fri Dec 19 14:48:57 2003
@@ -25,9 +25,6 @@
  * rev1 chips.  Rev1a silicon (0110) fixes almost all of them.
  */
 
-#define USE_DMA_CHAINING
-
-
 /*
  * Copyright (C) 2003 David Brownell
  * Copyright (C) 2003 NetChip Technologies
@@ -47,8 +44,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define DEBUG  1
-// #define     VERBOSE         /* extra debug messages (success too) */
+#undef DEBUG           /* messages on error and most fault paths */
+#undef VERBOSE         /* extra debug messages (success too) */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -77,7 +74,7 @@
 
 
 #define        DRIVER_DESC             "NetChip 2280 USB Peripheral Controller"
-#define        DRIVER_VERSION          "Bastille Day 2003"
+#define        DRIVER_VERSION          "19 December 2003"
 
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 #define        EP_DONTUSE              13      /* nonzero */
@@ -96,10 +93,21 @@
        "ep-e", "ep-f",
 };
 
+/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
+ * use_dma_chaining -- dma descriptor queues gives even more irq reduction
+ *
+ * The net2280 DMA engines are not tightly integrated with their FIFOs;
+ * not all cases are (yet) handled well in this driver or the silicon.
+ * Some gadget drivers work better with the dma support here than others.
+ * These two parameters let you use PIO or less aggressive DMA.
+ */
 static int use_dma = 1;
+static int use_dma_chaining = 1;
 
 /* "modprobe net2280 use_dma=n" etc */
-module_param (use_dma, bool, S_IRUGO|S_IWUSR);
+module_param (use_dma, bool, S_IRUGO);
+module_param (use_dma_chaining, bool, S_IRUGO);
+
 
 /* mode 0 == ep-{a,b,c,d} 1K fifo each
  * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
@@ -110,6 +118,7 @@
 /* "modprobe net2280 fifo_mode=1" etc */
 module_param (fifo_mode, ushort, 0644);
 
+
 #define        DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
 
 #if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG)
@@ -169,8 +178,8 @@
        /* FIFO lines can't go to different packets.  PIO is ok, so
         * use it instead of troublesome (non-bulk) multi-packet DMA.
         */
-       if (ep->is_in && ep->dma && (max % 4) != 0) {
-               DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n",
+       if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
+               DEBUG (ep->dev, "%s, no dma for maxpacket %d\n",
                        ep->ep.name, ep->ep.maxpacket);
                ep->dma = 0;
        }
@@ -188,8 +197,10 @@
                if ((dev->gadget.speed == USB_SPEED_HIGH
                                        && max != 512)
                                || (dev->gadget.speed == USB_SPEED_FULL
-                                       && max > 64))
+                                       && max > 64)) {
+                       spin_unlock_irqrestore (&dev->lock, flags);
                        return -ERANGE;
+               }
        }
        ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
        tmp <<= ENDPOINT_TYPE;
@@ -205,11 +216,6 @@
 
        writel (tmp, &ep->regs->ep_cfg);
 
-#ifdef NET2280_DMA_OUT_WORKAROUND
-       if (!ep->is_in)
-               ep->dma = 0;
-#endif
-
        /* enable irqs */
        if (!ep->dma) {                         /* pio, per-packet */
                tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
@@ -541,8 +547,11 @@
                count -= 4;
        }
 
-       /* last fifo entry is "short" unless we wrote a full packet */
-       if (total < ep->ep.maxpacket) {
+       /* last fifo entry is "short" unless we wrote a full packet.
+        * also explicitly validate last word in (periodic) transfers
+        * when maxpacket is not a multiple of 4 bytes.
+        */
+       if (count || total < ep->ep.maxpacket) {
                tmp = count ? get_unaligned ((u32 *)buf) : count;
                cpu_to_le32s (&tmp);
                set_fifo_bytecount (ep, count & 0x03);
@@ -555,6 +564,9 @@
 /* work around erratum 0106: PCI and USB race over the OUT fifo.
  * caller guarantees chiprev 0100, out endpoint is NAKing, and
  * there's no real data in the fifo.
+ *
+ * NOTE:  also used in cases where that erratum doesn't apply:
+ * where the host wrote "too much" data to us.
  */
 static void out_flush (struct net2280_ep *ep)
 {
@@ -626,7 +638,10 @@
                                ep->ep.name, count, tmp);
                        req->req.status = -EOVERFLOW;
                        cleanup = 1;
-               }
+                       /* NAK_OUT_PACKETS will be set, so flushing is safe;
+                        * the next read will start with the next packet
+                        */
+               } /* else it's a ZLP, no worries */
                count = tmp;
        }
        req->req.actual += count;
@@ -665,7 +680,7 @@
 }
 
 /* fill out dma descriptor to match a given request */
-static inline void
+static void
 fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
 {
        struct net2280_dma      *td = req->td;
@@ -678,15 +693,13 @@
         */
        if (ep->is_in)
                dmacount |= (1 << DMA_DIRECTION);
-       else
+       else if ((dmacount % ep->ep.maxpacket) != 0)
                dmacount |= (1 << END_OF_CHAIN);
 
        req->valid = valid;
        if (valid)
                dmacount |= (1 << VALID_BIT);
-#ifdef USE_DMA_CHAINING
-       if (!req->req.no_interrupt)
-#endif
+       if (likely(!req->req.no_interrupt || !use_dma_chaining))
                dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
 
        /* td->dmadesc = previously set by caller */
@@ -698,7 +711,8 @@
 }
 
 static const u32 dmactl_default =
-                 (1 << DMA_CLEAR_COUNT_ENABLE)
+                 (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT)
+               | (1 << DMA_CLEAR_COUNT_ENABLE)
                /* erratum 0116 workaround part 1 (use POLLING) */
                | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE)
                | (1 << DMA_VALID_BIT_POLLING_ENABLE)
@@ -744,6 +758,8 @@
                        req->td->dmacount = cpu_to_le32 (req->req.length - tmp);
                        writel ((1 << DMA_DONE_INTERRUPT_ENABLE)
                                | tmp, &dma->dmacount);
+                       req->td->dmadesc = 0;
+                       req->valid = 1;
 
                        writel ((1 << DMA_ENABLE), &dma->dmactl);
                        writel ((1 << DMA_START), &dma->dmastat);
@@ -772,13 +788,12 @@
        req->td->dmadesc = cpu_to_le32 (ep->td_dma);
        fill_dma_desc (ep, req, 1);
 
-#ifdef USE_DMA_CHAINING
-       writel (  (1 << VALID_BIT)
-               | (ep->is_in << DMA_DIRECTION)
-               | 0, &dma->dmacount);
-#else
-       req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
-#endif
+       if (use_dma_chaining)
+               writel (  (1 << VALID_BIT)
+                       | (ep->is_in << DMA_DIRECTION)
+                       | 0, &dma->dmacount);
+       else
+               req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
 
        writel (req->td_dma, &dma->dmadesc);
        writel (tmp, &dma->dmactl);
@@ -977,7 +992,6 @@
 )
 {
        req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);
-       rmb ();
        done (ep, req, status);
 }
 
@@ -1002,10 +1016,23 @@
                /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
                 * packets, including overruns, even when the transfer was
                 * exactly the length requested (dmacount now zero).
-                * FIXME there's an overrun case here too, where we expect
+                * Except when this s/g was faked (read-from-fifo).
+                *
+                * NOTE: there's an overrun case here too, where we expect
                 * a short packet but receive a max length one (won't NAK).
+                * In that case only this dma completion irq happens!
+                *
+                * AVOID by making gadget drivers always read N*maxpacket.
+                * (Which also avoids errata 0121, 0122, and 0124...)
                 */
-               if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) {
+               if (!ep->is_in
+                               && req->td->dmadesc
+                               && (req->req.length % ep->ep.maxpacket) != 0) {
+                       tmp = readl (&ep->regs->ep_stat);
+
+                       if ((tmp & (1 << NAK_OUT_PACKETS)) == 0)
+                               WARN (ep->dev, "%s short read trouble!\n",
+                                               ep->ep.name);
                        req->dma_done = 1;
                        break;
                }
@@ -1021,13 +1048,18 @@
                return;
        req = list_entry (ep->queue.next, struct net2280_request, queue);
 
-#ifdef USE_DMA_CHAINING
+       if (!use_dma_chaining) {
+               start_dma (ep, req);
+               return;
+       }
+
        /* the 2280 will be processing the queue unless queue hiccups after
         * the previous transfer:
         *  IN:   wanted automagic zlp, head doesn't (or vice versa)
+        *        DMA_FIFO_VALIDATE doesn't init from dma descriptors.
         *  OUT:  was "usb-short", we must restart.
         */
-       if (!req->valid) {
+       if (ep->is_in && !req->valid) {
                struct net2280_request  *entry, *prev = 0;
                int                     qmode, reqmode, done = 0;
 
@@ -1037,7 +1069,7 @@
                list_for_each_entry (entry, &ep->queue, queue) {
                        u32             dmacount;
 
-                       if (entry != req)
+                       if (entry == req)
                                continue;
                        dmacount = entry->td->dmacount;
                        if (!done) {
@@ -1051,6 +1083,7 @@
                                        prev = entry;
                                        continue;
                                } else {
+                                       /* force a hiccup */
                                        prev->td->dmacount |= dma_done_ie;
                                        done = 1;
                                }
@@ -1062,22 +1095,26 @@
                        entry->td->dmacount = dmacount;
                        prev = entry;
                }
-               start_dma (ep, req);
-       } else if (!ep->is_in
-                       && (readl (&ep->regs->ep_stat)
-                               & (1 << NAK_OUT_PACKETS)) != 0)
-               start_dma (ep, req);
-#else
-       start_dma (ep, req);
-#endif
+       }
+
+       /* descriptor queue was already set up */
+       writel (req->td_dma, &ep->dma->dmadesc);
+       writel (dmactl_default, &ep->dma->dmactl);
+       writel ((1 << DMA_START), &ep->dma->dmastat);
+
+       if (!ep->is_in)
+               stop_out_naking (ep);
 }
 
-static inline void abort_dma (struct net2280_ep *ep)
+static void abort_dma (struct net2280_ep *ep)
 {
        /* abort the current transfer */
-       writel ((1 << DMA_ABORT), &ep->dma->dmastat);
-
-       /* collect completed transfers (except the current one) */
+       if (likely (!list_empty (&ep->queue))) {
+               /* FIXME work around errata 0121, 0122, 0124 */
+               writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+               spin_stop_dma (ep->dma);
+       } else
+               stop_dma (ep->dma);
        scan_dma_completions (ep);
 }
 
@@ -1108,43 +1145,52 @@
        int                     stopped;
 
        ep = container_of (_ep, struct net2280_ep, ep);
-       req = container_of (_req, struct net2280_request, req);
        if (!_ep || (!ep->desc && ep->num != 0) || !_req)
                return -EINVAL;
 
        spin_lock_irqsave (&ep->dev->lock, flags);
        stopped = ep->stopped;
 
-       /* pause dma while we scan the queue */
+       /* quiesce dma while we patch the queue */
        dmactl = 0;
        ep->stopped = 1;
        if (ep->dma) {
                dmactl = readl (&ep->dma->dmactl);
-               writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl);
-               /* force synch, clean any completed requests */
-               spin_stop_dma (ep->dma);
+               /* WARNING errataum 0127 may kick in ... */
+               stop_dma (ep->dma);
                scan_dma_completions (ep);
        }
 
+       /* make sure it's still queued on this endpoint */
+       list_for_each_entry (req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+       if (&req->req != _req) {
+               spin_unlock_irqrestore (&ep->dev->lock, flags);
+               return -EINVAL;
+       }
+
        /* queue head may be partially complete. */
        if (ep->queue.next == &req->queue) {
                if (ep->dma) {
                        DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);
                        _req->status = -ECONNRESET;
                        abort_dma (ep);
-                       if (likely (ep->queue.next == &req->queue))
+                       if (likely (ep->queue.next == &req->queue)) {
+                               req->td->dmacount = 0;  /* invalidate */
                                dma_done (ep, req,
-                                       le32_to_cpup (&req->td->dmacount),
+                                       readl (&ep->dma->dmacount),
                                        -ECONNRESET);
+                       }
                } else {
                        DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);
                        done (ep, req, -ECONNRESET);
                }
                req = 0;
 
-#ifdef USE_DMA_CHAINING
        /* patch up hardware chaining data */
-       } else if (ep->dma) {
+       } else if (ep->dma && use_dma_chaining) {
                if (req->queue.prev == ep->queue.next) {
                        writel (le32_to_cpu (req->td->dmadesc),
                                &ep->dma->dmadesc);
@@ -1161,7 +1207,6 @@
                        if (req->td->dmacount & dma_done_ie)
                                prev->td->dmacount |= dma_done_ie;
                }
-#endif
        }
 
        if (req)
@@ -1188,10 +1233,14 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int net2280_fifo_status (struct usb_ep *_ep);
+
 static int
 net2280_set_halt (struct usb_ep *_ep, int value)
 {
        struct net2280_ep       *ep;
+       unsigned long           flags;
+       int                     retval = 0;
 
        ep = container_of (_ep, struct net2280_ep, ep);
        if (!_ep || (!ep->desc && ep->num != 0))
@@ -1202,19 +1251,27 @@
                                                == USB_ENDPOINT_XFER_ISOC)
                return -EINVAL;
 
-       VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
-
-       /* set/clear, then synch memory views with the device */
-       if (value) {
-               if (ep->num == 0)
-                       ep->dev->protocol_stall = 1;
-               else
-                       set_halt (ep);
-       } else
-               clear_halt (ep);
-       (void) readl (&ep->regs->ep_rsp);
+       spin_lock_irqsave (&ep->dev->lock, flags);
+       if (!list_empty (&ep->queue))
+               retval = -EAGAIN;
+       else if (ep->is_in && value && net2280_fifo_status (_ep) != 0)
+               retval = -EAGAIN;
+       else {
+               VDEBUG (ep->dev, "%s %s halt\n", _ep->name,
+                               value ? "set" : "clear");
+               /* set/clear, then synch memory views with the device */
+               if (value) {
+                       if (ep->num == 0)
+                               ep->dev->protocol_stall = 1;
+                       else
+                               set_halt (ep);
+               } else
+                       clear_halt (ep);
+               (void) readl (&ep->regs->ep_rsp);
+       }
+       spin_unlock_irqrestore (&ep->dev->lock, flags);
 
-       return 0;
+       return retval;
 }
 
 static int
@@ -1290,21 +1347,49 @@
 static int net2280_wakeup (struct usb_gadget *_gadget)
 {
        struct net2280          *dev;
+       u32                     tmp;
+       unsigned long           flags;
 
        if (!_gadget)
                return 0;
        dev = container_of (_gadget, struct net2280, gadget);
-       writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
+
+       spin_lock_irqsave (&dev->lock, flags);
+       tmp = readl (&dev->usb->usbctl);
+       if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE))
+               writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
+       spin_unlock_irqrestore (&dev->lock, flags);
 
        /* pci writes may still be posted */
        return 0;
 }
 
+static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value)
+{
+       struct net2280          *dev;
+       u32                     tmp;
+       unsigned long           flags;
+
+       if (!_gadget)
+               return 0;
+       dev = container_of (_gadget, struct net2280, gadget);
+
+       spin_lock_irqsave (&dev->lock, flags);
+       tmp = readl (&dev->usb->usbctl);
+       if (value)
+               tmp |= (1 << SELF_POWERED_STATUS);
+       else
+               tmp &= ~(1 << SELF_POWERED_STATUS);
+       writel (tmp, &dev->usb->usbctl);
+       spin_unlock_irqrestore (&dev->lock, flags);
+
+       return 0;
+}
+
 static const struct usb_gadget_ops net2280_ops = {
        .get_frame      = net2280_get_frame,
        .wakeup         = net2280_wakeup,
-
-       // .set_selfpowered = net2280_set_selfpowered,
+       .set_selfpowered = net2280_set_selfpowered,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1348,11 +1433,14 @@
 
        /* Main Control Registers */
        t = snprintf (next, size, "%s version " DRIVER_VERSION
-                       ", chiprev %04x\n"
+                       ", chiprev %04x, dma %s\n\n"
                        "devinit %03x fifoctl %08x gadget '%s'\n"
                        "pci irqenb0 %02x irqenb1 %08x "
                        "irqstat0 %04x irqstat1 %08x\n",
                        driver_name, dev->chiprev,
+                       use_dma
+                               ? (use_dma_chaining ? "chaining" : "enabled")
+                               : "disabled",
                        readl (&dev->regs->devinit),
                        readl (&dev->regs->fifoctl),
                        s,
@@ -1399,7 +1487,7 @@
                t1 = readl (&ep->regs->ep_cfg);
                t2 = readl (&ep->regs->ep_rsp) & 0xff;
                t = snprintf (next, size,
-                               "%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
+                               "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
                                        "irqenb %02x\n",
                                ep->ep.name, t1, t2,
                                (t2 & (1 << CLEAR_NAK_OUT_PACKETS))
@@ -1453,7 +1541,7 @@
                // none yet 
 
        /* Statistics */
-       t = snprintf (next, size, "irqs:  ");
+       t = snprintf (next, size, "\nirqs:  ");
        size -= t;
        next += t;
        for (i = 0; i < 7; i++) {
@@ -1504,7 +1592,7 @@
                                continue;
                        t = d->bEndpointAddress;
                        t = snprintf (next, size,
-                               "%s (ep%d%s-%s) max %04x %s\n",
+                               "\n%s (ep%d%s-%s) max %04x %s\n",
                                ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
                                (t & USB_DIR_IN) ? "in" : "out",
                                ({ char *val;
@@ -1552,6 +1640,20 @@
                                goto done;
                        size -= t;
                        next += t;
+
+                       if (ep->dma) {
+                               struct net2280_dma      *td;
+
+                               td = req->td;
+                               t = snprintf (next, size, "\t    td %08x "
+                                       " count %08x buf %08x desc %08x\n",
+                                       req->td_dma, td->dmacount,
+                                       td->dmaaddr, td->dmadesc);
+                               if (t <= 0 || t > size)
+                                       goto done;
+                               size -= t;
+                               next += t;
+                       }
                }
        }
 
@@ -1686,8 +1788,10 @@
 
        /* clear old dma and irq state */
        for (tmp = 0; tmp < 4; tmp++) {
-               writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat);
-               stop_dma (&dev->dma [tmp]);
+               struct net2280_ep       *ep = &dev->ep [tmp + 1];
+
+               if (ep->dma)
+                       abort_dma (ep);
        }
        writel (~0, &dev->regs->irqstat0),
        writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1),
@@ -1767,7 +1871,7 @@
                | (1 << SELF_POWERED_USB_DEVICE)
                | (1 << REMOTE_WAKEUP_SUPPORT)
                | (1 << USB_DETECT_ENABLE)
-               | (1 << DEVICE_REMOTE_WAKEUP_ENABLE)
+               | (1 << SELF_POWERED_STATUS)
                , &dev->usb->usbctl);
 
        /* enable irqs so we can see ep0 and general operation  */
@@ -1889,6 +1993,7 @@
        spin_unlock_irqrestore (&dev->lock, flags);
 
        driver->unbind (&dev->gadget);
+       dev->gadget.dev.driver = 0;
        dev->driver = 0;
 
        net2280_led_active (dev, 0);
@@ -2009,6 +2114,7 @@
                        /* stop DMA, leave ep NAKing */
                        writel ((1 << DMA_ABORT), &ep->dma->dmastat);
                        spin_stop_dma (ep->dma);
+                       req->td->dmacount = 0;  /* invalidate; abort won't */
 
                        /* buffer might have been too small */
                        t = readl (&ep->regs->ep_avail);
@@ -2021,9 +2127,11 @@
                        if (t || ep->dev->chiprev == 0x0100)
                                out_flush (ep);
 
-                       /* restart dma (still NAKing OUT!) if needed */
+                       /* (re)start dma if needed, stop NAKing */
                        if (!list_empty (&ep->queue))
                                restart_dma (ep);
+                       else
+                               stop_out_naking (ep);
                } else
                        DEBUG (ep->dev, "%s dma ep_stat %08x ??\n",
                                        ep->ep.name, t);
@@ -2398,18 +2506,18 @@
                tmp = readl (&dma->dmastat);
                writel (tmp, &dma->dmastat);
 
-#ifdef USE_DMA_CHAINING
-               /* chaining should stop only on error (which?)
+               /* chaining should stop on abort, short OUT from fifo,
                 * or (stat0 codepath) short OUT transfer.
                 */
-#else
-               if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) {
-                       DEBUG (ep->dev, "%s no xact done? %08x\n",
-                               ep->ep.name, tmp);
-                       continue;
+               if (!use_dma_chaining) {
+                       if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT))
+                                       == 0) {
+                               DEBUG (ep->dev, "%s no xact done? %08x\n",
+                                       ep->ep.name, tmp);
+                               continue;
+                       }
+                       stop_dma (ep->dma);
                }
-               stop_dma (ep->dma);
-#endif
 
                /* OUT transfers terminate when the data from the
                 * host is in our memory.  Process whatever's done.
@@ -2425,16 +2533,14 @@
 
                /* disable dma on inactive queues; else maybe restart */
                if (list_empty (&ep->queue)) {
-#ifdef USE_DMA_CHAINING
-                       stop_dma (ep->dma);
-#endif
+                       if (use_dma_chaining)
+                               stop_dma (ep->dma);
                } else {
                        tmp = readl (&dma->dmactl);
-                       if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0
+                       if (!use_dma_chaining
                                        || (tmp & (1 << DMA_ENABLE)) == 0)
                                restart_dma (ep);
-#ifdef USE_DMA_CHAINING
-                       else if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+                       else if (ep->is_in && use_dma_chaining) {
                                struct net2280_request  *req;
                                u32                     dmacount;
 
@@ -2449,12 +2555,9 @@
                                dmacount &= __constant_cpu_to_le32 (
                                                (1 << VALID_BIT)
                                                | DMA_BYTE_COUNT_MASK);
-                               if (dmacount && (dmacount & valid_bit) == 0) {
-                                       stop_dma (ep->dma);
+                               if (dmacount && (dmacount & valid_bit) == 0)
                                        restart_dma (ep);
-                               }
                        }
-#endif
                }
                ep->irqs++;
        }
@@ -2505,7 +2608,7 @@
 
 /* tear down the binding between this driver and the pci device */
 
-static void net2280_remove (struct pci_dev *pdev)
+static void __exit net2280_remove (struct pci_dev *pdev)
 {
        struct net2280          *dev = pci_get_drvdata (pdev);
 
@@ -2669,8 +2772,9 @@
        }
 
        /* enable lower-overhead pci memory bursts during DMA */
-       writel ((1 << PCI_RETRY_ABORT_ENABLE)
-                       | (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+       writel ( (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+                       // 256 write retries may not be enough...
+                       // | (1 << PCI_RETRY_ABORT_ENABLE)
                        | (1 << DMA_READ_MULTIPLE_ENABLE)
                        | (1 << DMA_READ_LINE_ENABLE)
                        , &dev->pci->pcimstctl);
@@ -2686,15 +2790,10 @@
        INFO (dev, "%s\n", driver_desc);
        INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
                        bufp, base, dev->chiprev);
-       bufp = DRIVER_VERSION
-#ifndef USE_DMA_CHAINING
-               " (no dma chain)"
-#endif
-#ifdef NET2280_DMA_OUT_WORKAROUND
-               " (no dma out)"
-#endif
-               ;
-       INFO (dev, "version: %s\n", bufp);
+       INFO (dev, "version: " DRIVER_VERSION "; dma %s\n",
+                       use_dma
+                               ? (use_dma_chaining ? "chaining" : "enabled")
+                               : "disabled");
        the_controller = dev;
 
        device_register (&dev->gadget.dev);
@@ -2729,7 +2828,7 @@
        .id_table =     pci_ids,
 
        .probe =        net2280_probe,
-       .remove =       net2280_remove,
+       .remove =       __exit_p(net2280_remove),
 
        /* FIXME add power management support */
 };
@@ -2740,6 +2839,8 @@
 
 static int __init init (void)
 {
+       if (!use_dma)
+               use_dma_chaining = 0;
        return pci_module_init (&net2280_pci_driver);
 }
 module_init (init);
--- a/drivers/usb/gadget/net2280.h      Fri Dec 19 14:48:57 2003
+++ b/drivers/usb/gadget/net2280.h      Fri Dec 19 14:48:57 2003
@@ -559,8 +559,7 @@
        unsigned                        enabled : 1,
                                        protocol_stall : 1,
                                        got_irq : 1,
-                                       region : 1,
-                                       selfpowered : 1;
+                                       region : 1;
        u16                             chiprev;
 
        /* pci state used to access those endpoints */

Reply via email to