summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/ehci_pci.c
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2006-05-28 05:27:09 +0000
committeriedowse <iedowse@FreeBSD.org>2006-05-28 05:27:09 +0000
commit225f58e59f70fbec54ed3ef9c9e4190dee7f16c0 (patch)
treeb49c0a89d3a65700c3feb75bdd142516eff11782 /sys/dev/usb/ehci_pci.c
parent9cd9aeea7a6956872906dbb99a9013fe89b5cbc3 (diff)
downloadFreeBSD-src-225f58e59f70fbec54ed3ef9c9e4190dee7f16c0.zip
FreeBSD-src-225f58e59f70fbec54ed3ef9c9e4190dee7f16c0.tar.gz
Use the limited scatter-gather capabilities of ehci, ohci and uhci
host controllers to avoid the need to allocate any multi-page physically contiguous memory blocks. This makes it possible to use USB devices reliably on low-memory systems or when memory is too fragmented for contiguous allocations to succeed. The USB subsystem now uses bus_dmamap_load() directly on the buffers supplied by USB peripheral drivers, so this also avoids having to copy data back and forth before and after transfers. The ehci and ohci controllers support scatter/gather as long as the buffer is contiguous in the virtual address space. For uhci the hardware cannot handle a physical address discontinuity within a USB packet, so it is necessary to copy small memory fragments at times.
Diffstat (limited to 'sys/dev/usb/ehci_pci.c')
-rw-r--r--sys/dev/usb/ehci_pci.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c
index 204fad0..6ed26140 100644
--- a/sys/dev/usb/ehci_pci.c
+++ b/sys/dev/usb/ehci_pci.c
@@ -58,6 +58,8 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/bus.h>
#include <sys/queue.h>
#include <sys/lockmgr.h>
@@ -420,6 +422,30 @@ ehci_pci_attach(device_t self)
}
sc->sc_ncomp = ncomp;
+ /* Allocate a parent dma tag for DMA maps */
+ err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE_32BIT,
+ USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
+ &sc->sc_bus.parent_dmatag);
+ if (err) {
+ device_printf(self, "Could not allocate parent DMA tag (%d)\n",
+ err);
+ ehci_pci_detach(self);
+ return ENXIO;
+ }
+
+ /* Allocate a dma tag for transfer buffers */
+ err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
+ busdma_lock_mutex, &Giant, &sc->sc_bus.buffer_dmatag);
+ if (err) {
+ device_printf(self, "Could not allocate buffer DMA tag (%d)\n",
+ err);
+ ehci_pci_detach(self);
+ return ENXIO;
+ }
+
ehci_pci_takecontroller(self);
err = ehci_init(sc);
if (!err) {
@@ -450,6 +476,10 @@ ehci_pci_detach(device_t self)
*/
if (sc->iot && sc->ioh)
bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0);
+ if (sc->sc_bus.parent_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_bus.parent_dmatag);
+ if (sc->sc_bus.buffer_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag);
if (sc->irq_res && sc->ih) {
int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
OpenPOWER on IntegriCloud