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>
This commit is contained in:
parent
80f8af0c59
commit
901b3d75e7
|
@ -26,7 +26,8 @@
|
||||||
* Copyright (C) 2003 David Brownell
|
* Copyright (C) 2003 David Brownell
|
||||||
* Copyright (C) 2003-2005 PLX Technology, Inc.
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -85,7 +86,7 @@ static const char driver_name [] = "net2280";
|
||||||
static const char driver_desc [] = DRIVER_DESC;
|
static const char driver_desc [] = DRIVER_DESC;
|
||||||
|
|
||||||
static const char ep0name [] = "ep0";
|
static const char ep0name [] = "ep0";
|
||||||
static const char *ep_name [] = {
|
static const char *const ep_name [] = {
|
||||||
ep0name,
|
ep0name,
|
||||||
"ep-a", "ep-b", "ep-c", "ep-d",
|
"ep-a", "ep-b", "ep-c", "ep-d",
|
||||||
"ep-e", "ep-f",
|
"ep-e", "ep-f",
|
||||||
|
@ -225,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
||||||
if (!ep->is_in)
|
if (!ep->is_in)
|
||||||
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
|
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
|
||||||
else if (dev->pdev->device != 0x2280) {
|
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)
|
writel ((1 << CLEAR_NAK_OUT_PACKETS)
|
||||||
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
|
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
|
||||||
}
|
}
|
||||||
|
@ -288,7 +291,7 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
|
||||||
return -ETIMEDOUT;
|
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)
|
static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
|
||||||
{
|
{
|
||||||
|
@ -449,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#undef USE_KMALLOC
|
/*
|
||||||
|
* dma-coherent memory allocation (for dma-capable endpoints)
|
||||||
/* 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
|
* NOTE: the dma_*_coherent() API calls suck. Most implementations are
|
||||||
* solution (which falls down for allocations smaller than one page)
|
* (a) page-oriented, so small buffers lose big; and (b) asymmetric with
|
||||||
* that improves significantly on the 2.4 PCI allocators by removing
|
* respect to calls with irqs disabled: alloc is safe, free is not.
|
||||||
* the restriction that memory never be freed in_interrupt().
|
* 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 *
|
static void *
|
||||||
net2280_alloc_buffer (
|
net2280_alloc_buffer (
|
||||||
struct usb_ep *_ep,
|
struct usb_ep *_ep,
|
||||||
|
@ -493,43 +477,71 @@ net2280_alloc_buffer (
|
||||||
return NULL;
|
return NULL;
|
||||||
*dma = DMA_ADDR_INVALID;
|
*dma = DMA_ADDR_INVALID;
|
||||||
|
|
||||||
#if defined(USE_KMALLOC)
|
if (ep->dma)
|
||||||
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,
|
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
|
||||||
bytes, dma, gfp_flags);
|
bytes, dma, gfp_flags);
|
||||||
} else
|
else
|
||||||
retval = kmalloc(bytes, gfp_flags);
|
retval = kmalloc(bytes, gfp_flags);
|
||||||
#endif
|
|
||||||
return retval;
|
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
|
static void
|
||||||
net2280_free_buffer (
|
net2280_free_buffer (
|
||||||
struct usb_ep *_ep,
|
struct usb_ep *_ep,
|
||||||
void *buf,
|
void *address,
|
||||||
dma_addr_t dma,
|
dma_addr_t dma,
|
||||||
unsigned bytes
|
unsigned bytes
|
||||||
) {
|
) {
|
||||||
/* free memory into the right allocator */
|
/* free memory into the right allocator */
|
||||||
#ifndef USE_KMALLOC
|
|
||||||
if (dma != DMA_ADDR_INVALID) {
|
if (dma != DMA_ADDR_INVALID) {
|
||||||
struct net2280_ep *ep;
|
struct net2280_ep *ep;
|
||||||
|
struct free_record *buf = address;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
ep = container_of(_ep, struct net2280_ep, ep);
|
ep = container_of(_ep, struct net2280_ep, ep);
|
||||||
if (!_ep)
|
if (!_ep)
|
||||||
return;
|
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
|
} else
|
||||||
#endif
|
kfree (address);
|
||||||
kfree (buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
@ -737,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
|
||||||
*/
|
*/
|
||||||
if (ep->is_in)
|
if (ep->is_in)
|
||||||
dmacount |= (1 << DMA_DIRECTION);
|
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);
|
dmacount |= (1 << END_OF_CHAIN);
|
||||||
|
|
||||||
req->valid = valid;
|
req->valid = valid;
|
||||||
|
@ -1373,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep)
|
||||||
(void) readl (&ep->regs->ep_rsp);
|
(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,
|
.enable = net2280_enable,
|
||||||
.disable = net2280_disable,
|
.disable = net2280_disable,
|
||||||
|
|
||||||
|
@ -2241,7 +2254,8 @@ static void handle_ep_small (struct net2280_ep *ep)
|
||||||
req->td->dmacount = 0;
|
req->td->dmacount = 0;
|
||||||
t = readl (&ep->regs->ep_avail);
|
t = readl (&ep->regs->ep_avail);
|
||||||
dma_done (ep, req, count,
|
dma_done (ep, req, count,
|
||||||
(ep->out_overflow || t) ? -EOVERFLOW : 0);
|
(ep->out_overflow || t)
|
||||||
|
? -EOVERFLOW : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* also flush to prevent erratum 0106 trouble */
|
/* also flush to prevent erratum 0106 trouble */
|
||||||
|
@ -2583,9 +2597,11 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
|
||||||
*/
|
*/
|
||||||
if (stat & tmp) {
|
if (stat & tmp) {
|
||||||
writel (tmp, &dev->regs->irqstat1);
|
writel (tmp, &dev->regs->irqstat1);
|
||||||
if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
|
if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
|
||||||
((readl (&dev->usb->usbstat) & mask) == 0))
|
&& ((readl (&dev->usb->usbstat) & mask)
|
||||||
|| ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
|
== 0))
|
||||||
|
|| ((readl (&dev->usb->usbctl)
|
||||||
|
& (1 << VBUS_PIN)) == 0)
|
||||||
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
|
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
|
||||||
DEBUG (dev, "disconnect %s\n",
|
DEBUG (dev, "disconnect %s\n",
|
||||||
dev->driver->driver.name);
|
dev->driver->driver.name);
|
||||||
|
@ -2870,6 +2886,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
}
|
}
|
||||||
dev->region = 1;
|
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);
|
base = ioremap_nocache (resource, len);
|
||||||
if (base == NULL) {
|
if (base == NULL) {
|
||||||
DEBUG (dev, "can't map memory\n");
|
DEBUG (dev, "can't map memory\n");
|
||||||
|
@ -2984,7 +3004,7 @@ static void net2280_shutdown (struct pci_dev *pdev)
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static struct pci_device_id pci_ids [] = { {
|
static const struct pci_device_id pci_ids [] = { {
|
||||||
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
|
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
|
||||||
.class_mask = ~0,
|
.class_mask = ~0,
|
||||||
.vendor = 0x17cc,
|
.vendor = 0x17cc,
|
||||||
|
|
Loading…
Reference in a new issue