aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/net2280.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/net2280.c')
-rw-r--r--drivers/usb/gadget/net2280.c2967
1 files changed, 2967 insertions, 0 deletions
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
new file mode 100644
index 00000000000..e5457f2026c
--- /dev/null
+++ b/drivers/usb/gadget/net2280.c
@@ -0,0 +1,2967 @@
+/*
+ * Driver for the PLX NET2280 USB device controller.
+ * Specs and errata are available from <http://www.plxtech.com>.
+ *
+ * PLX Technology Inc. (formerly NetChip Technology) supported the
+ * development of this driver.
+ *
+ *
+ * CODE STATUS HIGHLIGHTS
+ *
+ * This driver should work well with most "gadget" drivers, including
+ * the File Storage, Serial, and Ethernet/RNDIS gadget drivers
+ * as well as Gadget Zero and Gadgetfs.
+ *
+ * DMA is enabled by default. Drivers using transfer queues might use
+ * DMA chaining to remove IRQ latencies between transfers. (Except when
+ * short OUT transfers happen.) Drivers can use the req->no_interrupt
+ * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
+ * and DMA chaining is enabled.
+ *
+ * Note that almost all the errata workarounds here are only needed for
+ * rev1 chips. Rev1a silicon (0110) fixes almost all of them.
+ */
+
+/*
+ * Copyright (C) 2003 David Brownell
+ * Copyright (C) 2003-2005 PLX Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#undef DEBUG /* messages on error and most fault paths */
+#undef VERBOSE /* extra debug messages (success too) */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller"
+#define DRIVER_VERSION "2005 Feb 03"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define EP_DONTUSE 13 /* nonzero */
+
+#define USE_RDK_LEDS /* GPIO pins control three LEDs */
+
+
+static const char driver_name [] = "net2280";
+static const char driver_desc [] = DRIVER_DESC;
+
+static const char ep0name [] = "ep0";
+static const char *ep_name [] = {
+ ep0name,
+ "ep-a", "ep-b", "ep-c", "ep-d",
+ "ep-e", "ep-f",
+};
+
+/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
+ * use_dma_chaining -- dma descriptor queueing 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 more aggressive DMA.
+ */
+static int use_dma = 1;
+static int use_dma_chaining = 0;
+
+/* "modprobe net2280 use_dma=n" etc */
+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
+ * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
+ */
+static ushort fifo_mode = 0;
+
+/* "modprobe net2280 fifo_mode=1" etc */
+module_param (fifo_mode, ushort, 0644);
+
+/* enable_suspend -- When enabled, the driver will respond to
+ * USB suspend requests by powering down the NET2280. Otherwise,
+ * USB suspend requests will be ignored. This is acceptible for
+ * self-powered devices, and helps avoid some quirks.
+ */
+static int enable_suspend = 0;
+
+/* "modprobe net2280 enable_suspend=1" etc */
+module_param (enable_suspend, bool, S_IRUGO);
+
+
+#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG)
+static char *type_string (u8 bmAttributes)
+{
+ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK: return "bulk";
+ case USB_ENDPOINT_XFER_ISOC: return "iso";
+ case USB_ENDPOINT_XFER_INT: return "intr";
+ };
+ return "control";
+}
+#endif
+
+#include "net2280.h"
+
+#define valid_bit __constant_cpu_to_le32 (1 << VALID_BIT)
+#define dma_done_ie __constant_cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+ struct net2280 *dev;
+ struct net2280_ep *ep;
+ u32 max, tmp;
+ unsigned long flags;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* erratum 0119 workaround ties up an endpoint number */
+ if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE)
+ return -EDOM;
+
+ /* sanity check ep-e/ep-f since their fifos are small */
+ max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+ if (ep->num > 4 && max > 64)
+ return -ERANGE;
+
+ spin_lock_irqsave (&dev->lock, flags);
+ _ep->maxpacket = max & 0x7ff;
+ ep->desc = desc;
+
+ /* ep_reset() has already been called */
+ ep->stopped = 0;
+ ep->out_overflow = 0;
+
+ /* set speed-dependent max packet; may kick in high bandwidth */
+ set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max);
+
+ /* FIFO lines can't go to different packets. PIO is ok, so
+ * use it instead of troublesome (non-bulk) multi-packet DMA.
+ */
+ 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 = NULL;
+ }
+
+ /* set type, direction, address; reset fifo counters */
+ writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
+ tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ if (tmp == USB_ENDPOINT_XFER_INT) {
+ /* erratum 0105 workaround prevents hs NYET */
+ if (dev->chiprev == 0100
+ && dev->gadget.speed == USB_SPEED_HIGH
+ && !(desc->bEndpointAddress & USB_DIR_IN))
+ writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE),
+ &ep->regs->ep_rsp);
+ } else if (tmp == USB_ENDPOINT_XFER_BULK) {
+ /* catch some particularly blatant driver bugs */
+ if ((dev->gadget.speed == USB_SPEED_HIGH
+ && max != 512)
+ || (dev->gadget.speed == USB_SPEED_FULL
+ && max > 64)) {
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return -ERANGE;
+ }
+ }
+ ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
+ tmp <<= ENDPOINT_TYPE;
+ tmp |= desc->bEndpointAddress;
+ tmp |= (4 << ENDPOINT_BYTE_COUNT); /* default full fifo lines */
+ tmp |= 1 << ENDPOINT_ENABLE;
+ wmb ();
+
+ /* for OUT transfers, block the rx fifo until a read is posted */
+ ep->is_in = (tmp & USB_DIR_IN) != 0;
+ if (!ep->is_in)
+ writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+
+ writel (tmp, &ep->regs->ep_cfg);
+
+ /* enable irqs */
+ if (!ep->dma) { /* pio, per-packet */
+ tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+ writel (tmp, &dev->regs->pciirqenb0);
+
+ tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+ | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+ | readl (&ep->regs->ep_irqenb);
+ writel (tmp, &ep->regs->ep_irqenb);
+ } else { /* dma, per-request */
+ tmp = (1 << (8 + ep->num)); /* completion */
+ tmp |= readl (&dev->regs->pciirqenb1);
+ writel (tmp, &dev->regs->pciirqenb1);
+
+ /* for short OUT transfers, dma completions can't
+ * advance the queue; do it pio-style, by hand.
+ * NOTE erratum 0112 workaround #2
+ */
+ if ((desc->bEndpointAddress & USB_DIR_IN) == 0) {
+ tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE);
+ writel (tmp, &ep->regs->ep_irqenb);
+
+ tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+ writel (tmp, &dev->regs->pciirqenb0);
+ }
+ }
+
+ tmp = desc->bEndpointAddress;
+ DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n",
+ _ep->name, tmp & 0x0f, DIR_STRING (tmp),
+ type_string (desc->bmAttributes),
+ ep->dma ? "dma" : "pio", max);
+
+ /* pci writes may still be posted */
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return 0;
+}
+
+static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = readl (ptr);
+ if (result == ~(u32)0) /* "device unplugged" */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay (1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+static struct usb_ep_ops net2280_ep_ops;
+
+static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
+{
+ u32 tmp;
+
+ ep->desc = NULL;
+ INIT_LIST_HEAD (&ep->queue);
+
+ ep->ep.maxpacket = ~0;
+ ep->ep.ops = &net2280_ep_ops;
+
+ /* disable the dma, irqs, endpoint... */
+ if (ep->dma) {
+ writel (0, &ep->dma->dmactl);
+ writel ( (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT)
+ | (1 << DMA_TRANSACTION_DONE_INTERRUPT)
+ | (1 << DMA_ABORT)
+ , &ep->dma->dmastat);
+
+ tmp = readl (&regs->pciirqenb0);
+ tmp &= ~(1 << ep->num);
+ writel (tmp, &regs->pciirqenb0);
+ } else {
+ tmp = readl (&regs->pciirqenb1);
+ tmp &= ~(1 << (8 + ep->num)); /* completion */
+ writel (tmp, &regs->pciirqenb1);
+ }
+ writel (0, &ep->regs->ep_irqenb);
+
+ /* init to our chosen defaults, notably so that we NAK OUT
+ * packets until the driver queues a read (+note erratum 0112)
+ */
+ tmp = (1 << SET_NAK_OUT_PACKETS_MODE)
+ | (1 << SET_NAK_OUT_PACKETS)
+ | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
+ | (1 << CLEAR_INTERRUPT_MODE);
+
+ if (ep->num != 0) {
+ tmp |= (1 << CLEAR_ENDPOINT_TOGGLE)
+ | (1 << CLEAR_ENDPOINT_HALT);
+ }
+ writel (tmp, &ep->regs->ep_rsp);
+
+ /* scrub most status bits, and flush any fifo state */
+ writel ( (1 << TIMEOUT)
+ | (1 << USB_STALL_SENT)
+ | (1 << USB_IN_NAK_SENT)
+ | (1 << USB_IN_ACK_RCVD)
+ | (1 << USB_OUT_PING_NAK_SENT)
+ | (1 << USB_OUT_ACK_SENT)
+ | (1 << FIFO_OVERFLOW)
+ | (1 << FIFO_UNDERFLOW)
+ | (1 << FIFO_FLUSH)
+ | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
+ | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
+ | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+ | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_IN_TOKEN_INTERRUPT)
+ , &ep->regs->ep_stat);
+
+ /* fifo size is handled separately */
+}
+
+static void nuke (struct net2280_ep *);
+
+static int net2280_disable (struct usb_ep *_ep)
+{
+ struct net2280_ep *ep;
+ unsigned long flags;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || !ep->desc || _ep->name == ep0name)
+ return -EINVAL;
+
+ spin_lock_irqsave (&ep->dev->lock, flags);
+ nuke (ep);
+ ep_reset (ep->dev->regs, ep);
+
+ VDEBUG (ep->dev, "disabled %s %s\n",
+ ep->dma ? "dma" : "pio", _ep->name);
+
+ /* synch memory views with the device */
+ (void) readl (&ep->regs->ep_cfg);
+
+ if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
+ ep->dma = &ep->dev->dma [ep->num - 1];
+
+ spin_unlock_irqrestore (&ep->dev->lock, flags);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
+{
+ struct net2280_ep *ep;
+ struct net2280_request *req;
+
+ if (!_ep)
+ return NULL;
+ ep = container_of (_ep, struct net2280_ep, ep);
+
+ req = kmalloc (sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ memset (req, 0, sizeof *req);
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD (&req->queue);
+
+ /* this dma descriptor may be swapped with the previous dummy */
+ if (ep->dma) {
+ struct net2280_dma *td;
+
+ td = pci_pool_alloc (ep->dev->requests, gfp_flags,
+ &req->td_dma);
+ if (!td) {
+ kfree (req);
+ return NULL;
+ }
+ td->dmacount = 0; /* not VALID */
+ td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+ td->dmadesc = td->dmaaddr;
+ req->td = td;
+ }
+ return &req->req;
+}
+
+static void
+net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct net2280_ep *ep;
+ struct net2280_request *req;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || !_req)
+ return;
+
+ req = container_of (_req, struct net2280_request, req);
+ WARN_ON (!list_empty (&req->queue));
+ if (req->td)
+ pci_pool_free (ep->dev->requests, req->td, req->td_dma);
+ kfree (req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#undef USE_KMALLOC
+
+/* many common platforms have dma-coherent caches, which means that it's
+ * safe to use kmalloc() memory for all i/o buffers without using any
+ * cache flushing calls. (unless you're trying to share cache lines
+ * between dma and non-dma activities, which is a slow idea in any case.)
+ *
+ * other platforms need more care, with 2.5 having a moderately general
+ * solution (which falls down for allocations smaller than one page)
+ * that improves significantly on the 2.4 PCI allocators by removing
+ * the restriction that memory never be freed in_interrupt().
+ */
+#if defined(CONFIG_X86)
+#define USE_KMALLOC
+
+#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+#define USE_KMALLOC
+
+#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#define USE_KMALLOC
+
+/* FIXME there are other cases, including an x86-64 one ... */
+#endif
+
+/* allocating buffers this way eliminates dma mapping overhead, which
+ * on some platforms will mean eliminating a per-io buffer copy. with
+ * some kinds of system caches, further tweaks may still be needed.
+ */
+static void *
+net2280_alloc_buffer (
+ struct usb_ep *_ep,
+ unsigned bytes,
+ dma_addr_t *dma,
+ int gfp_flags
+)
+{
+ void *retval;
+ struct net2280_ep *ep;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep)
+ return NULL;
+ *dma = DMA_ADDR_INVALID;
+
+#if defined(USE_KMALLOC)
+ retval = kmalloc(bytes, gfp_flags);
+ if (retval)
+ *dma = virt_to_phys(retval);
+#else
+ if (ep->dma) {
+ /* the main problem with this call is that it wastes memory
+ * on typical 1/N page allocations: it allocates 1-N pages.
+ */
+#warning Using dma_alloc_coherent even with buffers smaller than a page.
+ retval = dma_alloc_coherent(&ep->dev->pdev->dev,
+ bytes, dma, gfp_flags);
+ } else
+ retval = kmalloc(bytes, gfp_flags);
+#endif
+ return retval;
+}
+
+static void
+net2280_free_buffer (
+ struct usb_ep *_ep,
+ void *buf,
+ dma_addr_t dma,
+ unsigned bytes
+) {
+ /* free memory into the right allocator */
+#ifndef USE_KMALLOC
+ if (dma != DMA_ADDR_INVALID) {
+ struct net2280_ep *ep;
+
+ ep = container_of(_ep, struct net2280_ep, ep);
+ if (!_ep)
+ return;
+ dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
+ } else
+#endif
+ kfree (buf);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* load a packet into the fifo we use for usb IN transfers.
+ * works for all endpoints.
+ *
+ * NOTE: pio with ep-a..ep-d could stuff multiple packets into the fifo
+ * at a time, but this code is simpler because it knows it only writes
+ * one packet. ep-a..ep-d should use dma instead.
+ */
+static void
+write_fifo (struct net2280_ep *ep, struct usb_request *req)
+{
+ struct net2280_ep_regs __iomem *regs = ep->regs;
+ u8 *buf;
+ u32 tmp;
+ unsigned count, total;
+
+ /* INVARIANT: fifo is currently empty. (testable) */
+
+ if (req) {
+ buf = req->buf + req->actual;
+ prefetch (buf);
+ total = req->length - req->actual;
+ } else {
+ total = 0;
+ buf = NULL;
+ }
+
+ /* write just one packet at a time */
+ count = ep->ep.maxpacket;
+ if (count > total) /* min() cannot be used on a bitfield */
+ count = total;
+
+ VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
+ ep->ep.name, count,
+ (count != ep->ep.maxpacket) ? " (short)" : "",
+ req);
+ while (count >= 4) {
+ /* NOTE be careful if you try to align these. fifo lines
+ * should normally be full (4 bytes) and successive partial
+ * lines are ok only in certain cases.
+ */
+ tmp = get_unaligned ((u32 *)buf);
+ cpu_to_le32s (&tmp);
+ writel (tmp, &regs->ep_data);
+ buf += 4;
+ count -= 4;
+ }
+
+ /* 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);
+ writel (tmp, &regs->ep_data);
+ }
+
+ /* pci writes may still be posted */
+}
+
+/* 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)
+{
+ u32 __iomem *statp;
+ u32 tmp;
+
+ ASSERT_OUT_NAKING (ep);
+
+ statp = &ep->regs->ep_stat;
+ writel ( (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ , statp);
+ writel ((1 << FIFO_FLUSH), statp);
+ mb ();
+ tmp = readl (statp);
+ if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ /* high speed did bulk NYET; fifo isn't filling */
+ && ep->dev->gadget.speed == USB_SPEED_FULL) {
+ unsigned usec;
+
+ usec = 50; /* 64 byte bulk/interrupt */
+ handshake (statp, (1 << USB_OUT_PING_NAK_SENT),
+ (1 << USB_OUT_PING_NAK_SENT), usec);
+ /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */
+ }
+}
+
+/* unload packet(s) from the fifo we use for usb OUT transfers.
+ * returns true iff the request completed, because of short packet
+ * or the request buffer having filled with full packets.
+ *
+ * for ep-a..ep-d this will read multiple packets out when they
+ * have been accepted.
+ */
+static int
+read_fifo (struct net2280_ep *ep, struct net2280_request *req)
+{
+ struct net2280_ep_regs __iomem *regs = ep->regs;
+ u8 *buf = req->req.buf + req->req.actual;
+ unsigned count, tmp, is_short;
+ unsigned cleanup = 0, prevent = 0;
+
+ /* erratum 0106 ... packets coming in during fifo reads might
+ * be incompletely rejected. not all cases have workarounds.
+ */
+ if (ep->dev->chiprev == 0x0100
+ && ep->dev->gadget.speed == USB_SPEED_FULL) {
+ udelay (1);
+ tmp = readl (&ep->regs->ep_stat);
+ if ((tmp & (1 << NAK_OUT_PACKETS)))
+ cleanup = 1;
+ else if ((tmp & (1 << FIFO_FULL))) {
+ start_out_naking (ep);
+ prevent = 1;
+ }
+ /* else: hope we don't see the problem */
+ }
+
+ /* never overflow the rx buffer. the fifo reads packets until
+ * it sees a short one; we might not be ready for them all.
+ */
+ prefetchw (buf);
+ count = readl (&regs->ep_avail);
+ if (unlikely (count == 0)) {
+ udelay (1);
+ tmp = readl (&ep->regs->ep_stat);
+ count = readl (&regs->ep_avail);
+ /* handled that data already? */
+ if (count == 0 && (tmp & (1 << NAK_OUT_PACKETS)) == 0)
+ return 0;
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ /* as with DMA, data overflow gets flushed */
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ ERROR (ep->dev,
+ "%s out fifo %d bytes, expected %d\n",
+ 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;
+
+ is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0);
+
+ VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n",
+ ep->ep.name, count, is_short ? " (short)" : "",
+ cleanup ? " flush" : "", prevent ? " nak" : "",
+ req, req->req.actual, req->req.length);
+
+ while (count >= 4) {
+ tmp = readl (&regs->ep_data);
+ cpu_to_le32s (&tmp);
+ put_unaligned (tmp, (u32 *)buf);
+ buf += 4;
+ count -= 4;
+ }
+ if (count) {
+ tmp = readl (&regs->ep_data);
+ /* LE conversion is implicit here: */
+ do {
+ *buf++ = (u8) tmp;
+ tmp >>= 8;
+ } while (--count);
+ }
+ if (cleanup)
+ out_flush (ep);
+ if (prevent) {
+ writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+ (void) readl (&ep->regs->ep_rsp);
+ }
+
+ return is_short || ((req->req.actual == req->req.length)
+ && !req->req.zero);
+}
+
+/* fill out dma descriptor to match a given request */
+static void
+fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+ struct net2280_dma *td = req->td;
+ u32 dmacount = req->req.length;
+
+ /* don't let DMA continue after a short OUT packet,
+ * so overruns can't affect the next transfer.
+ * in case of overruns on max-size packets, we can't
+ * stop the fifo from filling but we can flush it.
+ */
+ if (ep->is_in)
+ dmacount |= (1 << DMA_DIRECTION);
+ else if ((dmacount % ep->ep.maxpacket) != 0)
+ dmacount |= (1 << END_OF_CHAIN);
+
+ req->valid = valid;
+ if (valid)
+ dmacount |= (1 << VALID_BIT);
+ if (likely(!req->req.no_interrupt || !use_dma_chaining))
+ dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
+
+ /* td->dmadesc = previously set by caller */
+ td->dmaaddr = cpu_to_le32 (req->req.dma);
+
+ /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
+ wmb ();
+ td->dmacount = cpu_to_le32p (&dmacount);
+}
+
+static const u32 dmactl_default =
+ (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)
+ | (1 << DMA_VALID_BIT_ENABLE)
+ | (1 << DMA_SCATTER_GATHER_ENABLE)
+ /* erratum 0116 workaround part 2 (no AUTOSTART) */
+ | (1 << DMA_ENABLE);
+
+static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma)
+{
+ handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50);
+}
+
+static inline void stop_dma (struct net2280_dma_regs __iomem *dma)
+{
+ writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl);
+ spin_stop_dma (dma);
+}
+
+static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
+{
+ struct net2280_dma_regs __iomem *dma = ep->dma;
+
+ writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION),
+ &dma->dmacount);
+ writel (readl (&dma->dmastat), &dma->dmastat);
+
+ writel (td_dma, &dma->dmadesc);
+ writel (dmactl, &dma->dmactl);
+
+ /* erratum 0116 workaround part 3: pci arbiter away from net2280 */
+ (void) readl (&ep->dev->pci->pcimstctl);
+
+ writel ((1 << DMA_START), &dma->dmastat);
+
+ if (!ep->is_in)
+ stop_out_naking (ep);
+}
+
+static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
+{
+ u32 tmp;
+ struct net2280_dma_regs __iomem *dma = ep->dma;
+
+ /* FIXME can't use DMA for ZLPs */
+
+ /* on this path we "know" there's no dma active (yet) */
+ WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
+ writel (0, &ep->dma->dmactl);
+
+ /* previous OUT packet might have been short */
+ if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
+ & (1 << NAK_OUT_PACKETS)) != 0) {
+ writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
+ &ep->regs->ep_stat);
+
+ tmp = readl (&ep->regs->ep_avail);
+ if (tmp) {
+ writel (readl (&dma->dmastat), &dma->dmastat);
+
+ /* transfer all/some fifo data */
+ writel (req->req.dma, &dma->dmaaddr);
+ tmp = min (tmp, req->req.length);
+
+ /* dma irq, faking scatterlist status */
+ 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);
+ return;
+ }
+ }
+
+ tmp = dmactl_default;
+
+ /* force packet boundaries between dma requests, but prevent the
+ * controller from automagically writing a last "short" packet
+ * (zero length) unless the driver explicitly said to do that.
+ */
+ if (ep->is_in) {
+ if (likely ((req->req.length % ep->ep.maxpacket) != 0
+ || req->req.zero)) {
+ tmp |= (1 << DMA_FIFO_VALIDATE);
+ ep->in_fifo_validate = 1;
+ } else
+ ep->in_fifo_validate = 0;
+ }
+
+ /* init req->td, pointing to the current dummy */
+ req->td->dmadesc = cpu_to_le32 (ep->td_dma);
+ fill_dma_desc (ep, req, 1);
+
+ if (!use_dma_chaining)
+ req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
+
+ start_queue (ep, tmp, req->td_dma);
+}
+
+static inline void
+queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+ struct net2280_dma *end;
+ dma_addr_t tmp;
+
+ /* swap new dummy for old, link; fill and maybe activate */
+ end = ep->dummy;
+ ep->dummy = req->td;
+ req->td = end;
+
+ tmp = ep->td_dma;
+ ep->td_dma = req->td_dma;
+ req->td_dma = tmp;
+
+ end->dmadesc = cpu_to_le32 (ep->td_dma);
+
+ fill_dma_desc (ep, req, valid);
+}
+
+static void
+done (struct net2280_ep *ep, struct net2280_request *req, int status)
+{
+ struct net2280 *dev;
+ unsigned stopped = ep->stopped;
+
+ list_del_init (&req->queue);
+
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ dev = ep->dev;
+ if (req->mapped) {
+ pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ if (status && status != -ESHUTDOWN)
+ VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+ spin_unlock (&dev->lock);
+ req->req.complete (&ep->ep, &req->req);
+ spin_lock (&dev->lock);
+ ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+ struct net2280_request *req;
+ struct net2280_ep *ep;
+ struct net2280 *dev;
+ unsigned long flags;
+
+ /* we always require a cpu-view buffer, so that we can
+ * always use pio (as fallback or whatever).
+ */
+ req = container_of (_req, struct net2280_request, req);
+ if (!_req || !_req->complete || !_req->buf
+ || !list_empty (&req->queue))
+ return -EINVAL;
+ if (_req->length > (~0 & DMA_BYTE_COUNT_MASK))
+ return -EDOM;
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || (!ep->desc && ep->num != 0))
+ return -EINVAL;
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* FIXME implement PIO fallback for ZLPs with DMA */
+ if (ep->dma && _req->length == 0)
+ return -EOPNOTSUPP;
+
+ /* set up dma mapping in case the caller didn't */
+ if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
+ _req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ req->mapped = 1;
+ }
+
+#if 0
+ VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
+ _ep->name, _req, _req->length, _req->buf);
+#endif
+
+ spin_lock_irqsave (&dev->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ /* kickstart this i/o queue? */
+ if (list_empty (&ep->queue) && !ep->stopped) {
+ /* use DMA if the endpoint supports it, else pio */
+ if (ep->dma)
+ start_dma (ep, req);
+ else {
+ /* maybe there's no control data, just status ack */
+ if (ep->num == 0 && _req->length == 0) {
+ allow_status (ep);
+ done (ep, req, 0);
+ VDEBUG (dev, "%s status ack\n", ep->ep.name);
+ goto done;
+ }
+
+ /* PIO ... stuff the fifo, or unblock it. */
+ if (ep->is_in)
+ write_fifo (ep, _req);
+ else if (list_empty (&ep->queue)) {
+ u32 s;
+
+ /* OUT FIFO might have packet(s) buffered */
+ s = readl (&ep->regs->ep_stat);
+ if ((s & (1 << FIFO_EMPTY)) == 0) {
+ /* note: _req->short_not_ok is
+ * ignored here since PIO _always_
+ * stops queue advance here, and
+ * _req->status doesn't change for
+ * short reads (only _req->actual)
+ */
+ if (read_fifo (ep, req)) {
+ done (ep, req, 0);
+ if (ep->num == 0)
+ allow_status (ep);
+ /* don't queue it */
+ req = NULL;
+ } else
+ s = readl (&ep->regs->ep_stat);
+ }
+
+ /* don't NAK, let the fifo fill */
+ if (req && (s & (1 << NAK_OUT_PACKETS)))
+ writel ((1 << CLEAR_NAK_OUT_PACKETS),
+ &ep->regs->ep_rsp);
+ }
+ }
+
+ } else if (ep->dma) {
+ int valid = 1;
+
+ if (ep->is_in) {
+ int expect;
+
+ /* preventing magic zlps is per-engine state, not
+ * per-transfer; irq logic must recover hiccups.
+ */
+ expect = likely (req->req.zero
+ || (req->req.length % ep->ep.maxpacket) != 0);
+ if (expect != ep->in_fifo_validate)
+ valid = 0;
+ }
+ queue_dma (ep, req, valid);
+
+ } /* else the irq handler advances the queue. */
+
+ if (req)
+ list_add_tail (&req->queue, &ep->queue);
+done:
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ /* pci writes may still be posted */
+ return 0;
+}
+
+static inline void
+dma_done (
+ struct net2280_ep *ep,
+ struct net2280_request *req,
+ u32 dmacount,
+ int status
+)
+{
+ req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);
+ done (ep, req, status);
+}
+
+static void restart_dma (struct net2280_ep *ep);
+
+static void scan_dma_completions (struct net2280_ep *ep)
+{
+ /* only look at descriptors that were "naturally" retired,
+ * so fifo and list head state won't matter
+ */
+ while (!list_empty (&ep->queue)) {
+ struct net2280_request *req;
+ u32 tmp;
+
+ req = list_entry (ep->queue.next,
+ struct net2280_request, queue);
+ if (!req->valid)
+ break;
+ rmb ();
+ tmp = le32_to_cpup (&req->td->dmacount);
+ if ((tmp & (1 << VALID_BIT)) != 0)
+ break;
+
+ /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
+ * cases where DMA must be aborted; this code handles
+ * all non-abort DMA completions.
+ */
+ if (unlikely (req->td->dmadesc == 0)) {
+ /* paranoia */
+ tmp = readl (&ep->dma->dmacount);
+ if (tmp & DMA_BYTE_COUNT_MASK)
+ break;
+ /* single transfer mode */
+ dma_done (ep, req, tmp, 0);
+ break;
+ } else if (!ep->is_in
+ && (req->req.length % ep->ep.maxpacket) != 0) {
+ tmp = readl (&ep->regs->ep_stat);
+
+ /* AVOID TROUBLE HERE by not issuing short reads from
+ * your gadget driver. That helps avoids errata 0121,
+ * 0122, and 0124; not all cases trigger the warning.
+ */
+ if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+ WARN (ep->dev, "%s lost packet sync!\n",
+ ep->ep.name);
+ req->req.status = -EOVERFLOW;
+ } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) {
+ /* fifo gets flushed later */
+ ep->out_overflow = 1;
+ DEBUG (ep->dev, "%s dma, discard %d len %d\n",
+ ep->ep.name, tmp,
+ req->req.length);
+ req->req.status = -EOVERFLOW;
+ }
+ }
+ dma_done (ep, req, tmp, 0);
+ }
+}
+
+static void restart_dma (struct net2280_ep *ep)
+{
+ struct net2280_request *req;
+ u32 dmactl = dmactl_default;
+
+ if (ep->stopped)
+ return;
+ req = list_entry (ep->queue.next, struct net2280_request, queue);
+
+ 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 (ep->is_in && !req->valid) {
+ struct net2280_request *entry, *prev = NULL;
+ int reqmode, done = 0;
+
+ DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
+ ep->in_fifo_validate = likely (req->req.zero
+ || (req->req.length % ep->ep.maxpacket) != 0);
+ if (ep->in_fifo_validate)
+ dmactl |= (1 << DMA_FIFO_VALIDATE);
+ list_for_each_entry (entry, &ep->queue, queue) {
+ u32 dmacount;
+
+ if (entry == req)
+ continue;
+ dmacount = entry->td->dmacount;
+ if (!done) {
+ reqmode = likely (entry->req.zero
+ || (entry->req.length
+ % ep->ep.maxpacket) != 0);
+ if (reqmode == ep->in_fifo_validate