USB: net2280: update dma buffer allocation

This updates the code handling dma-coherent buffer allocations, basically
reusing code from the musb_hdrc driver.  Instead of trying to work around two
significant limitations of the dma framework (memory wastage for buffers
smaller than a page, and inconsistency between calling context requirements
for allocation and free) this just works around one of them (the latter).

So count this as two steps forward (bugfixes:  the latter issue could cause
errors on some platforms, and some MIPS changes broke code for the former), 
and one step back (increasing cross-platform memory wastage).

Plus linelength and whitespace fixes; and minor data segment shrinkage.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 0924323..3bda37f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2,7 +2,7 @@
  * 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 
+ * PLX Technology Inc. (formerly NetChip Technology) supported the
  * development of this driver.
  *
  *
@@ -26,7 +26,8 @@
  * Copyright (C) 2003 David Brownell
  * Copyright (C) 2003-2005 PLX Technology, Inc.
  *
- * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
+ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility
+ *	with 2282 chip
  *
  * 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
@@ -85,7 +86,7 @@
 static const char driver_desc [] = DRIVER_DESC;
 
 static const char ep0name [] = "ep0";
-static const char *ep_name [] = {
+static const char *const ep_name [] = {
 	ep0name,
 	"ep-a", "ep-b", "ep-c", "ep-d",
 	"ep-e", "ep-f",
@@ -225,7 +226,9 @@
 	if (!ep->is_in)
 		writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
 	else if (dev->pdev->device != 0x2280) {
-		/* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
+		/* Added for 2282, Don't use nak packets on an in endpoint,
+		 * this was ignored on 2280
+		 */
 		writel ((1 << CLEAR_NAK_OUT_PACKETS)
 			| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
 	}
@@ -288,7 +291,7 @@
 	return -ETIMEDOUT;
 }
 
-static struct usb_ep_ops net2280_ep_ops;
+static const struct usb_ep_ops net2280_ep_ops;
 
 static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
 {
@@ -449,34 +452,15 @@
 
 /*-------------------------------------------------------------------------*/
 
-#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.)
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
  *
- * 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().
+ * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
+ * respect to calls with irqs disabled:  alloc is safe, free is not.
+ * We currently work around (b), but not (a).
  */
-#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_DMA_NONCOHERENT)
-#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,
@@ -493,43 +477,71 @@
 		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.
+	if (ep->dma)
 		retval = dma_alloc_coherent(&ep->dev->pdev->dev,
 				bytes, dma, gfp_flags);
-	} else
+	else
 		retval = kmalloc(bytes, gfp_flags);
-#endif
 	return retval;
 }
 
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+	struct list_head	list;
+	struct device		*dev;
+	unsigned		bytes;
+	dma_addr_t		dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+	spin_lock_irq(&buflock);
+	while (!list_empty(&buffers)) {
+		struct free_record	*buf;
+
+		buf = list_entry(buffers.next, struct free_record, list);
+		list_del(&buf->list);
+		spin_unlock_irq(&buflock);
+
+		dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+		spin_lock_irq(&buflock);
+	}
+	spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
 static void
 net2280_free_buffer (
 	struct usb_ep *_ep,
-	void *buf,
+	void *address,
 	dma_addr_t dma,
 	unsigned bytes
 ) {
 	/* free memory into the right allocator */
-#ifndef	USE_KMALLOC
 	if (dma != DMA_ADDR_INVALID) {
 		struct net2280_ep	*ep;
+		struct free_record	*buf = address;
+		unsigned long		flags;
 
 		ep = container_of(_ep, struct net2280_ep, ep);
 		if (!_ep)
 			return;
-		dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
+
+		ep = container_of (_ep, struct net2280_ep, ep);
+		buf->dev = &ep->dev->pdev->dev;
+		buf->bytes = bytes;
+		buf->dma = dma;
+
+		spin_lock_irqsave(&buflock, flags);
+		list_add_tail(&buf->list, &buffers);
+		tasklet_schedule(&deferred_free);
+		spin_unlock_irqrestore(&buflock, flags);
 	} else
-#endif
-		kfree (buf);
+		kfree (address);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -737,7 +749,8 @@
 	 */
 	if (ep->is_in)
 		dmacount |= (1 << DMA_DIRECTION);
-	if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
+	if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)
+			|| ep->dev->pdev->device != 0x2280)
 		dmacount |= (1 << END_OF_CHAIN);
 
 	req->valid = valid;
@@ -812,7 +825,7 @@
 
 	/* previous OUT packet might have been short */
 	if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
-		 		& (1 << NAK_OUT_PACKETS)) != 0) {
+				& (1 << NAK_OUT_PACKETS)) != 0) {
 		writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
 			&ep->regs->ep_stat);
 
@@ -1373,7 +1386,7 @@
 	(void) readl (&ep->regs->ep_rsp);
 }
 
-static struct usb_ep_ops net2280_ep_ops = {
+static const struct usb_ep_ops net2280_ep_ops = {
 	.enable		= net2280_enable,
 	.disable	= net2280_disable,
 
@@ -1631,7 +1644,7 @@
 	}
 
 	/* Indexed Registers */
-		// none yet 
+		// none yet
 
 	/* Statistics */
 	t = scnprintf (next, size, "\nirqs:  ");
@@ -1691,11 +1704,11 @@
 				({ char *val;
 				 switch (d->bmAttributes & 0x03) {
 				 case USB_ENDPOINT_XFER_BULK:
-				 	val = "bulk"; break;
+					val = "bulk"; break;
 				 case USB_ENDPOINT_XFER_INT:
-				 	val = "intr"; break;
+					val = "intr"; break;
 				 default:
-				 	val = "iso"; break;
+					val = "iso"; break;
 				 }; val; }),
 				le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
 				ep->dma ? "dma" : "pio", ep->fifo_size
@@ -1808,8 +1821,8 @@
  * net2280_set_fifo_mode - change allocation of fifo buffers
  * @gadget: access to the net2280 device that will be updated
  * @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
- * 	1 for two 2kB buffers (ep-a and ep-b only);
- * 	2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ *	1 for two 2kB buffers (ep-a and ep-b only);
+ *	2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
  *
  * returns zero on success, else negative errno.  when this succeeds,
  * the contents of gadget->ep_list may have changed.
@@ -2241,7 +2254,8 @@
 				req->td->dmacount = 0;
 				t = readl (&ep->regs->ep_avail);
 				dma_done (ep, req, count,
-					(ep->out_overflow || t) ? -EOVERFLOW : 0);
+					(ep->out_overflow || t)
+						? -EOVERFLOW : 0);
 			}
 
 			/* also flush to prevent erratum 0106 trouble */
@@ -2411,7 +2425,7 @@
 			, &ep->regs->ep_stat);
 		u.raw [0] = readl (&dev->usb->setup0123);
 		u.raw [1] = readl (&dev->usb->setup4567);
-		
+
 		cpu_to_le32s (&u.raw [0]);
 		cpu_to_le32s (&u.raw [1]);
 
@@ -2578,14 +2592,16 @@
 
 	/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
 	 * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
-	 * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT 
+	 * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
 	 * only indicates a change in the reset state).
 	 */
 	if (stat & tmp) {
 		writel (tmp, &dev->regs->irqstat1);
-		if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && 
-				((readl (&dev->usb->usbstat) & mask) == 0))
-				|| ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0) 
+		if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
+					&& ((readl (&dev->usb->usbstat) & mask)
+							== 0))
+				|| ((readl (&dev->usb->usbctl)
+					& (1 << VBUS_PIN)) == 0)
 			    ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
 			DEBUG (dev, "disconnect %s\n",
 					dev->driver->driver.name);
@@ -2852,7 +2868,7 @@
 
 	/* now all the pci goodies ... */
 	if (pci_enable_device (pdev) < 0) {
-   	        retval = -ENODEV;
+	        retval = -ENODEV;
 		goto done;
 	}
 	dev->enabled = 1;
@@ -2870,6 +2886,10 @@
 	}
 	dev->region = 1;
 
+	/* FIXME provide firmware download interface to put
+	 * 8051 code into the chip, e.g. to turn on PCI PM.
+	 */
+
 	base = ioremap_nocache (resource, len);
 	if (base == NULL) {
 		DEBUG (dev, "can't map memory\n");
@@ -2984,16 +3004,16 @@
 
 /*-------------------------------------------------------------------------*/
 
-static struct pci_device_id pci_ids [] = { {
-	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-	.class_mask = 	~0,
+static const struct pci_device_id pci_ids [] = { {
+	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask =	~0,
 	.vendor =	0x17cc,
 	.device =	0x2280,
 	.subvendor =	PCI_ANY_ID,
 	.subdevice =	PCI_ANY_ID,
 }, {
-	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-	.class_mask = 	~0,
+	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask =	~0,
 	.vendor =	0x17cc,
 	.device =	0x2282,
 	.subvendor =	PCI_ANY_ID,