diff options
Diffstat (limited to 'drivers/usb/gadget')
| -rw-r--r-- | drivers/usb/gadget/net2280.c | 156 |
1 files changed, 88 insertions, 68 deletions
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 09243239d948..3bda37f9a35f 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Driver for the PLX NET2280 USB device controller. | 2 | * Driver for the PLX NET2280 USB device controller. |
| 3 | * Specs and errata are available from <http://www.plxtech.com>. | 3 | * Specs and errata are available from <http://www.plxtech.com>. |
| 4 | * | 4 | * |
| 5 | * PLX Technology Inc. (formerly NetChip Technology) supported the | 5 | * PLX Technology Inc. (formerly NetChip Technology) supported the |
| 6 | * development of this driver. | 6 | * development of this driver. |
| 7 | * | 7 | * |
| 8 | * | 8 | * |
| @@ -26,7 +26,8 @@ | |||
| 26 | * Copyright (C) 2003 David Brownell | 26 | * Copyright (C) 2003 David Brownell |
| 27 | * Copyright (C) 2003-2005 PLX Technology, Inc. | 27 | * Copyright (C) 2003-2005 PLX Technology, Inc. |
| 28 | * | 28 | * |
| 29 | * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip | 29 | * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility |
| 30 | * with 2282 chip | ||
| 30 | * | 31 | * |
| 31 | * This program is free software; you can redistribute it and/or modify | 32 | * This program is free software; you can redistribute it and/or modify |
| 32 | * it under the terms of the GNU General Public License as published by | 33 | * it under the terms of the GNU General Public License as published by |
| @@ -85,7 +86,7 @@ static const char driver_name [] = "net2280"; | |||
| 85 | static const char driver_desc [] = DRIVER_DESC; | 86 | static const char driver_desc [] = DRIVER_DESC; |
| 86 | 87 | ||
| 87 | static const char ep0name [] = "ep0"; | 88 | static const char ep0name [] = "ep0"; |
| 88 | static const char *ep_name [] = { | 89 | static const char *const ep_name [] = { |
| 89 | ep0name, | 90 | ep0name, |
| 90 | "ep-a", "ep-b", "ep-c", "ep-d", | 91 | "ep-a", "ep-b", "ep-c", "ep-d", |
| 91 | "ep-e", "ep-f", | 92 | "ep-e", "ep-f", |
| @@ -225,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | |||
| 225 | if (!ep->is_in) | 226 | if (!ep->is_in) |
| 226 | writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); | 227 | writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); |
| 227 | else if (dev->pdev->device != 0x2280) { | 228 | else if (dev->pdev->device != 0x2280) { |
| 228 | /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */ | 229 | /* Added for 2282, Don't use nak packets on an in endpoint, |
| 230 | * this was ignored on 2280 | ||
| 231 | */ | ||
| 229 | writel ((1 << CLEAR_NAK_OUT_PACKETS) | 232 | writel ((1 << CLEAR_NAK_OUT_PACKETS) |
| 230 | | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); | 233 | | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); |
| 231 | } | 234 | } |
| @@ -288,7 +291,7 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) | |||
| 288 | return -ETIMEDOUT; | 291 | return -ETIMEDOUT; |
| 289 | } | 292 | } |
| 290 | 293 | ||
| 291 | static struct usb_ep_ops net2280_ep_ops; | 294 | static const struct usb_ep_ops net2280_ep_ops; |
| 292 | 295 | ||
| 293 | static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) | 296 | static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) |
| 294 | { | 297 | { |
| @@ -449,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) | |||
| 449 | 452 | ||
| 450 | /*-------------------------------------------------------------------------*/ | 453 | /*-------------------------------------------------------------------------*/ |
| 451 | 454 | ||
| 452 | #undef USE_KMALLOC | 455 | /* |
| 453 | 456 | * dma-coherent memory allocation (for dma-capable endpoints) | |
| 454 | /* many common platforms have dma-coherent caches, which means that it's | ||
| 455 | * safe to use kmalloc() memory for all i/o buffers without using any | ||
| 456 | * cache flushing calls. (unless you're trying to share cache lines | ||
| 457 | * between dma and non-dma activities, which is a slow idea in any case.) | ||
| 458 | * | 457 | * |
| 459 | * other platforms need more care, with 2.5 having a moderately general | 458 | * NOTE: the dma_*_coherent() API calls suck. Most implementations are |
| 460 | * solution (which falls down for allocations smaller than one page) | 459 | * (a) page-oriented, so small buffers lose big; and (b) asymmetric with |
| 461 | * that improves significantly on the 2.4 PCI allocators by removing | 460 | * respect to calls with irqs disabled: alloc is safe, free is not. |
| 462 | * the restriction that memory never be freed in_interrupt(). | 461 | * We currently work around (b), but not (a). |
| 463 | */ | 462 | */ |
| 464 | #if defined(CONFIG_X86) | ||
| 465 | #define USE_KMALLOC | ||
| 466 | |||
| 467 | #elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) | ||
| 468 | #define USE_KMALLOC | ||
| 469 | 463 | ||
| 470 | #elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT) | ||
| 471 | #define USE_KMALLOC | ||
| 472 | |||
| 473 | /* FIXME there are other cases, including an x86-64 one ... */ | ||
| 474 | #endif | ||
| 475 | |||
| 476 | /* allocating buffers this way eliminates dma mapping overhead, which | ||
| 477 | * on some platforms will mean eliminating a per-io buffer copy. with | ||
| 478 | * some kinds of system caches, further tweaks may still be needed. | ||
| 479 | */ | ||
| 480 | static void * | 464 | static void * |
| 481 | net2280_alloc_buffer ( | 465 | net2280_alloc_buffer ( |
| 482 | struct usb_ep *_ep, | 466 | struct usb_ep *_ep, |
| @@ -493,43 +477,71 @@ net2280_alloc_buffer ( | |||
| 493 | return NULL; | 477 | return NULL; |
| 494 | *dma = DMA_ADDR_INVALID; | 478 | *dma = DMA_ADDR_INVALID; |
| 495 | 479 | ||
| 496 | #if defined(USE_KMALLOC) | 480 | if (ep->dma) |
| 497 | retval = kmalloc(bytes, gfp_flags); | ||
| 498 | if (retval) | ||
| 499 | *dma = virt_to_phys(retval); | ||
| 500 | #else | ||
| 501 | if (ep->dma) { | ||
| 502 | /* the main problem with this call is that it wastes memory | ||
| 503 | * on typical 1/N page allocations: it allocates 1-N pages. | ||
| 504 | */ | ||
| 505 | #warning Using dma_alloc_coherent even with buffers smaller than a page. | ||
| 506 | retval = dma_alloc_coherent(&ep->dev->pdev->dev, | 481 | retval = dma_alloc_coherent(&ep->dev->pdev->dev, |
| 507 | bytes, dma, gfp_flags); | 482 | bytes, dma, gfp_flags); |
| 508 | } else | 483 | else |
| 509 | retval = kmalloc(bytes, gfp_flags); | 484 | retval = kmalloc(bytes, gfp_flags); |
| 510 | #endif | ||
| 511 | return retval; | 485 | return retval; |
| 512 | } | 486 | } |
| 513 | 487 | ||
| 488 | static DEFINE_SPINLOCK(buflock); | ||
| 489 | static LIST_HEAD(buffers); | ||
| 490 | |||
| 491 | struct free_record { | ||
| 492 | struct list_head list; | ||
| 493 | struct device *dev; | ||
| 494 | unsigned bytes; | ||
| 495 | dma_addr_t dma; | ||
| 496 | }; | ||
| 497 | |||
| 498 | static void do_free(unsigned long ignored) | ||
| 499 | { | ||
| 500 | spin_lock_irq(&buflock); | ||
| 501 | while (!list_empty(&buffers)) { | ||
| 502 | struct free_record *buf; | ||
| 503 | |||
| 504 | buf = list_entry(buffers.next, struct free_record, list); | ||
| 505 | list_del(&buf->list); | ||
| 506 | spin_unlock_irq(&buflock); | ||
| 507 | |||
| 508 | dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma); | ||
| 509 | |||
| 510 | spin_lock_irq(&buflock); | ||
| 511 | } | ||
| 512 | spin_unlock_irq(&buflock); | ||
| 513 | } | ||
| 514 | |||
| 515 | static DECLARE_TASKLET(deferred_free, do_free, 0); | ||
| 516 | |||
| 514 | static void | 517 | static void |
| 515 | net2280_free_buffer ( | 518 | net2280_free_buffer ( |
| 516 | struct usb_ep *_ep, | 519 | struct usb_ep *_ep, |
| 517 | void *buf, | 520 | void *address, |
| 518 | dma_addr_t dma, | 521 | dma_addr_t dma, |
| 519 | unsigned bytes | 522 | unsigned bytes |
| 520 | ) { | 523 | ) { |
| 521 | /* free memory into the right allocator */ | 524 | /* free memory into the right allocator */ |
| 522 | #ifndef USE_KMALLOC | ||
| 523 | if (dma != DMA_ADDR_INVALID) { | 525 | if (dma != DMA_ADDR_INVALID) { |
| 524 | struct net2280_ep *ep; | 526 | struct net2280_ep *ep; |
| 527 | struct free_record *buf = address; | ||
| 528 | unsigned long flags; | ||
| 525 | 529 | ||
| 526 | ep = container_of(_ep, struct net2280_ep, ep); | 530 | ep = container_of(_ep, struct net2280_ep, ep); |
| 527 | if (!_ep) | 531 | if (!_ep) |
| 528 | return; | 532 | return; |
| 529 | dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma); | 533 | |
| 534 | ep = container_of (_ep, struct net2280_ep, ep); | ||
| 535 | buf->dev = &ep->dev->pdev->dev; | ||
| 536 | buf->bytes = bytes; | ||
| 537 | buf->dma = dma; | ||
| 538 | |||
| 539 | spin_lock_irqsave(&buflock, flags); | ||
| 540 | list_add_tail(&buf->list, &buffers); | ||
| 541 | tasklet_schedule(&deferred_free); | ||
| 542 | spin_unlock_irqrestore(&buflock, flags); | ||
| 530 | } else | 543 | } else |
| 531 | #endif | 544 | kfree (address); |
| 532 | kfree (buf); | ||
| 533 | } | 545 | } |
| 534 | 546 | ||
| 535 | /*-------------------------------------------------------------------------*/ | 547 | /*-------------------------------------------------------------------------*/ |
| @@ -737,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) | |||
| 737 | */ | 749 | */ |
| 738 | if (ep->is_in) | 750 | if (ep->is_in) |
| 739 | dmacount |= (1 << DMA_DIRECTION); | 751 | dmacount |= (1 << DMA_DIRECTION); |
| 740 | if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280) | 752 | if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) |
| 753 | || ep->dev->pdev->device != 0x2280) | ||
| 741 | dmacount |= (1 << END_OF_CHAIN); | 754 | dmacount |= (1 << END_OF_CHAIN); |
| 742 | 755 | ||
| 743 | req->valid = valid; | 756 | req->valid = valid; |
| @@ -812,7 +825,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req) | |||
| 812 | 825 | ||
| 813 | /* previous OUT packet might have been short */ | 826 | /* previous OUT packet might have been short */ |
| 814 | if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) | 827 | if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) |
| 815 | & (1 << NAK_OUT_PACKETS)) != 0) { | 828 | & (1 << NAK_OUT_PACKETS)) != 0) { |
| 816 | writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT), | 829 | writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT), |
| 817 | &ep->regs->ep_stat); | 830 | &ep->regs->ep_stat); |
| 818 | 831 | ||
| @@ -1373,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep) | |||
| 1373 | (void) readl (&ep->regs->ep_rsp); | 1386 | (void) readl (&ep->regs->ep_rsp); |
| 1374 | } | 1387 | } |
| 1375 | 1388 | ||
| 1376 | static struct usb_ep_ops net2280_ep_ops = { | 1389 | static const struct usb_ep_ops net2280_ep_ops = { |
| 1377 | .enable = net2280_enable, | 1390 | .enable = net2280_enable, |
| 1378 | .disable = net2280_disable, | 1391 | .disable = net2280_disable, |
| 1379 | 1392 | ||
| @@ -1631,7 +1644,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf) | |||
| 1631 | } | 1644 | } |
| 1632 | 1645 | ||
| 1633 | /* Indexed Registers */ | 1646 | /* Indexed Registers */ |
| 1634 | // none yet | 1647 | // none yet |
| 1635 | 1648 | ||
| 1636 | /* Statistics */ | 1649 | /* Statistics */ |
| 1637 | t = scnprintf (next, size, "\nirqs: "); | 1650 | t = scnprintf (next, size, "\nirqs: "); |
| @@ -1691,11 +1704,11 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf) | |||
| 1691 | ({ char *val; | 1704 | ({ char *val; |
| 1692 | switch (d->bmAttributes & 0x03) { | 1705 | switch (d->bmAttributes & 0x03) { |
| 1693 | case USB_ENDPOINT_XFER_BULK: | 1706 | case USB_ENDPOINT_XFER_BULK: |
| 1694 | val = "bulk"; break; | 1707 | val = "bulk"; break; |
| 1695 | case USB_ENDPOINT_XFER_INT: | 1708 | case USB_ENDPOINT_XFER_INT: |
| 1696 | val = "intr"; break; | 1709 | val = "intr"; break; |
| 1697 | default: | 1710 | default: |
| 1698 | val = "iso"; break; | 1711 | val = "iso"; break; |
| 1699 | }; val; }), | 1712 | }; val; }), |
| 1700 | le16_to_cpu (d->wMaxPacketSize) & 0x1fff, | 1713 | le16_to_cpu (d->wMaxPacketSize) & 0x1fff, |
| 1701 | ep->dma ? "dma" : "pio", ep->fifo_size | 1714 | ep->dma ? "dma" : "pio", ep->fifo_size |
| @@ -1808,8 +1821,8 @@ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); | |||
| 1808 | * net2280_set_fifo_mode - change allocation of fifo buffers | 1821 | * net2280_set_fifo_mode - change allocation of fifo buffers |
| 1809 | * @gadget: access to the net2280 device that will be updated | 1822 | * @gadget: access to the net2280 device that will be updated |
| 1810 | * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); | 1823 | * @mode: 0 for default, four 1kB buffers (ep-a through ep-d); |
| 1811 | * 1 for two 2kB buffers (ep-a and ep-b only); | 1824 | * 1 for two 2kB buffers (ep-a and ep-b only); |
| 1812 | * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). | 1825 | * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c). |
| 1813 | * | 1826 | * |
| 1814 | * returns zero on success, else negative errno. when this succeeds, | 1827 | * returns zero on success, else negative errno. when this succeeds, |
| 1815 | * the contents of gadget->ep_list may have changed. | 1828 | * the contents of gadget->ep_list may have changed. |
| @@ -2241,7 +2254,8 @@ static void handle_ep_small (struct net2280_ep *ep) | |||
| 2241 | req->td->dmacount = 0; | 2254 | req->td->dmacount = 0; |
| 2242 | t = readl (&ep->regs->ep_avail); | 2255 | t = readl (&ep->regs->ep_avail); |
| 2243 | dma_done (ep, req, count, | 2256 | dma_done (ep, req, count, |
| 2244 | (ep->out_overflow || t) ? -EOVERFLOW : 0); | 2257 | (ep->out_overflow || t) |
| 2258 | ? -EOVERFLOW : 0); | ||
| 2245 | } | 2259 | } |
| 2246 | 2260 | ||
| 2247 | /* also flush to prevent erratum 0106 trouble */ | 2261 | /* also flush to prevent erratum 0106 trouble */ |
| @@ -2411,7 +2425,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) | |||
| 2411 | , &ep->regs->ep_stat); | 2425 | , &ep->regs->ep_stat); |
| 2412 | u.raw [0] = readl (&dev->usb->setup0123); | 2426 | u.raw [0] = readl (&dev->usb->setup0123); |
| 2413 | u.raw [1] = readl (&dev->usb->setup4567); | 2427 | u.raw [1] = readl (&dev->usb->setup4567); |
| 2414 | 2428 | ||
| 2415 | cpu_to_le32s (&u.raw [0]); | 2429 | cpu_to_le32s (&u.raw [0]); |
| 2416 | cpu_to_le32s (&u.raw [1]); | 2430 | cpu_to_le32s (&u.raw [1]); |
| 2417 | 2431 | ||
| @@ -2578,14 +2592,16 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) | |||
| 2578 | 2592 | ||
| 2579 | /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. | 2593 | /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. |
| 2580 | * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and | 2594 | * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and |
| 2581 | * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT | 2595 | * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT |
| 2582 | * only indicates a change in the reset state). | 2596 | * only indicates a change in the reset state). |
| 2583 | */ | 2597 | */ |
| 2584 | if (stat & tmp) { | 2598 | if (stat & tmp) { |
| 2585 | writel (tmp, &dev->regs->irqstat1); | 2599 | writel (tmp, &dev->regs->irqstat1); |
| 2586 | if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && | 2600 | if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) |
| 2587 | ((readl (&dev->usb->usbstat) & mask) == 0)) | 2601 | && ((readl (&dev->usb->usbstat) & mask) |
| 2588 | || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0) | 2602 | == 0)) |
| 2603 | || ((readl (&dev->usb->usbctl) | ||
| 2604 | & (1 << VBUS_PIN)) == 0) | ||
| 2589 | ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { | 2605 | ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { |
| 2590 | DEBUG (dev, "disconnect %s\n", | 2606 | DEBUG (dev, "disconnect %s\n", |
| 2591 | dev->driver->driver.name); | 2607 | dev->driver->driver.name); |
| @@ -2852,7 +2868,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2852 | 2868 | ||
| 2853 | /* now all the pci goodies ... */ | 2869 | /* now all the pci goodies ... */ |
| 2854 | if (pci_enable_device (pdev) < 0) { | 2870 | if (pci_enable_device (pdev) < 0) { |
| 2855 | retval = -ENODEV; | 2871 | retval = -ENODEV; |
| 2856 | goto done; | 2872 | goto done; |
| 2857 | } | 2873 | } |
| 2858 | dev->enabled = 1; | 2874 | dev->enabled = 1; |
| @@ -2870,6 +2886,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 2870 | } | 2886 | } |
| 2871 | dev->region = 1; | 2887 | dev->region = 1; |
| 2872 | 2888 | ||
| 2889 | /* FIXME provide firmware download interface to put | ||
| 2890 | * 8051 code into the chip, e.g. to turn on PCI PM. | ||
| 2891 | */ | ||
| 2892 | |||
| 2873 | base = ioremap_nocache (resource, len); | 2893 | base = ioremap_nocache (resource, len); |
| 2874 | if (base == NULL) { | 2894 | if (base == NULL) { |
| 2875 | DEBUG (dev, "can't map memory\n"); | 2895 | DEBUG (dev, "can't map memory\n"); |
| @@ -2984,16 +3004,16 @@ static void net2280_shutdown (struct pci_dev *pdev) | |||
| 2984 | 3004 | ||
| 2985 | /*-------------------------------------------------------------------------*/ | 3005 | /*-------------------------------------------------------------------------*/ |
| 2986 | 3006 | ||
| 2987 | static struct pci_device_id pci_ids [] = { { | 3007 | static const struct pci_device_id pci_ids [] = { { |
| 2988 | .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), | 3008 | .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), |
| 2989 | .class_mask = ~0, | 3009 | .class_mask = ~0, |
| 2990 | .vendor = 0x17cc, | 3010 | .vendor = 0x17cc, |
| 2991 | .device = 0x2280, | 3011 | .device = 0x2280, |
| 2992 | .subvendor = PCI_ANY_ID, | 3012 | .subvendor = PCI_ANY_ID, |
| 2993 | .subdevice = PCI_ANY_ID, | 3013 | .subdevice = PCI_ANY_ID, |
| 2994 | }, { | 3014 | }, { |
| 2995 | .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), | 3015 | .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), |
| 2996 | .class_mask = ~0, | 3016 | .class_mask = ~0, |
| 2997 | .vendor = 0x17cc, | 3017 | .vendor = 0x17cc, |
| 2998 | .device = 0x2282, | 3018 | .device = 0x2282, |
| 2999 | .subvendor = PCI_ANY_ID, | 3019 | .subvendor = PCI_ANY_ID, |
