diff options
| author | David Brownell <david-b@pacbell.net> | 2002-12-26 17:39:46 -0800 |
|---|---|---|
| committer | Vojtech Pavlik <vojtech@suse.cz> | 2002-12-26 17:39:46 -0800 |
| commit | 61426cf2ce361f3b06fbe855f5cc56df2e24edd2 (patch) | |
| tree | 450a466fef77fb88c85ee0622ae5aa6c248499d5 | |
| parent | 7013dfc35f2f38a057471010fd6853f041a2685f (diff) | |
[PATCH] usbcore dma updates (and doc)
Attached is a patch leveraging some of the new generic dma stuff:
- Replaces dma mapping calls in usbcore with generic equivalents.
This is a minor code shrink (which we'd hoped could happen).
- Pass dma mask along, so net drivers can notice it'd be good to
set NETIF_F_HIGHDMA; or scsi ones can set highmem_io. (Some
Intel EHCI setups are able to support this kind of DMA.)
- Updates one net driver (usbnet) to set NETIF_F_HIGHDMA when
appropriate, mostly as an example (since I can't test this).
- Provides Documentation/usb/dma.txt, describing current APIs.
(Unchanged by this patch, except dma mask visibility.)
- Converted another info() to dev_info(), and likewise a couple
dbg() to dev_dbg() conversions in the modified routine.
The number of FIXMEs was conserved: the generic API doesn't yet
fix the error reporting bugs in the PCI-specific mapping API.
| -rw-r--r-- | Documentation/usb/dma.txt | 104 | ||||
| -rw-r--r-- | drivers/usb/core/buffer.c | 100 | ||||
| -rw-r--r-- | drivers/usb/core/hcd-pci.c | 3 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.c | 20 | ||||
| -rw-r--r-- | drivers/usb/core/hcd.h | 37 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 105 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-hcd.c | 7 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-sa1111.c | 3 | ||||
| -rw-r--r-- | drivers/usb/net/usbnet.c | 11 | ||||
| -rw-r--r-- | include/linux/usb.h | 16 |
10 files changed, 184 insertions, 222 deletions
diff --git a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt new file mode 100644 index 000000000000..fae537186570 --- /dev/null +++ b/Documentation/usb/dma.txt @@ -0,0 +1,104 @@ +In Linux 2.5 kernels (and later), USB device drivers have additional control +over how DMA may be used to perform I/O operations. The APIs are detailed +in the kernel usb programming guide (kerneldoc, from the source code). + + +API OVERVIEW + +The big picture is that USB drivers can continue to ignore most DMA issues, +though they still must provide DMA-ready buffers (see DMA-mapping.txt). +That's how they've worked through the 2.4 (and earlier) kernels. + +OR: they can now be DMA-aware. + +- New calls enable DMA-aware drivers, letting them allocate dma buffers and + manage dma mappings for existing dma-ready buffers (see below). + +- URBs have an additional "transfer_dma" field, as well as a transfer_flags + bit saying if it's valid. (Control requests also needed "setup_dma".) + +- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do it + first and set URB_NO_DMA_MAP. HCDs don't manage dma mappings for urbs. + +- There's a new "generic DMA API", parts of which are usable by USB device + drivers. Never use dma_set_mask() on any USB interface or device; that + would potentially break all devices sharing that bus. + + +ELIMINATING COPIES + +It's good to avoid making CPUs copy data needlessly. The costs can add up, +and effects like cache-trashing can impose subtle penalties. + +- When you're allocating a buffer for DMA purposes anyway, use the buffer + primitives. Think of them as kmalloc and kfree that give you the right + kind of addresses to store in urb->transfer_buffer and urb->transfer_dma, + while guaranteeing that hidden copies through DMA "bounce" buffers won't + slow things down. You'd also set URB_NO_DMA_MAP in urb->transfer_flags: + + void *usb_buffer_alloc (struct usb_device *dev, size_t size, + int mem_flags, dma_addr_t *dma); + + void usb_buffer_free (struct usb_device *dev, size_t size, + void *addr, dma_addr_t dma); + + The memory buffer returned is "dma-coherent"; sometimes you might need to + force a consistent memory access ordering by using memory barriers. It's + not using a streaming DMA mapping, so it's good for small transfers on + systems where the I/O would otherwise tie up an IOMMU mapping. + + Asking for 1/Nth of a page (as well as asking for N pages) is reasonably + space-efficient. + +- Devices on some EHCI controllers could handle DMA to/from high memory. + Driver probe() routines can notice this using a generic DMA call, then + tell higher level code (network, scsi, etc) about it like this: + + if (dma_supported (&intf->dev, 0xffffffffffffffffULL)) + net->features |= NETIF_F_HIGHDMA; + + That can eliminate dma bounce buffering of requests that originate (or + terminate) in high memory, in cases where the buffers aren't allocated + with usb_buffer_alloc() but instead are dma-mapped. + + +WORKING WITH EXISTING BUFFERS + +Existing buffers aren't usable for DMA without first being mapped into the +DMA address space of the device. + +- When you're using scatterlists, you can map everything at once. On some + systems, this kicks in an IOMMU and turns the scatterlists into single + DMA transactions: + + int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int nents); + + void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); + + void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, + struct scatterlist *sg, int n_hw_ents); + + It's probably easier to use the new usb_sg_*() calls, which do the DMA + mapping and apply other tweaks to make scatterlist i/o be fast. + +- Some drivers may prefer to work with the model that they're mapping large + buffers, synchronizing their safe re-use. (If there's no re-use, then let + usbcore do the map/unmap.) Large periodic transfers make good examples + here, since it's cheaper to just synchronize the buffer than to unmap it + each time an urb completes and then re-map it on during resubmission. + + These calls all work with initialized urbs: urb->dev, urb->pipe, + urb->transfer_buffer, and urb->transfer_buffer_length must all be + valid when these calls are used: + + struct urb *usb_buffer_map (struct urb *urb); + + void usb_buffer_dmasync (struct urb *urb); + + void usb_buffer_unmap (struct urb *urb); + + The calls manage urb->transfer_dma for you, and set URB_NO_DMA_MAP so that + usbcore won't map or unmap the buffer. + diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 4f4211af98b6..6e4392596750 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -24,11 +24,14 @@ /* - * DMA-Consistent Buffers + * DMA-Coherent Buffers */ /* FIXME tune these based on pool statistics ... */ static const size_t pool_max [HCD_BUFFER_POOLS] = { + /* platforms without dma-friendly caches might need to + * prevent cacheline sharing... + */ 32, 128, 512, @@ -133,98 +136,3 @@ void hcd_buffer_free ( } pci_free_consistent (hcd->pdev, size, addr, dma); } - - -/* - * DMA-Mappings for arbitrary memory buffers - */ - -int hcd_buffer_map ( - struct usb_bus *bus, - void *addr, - dma_addr_t *dma, - size_t size, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - // FIXME pci_map_single() has no standard failure mode! - *dma = pci_map_single (hcd->pdev, addr, size, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); - return 0; -} - -void hcd_buffer_dmasync ( - struct usb_bus *bus, - dma_addr_t dma, - size_t size, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - pci_dma_sync_single (hcd->pdev, dma, size, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -} - -void hcd_buffer_unmap ( - struct usb_bus *bus, - dma_addr_t dma, - size_t size, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - pci_unmap_single (hcd->pdev, dma, size, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -} - -int hcd_buffer_map_sg ( - struct usb_bus *bus, - struct scatterlist *sg, - int *n_hw_ents, - int nents, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - // FIXME pci_map_sg() has no standard failure mode! - *n_hw_ents = pci_map_sg(hcd->pdev, sg, nents, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); - return 0; -} - -void hcd_buffer_sync_sg ( - struct usb_bus *bus, - struct scatterlist *sg, - int n_hw_ents, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - pci_dma_sync_sg(hcd->pdev, sg, n_hw_ents, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -} - -void hcd_buffer_unmap_sg ( - struct usb_bus *bus, - struct scatterlist *sg, - int n_hw_ents, - int direction -) { - struct usb_hcd *hcd = bus->hcpriv; - - pci_unmap_sg(hcd->pdev, sg, n_hw_ents, - (direction == USB_DIR_IN) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -} diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index e66aaac9fa78..9ca856cd6a42 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -138,7 +138,8 @@ clean_2: hcd->pdev = dev; hcd->self.bus_name = dev->slot_name; hcd->product_desc = dev->dev.name; - hcd->controller = &dev->dev; + hcd->self.controller = &dev->dev; + hcd->controller = hcd->self.controller; if ((retval = hcd_buffer_create (hcd)) != 0) { clean_3: diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 74a3993826fd..624beac700b4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1031,19 +1031,19 @@ static int hcd_submit_urb (struct urb *urb, int mem_flags) /* lower level hcd code should use *_dma exclusively */ if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = pci_map_single ( - hcd->pdev, + urb->setup_dma = dma_map_single ( + hcd->controller, urb->setup_packet, sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); if (urb->transfer_buffer_length != 0) - urb->transfer_dma = pci_map_single ( - hcd->pdev, + urb->transfer_dma = dma_map_single ( + hcd->controller, urb->transfer_buffer, urb->transfer_buffer_length, usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); + ? DMA_FROM_DEVICE + : DMA_TO_DEVICE); } status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); @@ -1265,12 +1265,6 @@ struct usb_operations usb_hcd_operations = { .deallocate = hcd_free_dev, .buffer_alloc = hcd_buffer_alloc, .buffer_free = hcd_buffer_free, - .buffer_map = hcd_buffer_map, - .buffer_dmasync = hcd_buffer_dmasync, - .buffer_unmap = hcd_buffer_unmap, - .buffer_map_sg = hcd_buffer_map_sg, - .buffer_dmasync_sg = hcd_buffer_sync_sg, - .buffer_unmap_sg = hcd_buffer_unmap_sg, }; EXPORT_SYMBOL (usb_hcd_operations); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 0db63cf30e7a..99cb0f4b2c84 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -145,26 +145,6 @@ struct usb_operations { dma_addr_t *dma); void (*buffer_free)(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); - - int (*buffer_map) (struct usb_bus *bus, - void *addr, dma_addr_t *dma, - size_t size, int direction); - void (*buffer_dmasync) (struct usb_bus *bus, - dma_addr_t dma, - size_t size, int direction); - void (*buffer_unmap) (struct usb_bus *bus, - dma_addr_t dma, - size_t size, int direction); - - int (*buffer_map_sg) (struct usb_bus *bus, - struct scatterlist *sg, int *n_hw_ents, - int nents, int direction); - void (*buffer_dmasync_sg) (struct usb_bus *bus, - struct scatterlist *sg, - int n_hw_ents, int direction); - void (*buffer_unmap_sg) (struct usb_bus *bus, - struct scatterlist *sg, - int n_hw_ents, int direction); }; /* each driver provides one of these, and hardware init support */ @@ -248,23 +228,6 @@ void *hcd_buffer_alloc (struct usb_bus *bus, size_t size, void hcd_buffer_free (struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma); -int hcd_buffer_map (struct usb_bus *bus, - void *addr, dma_addr_t *dma, - size_t size, int direction); -void hcd_buffer_dmasync (struct usb_bus *bus, - dma_addr_t dma, - size_t size, int direction); -void hcd_buffer_unmap (struct usb_bus *bus, - dma_addr_t dma, - size_t size, int direction); -int hcd_buffer_map_sg (struct usb_bus *bus, struct scatterlist *sg, - int *n_hw_ents, int nents, int direction); -void hcd_buffer_sync_sg (struct usb_bus *bus, struct scatterlist *sg, - int n_hw_ents, int direction); - -void hcd_buffer_unmap_sg (struct usb_bus *bus, struct scatterlist *sg, - int n_hw_ents, int direction); - /* generic bus glue, needed for host controllers that don't use PCI */ extern struct usb_operations usb_hcd_operations; extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 1325fc9b8a09..df15296da8a6 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -41,6 +41,11 @@ #endif #include <linux/usb.h> +#include <asm/io.h> +#include <asm/scatterlist.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> + #include "hcd.h" #include "usb.h" @@ -803,7 +808,7 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; - info("USB disconnect on device %d", dev->devnum); + dev_info (dev->dev, "USB disconnect, address %d\n", dev->devnum); /* Free up all the children before we remove this device */ for (i = 0; i < USB_MAXCHILDREN; i++) { @@ -812,7 +817,7 @@ void usb_disconnect(struct usb_device **pdev) usb_disconnect(child); } - dbg ("unregistering interfaces on device %d", dev->devnum); + dev_dbg (dev->dev, "unregistering interfaces\n"); if (dev->actconfig) { for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { struct usb_interface *interface = &dev->actconfig->interface[i]; @@ -822,7 +827,7 @@ void usb_disconnect(struct usb_device **pdev) } } - dbg ("unregistering the device %d", dev->devnum); + dev_dbg (dev->dev, "unregistering device\n"); /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, dev->bus->devmap.devicemap); @@ -980,6 +985,9 @@ int usb_new_device(struct usb_device *dev, struct device *parent) sprintf (&dev->dev.bus_id[0], "%d-%s", dev->bus->busnum, dev->devpath); + /* dma masks come from the controller; readonly, except to hcd */ + dev->dev.dma_mask = parent->dma_mask; + /* USB device state == default ... it's not usable yet */ /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... @@ -1104,6 +1112,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent) interface->dev.parent = &dev->dev; interface->dev.driver = NULL; interface->dev.bus = &usb_bus_type; + interface->dev.dma_mask = parent->dma_mask; sprintf (&interface->dev.bus_id[0], "%d-%s:%d", dev->bus->busnum, dev->devpath, desc->bInterfaceNumber); @@ -1206,24 +1215,21 @@ void usb_buffer_free ( struct urb *usb_buffer_map (struct urb *urb) { struct usb_bus *bus; - struct usb_operations *op; + struct device *controller; if (!urb || usb_pipecontrol (urb->pipe) || !urb->dev || !(bus = urb->dev->bus) - || !(op = bus->op) - || !op->buffer_map) + || !(controller = bus->controller)) return 0; - if (op->buffer_map (bus, - urb->transfer_buffer, - &urb->transfer_dma, - urb->transfer_buffer_length, + urb->transfer_dma = dma_map_single (controller, + urb->transfer_buffer, urb->transfer_buffer_length, usb_pipein (urb->pipe) - ? USB_DIR_IN - : USB_DIR_OUT)) - return 0; + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + // FIXME generic api broken like pci, can't report errors + // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; urb->transfer_flags |= URB_NO_DMA_MAP; return urb; } @@ -1235,22 +1241,19 @@ struct urb *usb_buffer_map (struct urb *urb) void usb_buffer_dmasync (struct urb *urb) { struct usb_bus *bus; - struct usb_operations *op; + struct device *controller; if (!urb || !(urb->transfer_flags & URB_NO_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) - || !(op = bus->op) - || !op->buffer_dmasync) + || !(controller = bus->controller)) return; - op->buffer_dmasync (bus, - urb->transfer_dma, - urb->transfer_buffer_length, + dma_sync_single (controller, + urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) - ? USB_DIR_IN - : USB_DIR_OUT); + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /** @@ -1262,23 +1265,21 @@ void usb_buffer_dmasync (struct urb *urb) void usb_buffer_unmap (struct urb *urb) { struct usb_bus *bus; - struct usb_operations *op; + struct device *controller; if (!urb || !(urb->transfer_flags & URB_NO_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) - || !(op = bus->op) - || !op->buffer_unmap) + || !(controller = bus->controller)) return; - op->buffer_unmap (bus, - urb->transfer_dma, - urb->transfer_buffer_length, + dma_unmap_single (controller, + urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) - ? USB_DIR_IN - : USB_DIR_OUT); + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } + /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped @@ -1297,6 +1298,7 @@ void usb_buffer_unmap (struct urb *urb) * to complete before starting the next I/O. This is particularly easy * to do with scatterlists. Just allocate and submit one URB for each DMA * mapping entry returned, stopping on the first error or when all succeed. + * Better yet, use the usb_sg_*() calls, which do that (and more) for you. * * This call would normally be used when translating scatterlist requests, * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it @@ -1308,26 +1310,17 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int nents) { struct usb_bus *bus; - struct usb_operations *op; - int n_hw_ents; + struct device *controller; if (!dev || usb_pipecontrol (pipe) || !(bus = dev->bus) - || !(op = bus->op) - || !op->buffer_map_sg) - return -1; - - if (op->buffer_map_sg (bus, - sg, - &n_hw_ents, - nents, - usb_pipein (pipe) - ? USB_DIR_IN - : USB_DIR_OUT)) + || !(controller = bus->controller)) return -1; - return n_hw_ents; + // FIXME generic api broken like pci, can't report errors + return dma_map_sg (controller, sg, nents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /** @@ -1344,20 +1337,15 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; - struct usb_operations *op; + struct device *controller; if (!dev || !(bus = dev->bus) - || !(op = bus->op) - || !op->buffer_dmasync_sg) + || !(controller = bus->controller)) return; - op->buffer_dmasync_sg (bus, - sg, - n_hw_ents, - usb_pipein (pipe) - ? USB_DIR_IN - : USB_DIR_OUT); + dma_sync_sg (controller, sg, n_hw_ents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /** @@ -1373,20 +1361,15 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int n_hw_ents) { struct usb_bus *bus; - struct usb_operations *op; + struct device *controller; if (!dev || !(bus = dev->bus) - || !(op = bus->op) - || !op->buffer_unmap_sg) + || !(controller = bus->controller)) return; - op->buffer_unmap_sg (bus, - sg, - n_hw_ents, - usb_pipein (pipe) - ? USB_DIR_IN - : USB_DIR_OUT); + dma_unmap_sg (controller, sg, n_hw_ents, + usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 48d9b806fcb2..239e398861df 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -405,9 +405,10 @@ static int ehci_start (struct usb_hcd *hcd) * streaming mappings for I/O buffers, like pci_map_single(), * can return segments above 4GB, if the device allows. * - * NOTE: layered drivers can't yet tell when we enable that, - * so they can't pass this info along (like NETIF_F_HIGHDMA) - * (or like Scsi_Host.highmem_io) ... usb_bus.flags? + * NOTE: the dma mask is visible through dma_supported(), so + * drivers can pass this info along ... like NETIF_F_HIGHDMA, + * Scsi_Host.highmem_io, and so forth. It's readonly to all + * host side drivers though. */ if (HCC_64BIT_ADDR (hcc_params)) { writel (0, &ehci->regs->segment); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index d03fce1c7da5..11d4fed34233 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -176,7 +176,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, hcd->irq = dev->irq[1]; hcd->regs = dev->mapbase; hcd->pdev = SA1111_FAKE_PCIDEV; - hcd->controller = &dev->dev; + hcd->self.controller = &dev->dev; + hcd->controller = hcd->self.controller; retval = hcd_buffer_create (hcd); if (retval != 0) { diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 17eb48408556..bf8ca2f5daf3 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -146,6 +146,11 @@ #endif #include <linux/usb.h> +#include <asm/io.h> +#include <asm/scatterlist.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> + /* minidrivers _could_ be individually configured */ #define CONFIG_USB_AN2720 @@ -2169,9 +2174,13 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) memcpy (net->dev_addr, node_id, sizeof node_id); // point-to-point link ... we always use Ethernet headers - // supports win32 interop and the bridge driver. + // supports win32 interop (some devices) and the bridge driver. ether_setup (net); + // possible with some EHCI controllers + if (dma_supported (&udev->dev, 0xffffffffffffffffULL)) + net->features |= NETIF_F_HIGHDMA; + net->change_mtu = usbnet_change_mtu; net->get_stats = usbnet_get_stats; net->hard_start_xmit = usbnet_start_xmit; diff --git a/include/linux/usb.h b/include/linux/usb.h index 88557d5957a7..b1d92b8c585f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -28,14 +28,6 @@ static __inline__ void wait_ms(unsigned int ms) mdelay(ms); } -/* - * USB device number allocation bitmap. There's one bitmap - * per USB tree. - */ -struct usb_devmap { - unsigned long devicemap[128 / (8*sizeof(unsigned long))]; -}; - struct usb_device; /*-------------------------------------------------------------------------*/ @@ -159,10 +151,16 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, struct usb_operations; +/* USB device number allocation bitmap */ +struct usb_devmap { + unsigned long devicemap[128 / (8*sizeof(unsigned long))]; +}; + /* - * Allocated per bus we have + * Allocated per bus (tree of devices) we have: */ struct usb_bus { + struct device *controller; /* host/master side hardware */ int busnum; /* Bus number (in order of reg) */ char *bus_name; /* stable id (PCI slot_name etc) */ |
