Date: Sat, 24 Nov 2007 18:19:03 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 129461 for review Message-ID: <200711241819.lAOIJ3va061137@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=129461 Change 129461 by hselasky@hselasky_laptop001 on 2007/11/24 18:18:59 This commit adds functions and callbacks required to support loading of virtual buffers directly into DMA. This feature is not yet fully functional. What is left is to add allocation of RX and TX BUS-DMA maps when setting up an USB transfer through "usbd_transfer_setup()". New functions "usbd_bus_mem_setup" and "usbd_bus_mem_unsetup" which factor out code. New USB API function "usbd_transfer_drain". See README for a detailed description. Affected files ... .. //depot/projects/usb/src/sys/arm/at91/ohci_atmelarm.c#6 edit .. //depot/projects/usb/src/sys/dev/usb/README#20 edit .. //depot/projects/usb/src/sys/dev/usb/ehci.c#48 edit .. //depot/projects/usb/src/sys/dev/usb/ehci.h#21 edit .. //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#24 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.c#38 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.h#17 edit .. //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#24 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.c#40 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.h#17 edit .. //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#23 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#49 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#56 edit .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#45 edit Differences ... ==== //depot/projects/usb/src/sys/arm/at91/ohci_atmelarm.c#6 (text) ==== @@ -71,13 +71,10 @@ if (sc == NULL) { return ENXIO; } - sc->sc_ohci.sc_hw_ptr = - usbd_mem_alloc(device_get_dma_tag(dev), - &(sc->sc_ohci.sc_hw_page), sizeof(*(sc->sc_ohci.sc_hw_ptr)), - LOG2(OHCI_HCCA_ALIGN)); - - if (sc->sc_ohci.sc_hw_ptr == NULL) { - return ENXIO; + if (usbd_bus_mem_setup(&(sc->sc_ohci.sc_bus), device_get_dma_tag(dev), + sizeof(*(sc->sc_ohci.sc_bus.hw_ptr.ohci)), 32, LOG2(OHCI_HCCA_ALIGN))) { + device_printf(dev, "Could not allocate DMA-able memory\n"); + return ENOMEM; } sc->iclk = at91_pmc_clock_ref("ohci_clk"); sc->fclk = at91_pmc_clock_ref("uhpck"); @@ -87,12 +84,6 @@ sc->sc_ohci.sc_dev = dev; - sc->sc_ohci.sc_bus.dma_tag = usbd_dma_tag_alloc(device_get_dma_tag(dev), - USB_PAGE_SIZE, USB_PAGE_SIZE); - - if (sc->sc_ohci.sc_bus.dma_tag == NULL) { - goto error; - } rid = MEM_RID; sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -204,13 +195,10 @@ sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_res = NULL; } - if (sc->sc_ohci.sc_bus.dma_tag) { - usbd_dma_tag_free(sc->sc_ohci.sc_bus.dma_tag); - } + usbd_bus_mem_unsetup(&(sc->sc_ohci.sc_bus)); + mtx_destroy(&(sc->sc_ohci.sc_bus.mtx)); - usbd_mem_free(&(sc->sc_ohci.sc_hw_page)); - return 0; } ==== //depot/projects/usb/src/sys/dev/usb/README#20 (text+ko) ==== @@ -15,22 +15,33 @@ | active, release all DMA | | memory and might sleep! | | | -| "usbd_transfer_start" - This function will start a USB | +| "usbd_transfer_start" - This function will start an USB | | transfer, if not already started.| -| This function is always non- | -| blocking, except when the USB | -| transfer is SYNCHRONOUS. ** | +| This function is always | +| non-blocking. ** | | | -| "usbd_transfer_stop" - This function will stop a USB | +| "usbd_transfer_stop" - This function will stop an USB | | transfer, if not already stopped.| | The callback function will be | | called before this function | | returns. This function is always | | non-blocking. ** | | | +| "usbd_transfer_drain" - This function will stop an USB | +| transfer, if not already stopped | +| and wait for any additional | +| DMA load operations to complete. | +| Buffers that are loaded into DMA | +| using "usbd_set_frame_data" can | +| safely be freed after that | +| this function has returned. This | +| function can block the caller. | +| | | ** These functions must be called with the private driver's | | lock locked. | | | +| NOTE: These USB API functions are NULL safe, with regard | +| to the USB transfer structure pointer. | +--------------------------------------------------------------+ Reference: /sys/dev/usb/usb_transfer.c @@ -245,13 +256,13 @@ to set initial flags an USB transfer. Valid flags are: force_short_xfer - This flag forces the last USB packet sent to be short. A short - packet has a length of less than "xfer->max_packet_size", which - derives from "wMaxPacketSize". + This flag forces the last transmitted USB packet to be short. + A short packet has a length of less than "xfer->max_packet_size", + which derives from "wMaxPacketSize". short_xfer_ok - This flag allows the transfer length, "xfer->actlen" to be - less than "xfer->sumlen" upon completion of a transfer. + This flag allows the received transfer length, "xfer->actlen" + to be less than "xfer->sumlen" upon completion of a transfer. use_polling This flag can be used with any callback and will cause the ==== //depot/projects/usb/src/sys/dev/usb/ehci.c#48 (text+ko) ==== @@ -3848,6 +3848,8 @@ xfer->qh_start = last_obj; + xfer->flags_int.bdma_enable = 1;/* enable BUS-DMA support */ + return; } ==== //depot/projects/usb/src/sys/dev/usb/ehci.h#21 (text+ko) ==== @@ -433,8 +433,10 @@ uint8_t temp[128]; }; +#define sc_hw_page sc_bus.hw_page +#define sc_hw_ptr sc_bus.hw_ptr.ehci + typedef struct ehci_softc { - struct usbd_page sc_hw_page; struct usbd_bus sc_bus; /* base device */ struct usbd_config_td sc_config_td; struct usb_callout sc_tmo_pcd; @@ -443,7 +445,6 @@ struct usbd_std_root_transfer sc_root_ctrl; struct usbd_std_root_transfer sc_root_intr; - struct ehci_hw_softc *sc_hw_ptr; struct resource *sc_io_res; struct resource *sc_irq_res; struct ehci_qh *sc_async_p_last; ==== //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#24 (text+ko) ==== @@ -215,16 +215,10 @@ device_printf(self, "Could not allocate sc\n"); return ENXIO; } - sc->sc_hw_ptr = - usbd_mem_alloc(device_get_dma_tag(self), - &(sc->sc_hw_page), sizeof(*(sc->sc_hw_ptr)), - LOG2(EHCI_FRAMELIST_ALIGN)); - - if (sc->sc_hw_ptr == NULL) { - device_printf(self, "Could not allocate DMA-able " - "memory, %d bytes!\n", - (int32_t)sizeof(*(sc->sc_hw_ptr))); - return ENXIO; + if (usbd_bus_mem_setup(&(sc->sc_bus), device_get_dma_tag(self), + sizeof(*(sc->sc_bus.hw_ptr.ehci)), 32, LOG2(EHCI_FRAMELIST_ALIGN))) { + device_printf(self, "Could not allocate DMA-able memory\n"); + return ENOMEM; } mtx_init(&sc->sc_bus.mtx, "usb lock", NULL, MTX_DEF | MTX_RECURSE); @@ -248,12 +242,6 @@ break; } - sc->sc_bus.dma_tag = usbd_dma_tag_alloc(device_get_dma_tag(self), - USB_PAGE_SIZE, USB_PAGE_SIZE); - if (sc->sc_bus.dma_tag == NULL) { - device_printf(self, "Could not allocate DMA tag\n"); - goto error; - } rid = PCI_CBMEM; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -408,15 +396,12 @@ sc->sc_io_res); sc->sc_io_res = NULL; } - if (sc->sc_bus.dma_tag) { - usbd_dma_tag_free(sc->sc_bus.dma_tag); - } usbd_config_td_unsetup(&(sc->sc_config_td)); + usbd_bus_mem_unsetup(&(sc->sc_bus)); + mtx_destroy(&sc->sc_bus.mtx); - usbd_mem_free(&(sc->sc_hw_page)); - return 0; } ==== //depot/projects/usb/src/sys/dev/usb/ohci.c#38 (text+ko) ==== @@ -2796,6 +2796,8 @@ xfer->qh_start = last_obj; + xfer->flags_int.bdma_enable = 1;/* enable BUS-DMA support */ + return; } ==== //depot/projects/usb/src/sys/dev/usb/ohci.h#17 (text+ko) ==== @@ -307,8 +307,10 @@ uint8_t temp[128]; }; +#define sc_hw_page sc_bus.hw_page +#define sc_hw_ptr sc_bus.hw_ptr.ohci + typedef struct ohci_softc { - struct usbd_page sc_hw_page; struct usbd_bus sc_bus; /* base device */ struct usbd_config_td sc_config_td; struct usb_callout sc_tmo_rhsc; @@ -317,7 +319,6 @@ struct usbd_std_root_transfer sc_root_ctrl; struct usbd_std_root_transfer sc_root_intr; - struct ohci_hw_softc *sc_hw_ptr; struct resource *sc_io_res; struct resource *sc_irq_res; struct ohci_ed *sc_ctrl_p_last; ==== //depot/projects/usb/src/sys/dev/usb/ohci_pci.c#24 (text+ko) ==== @@ -196,16 +196,10 @@ device_printf(self, "Could not allocate sc\n"); return ENXIO; } - sc->sc_hw_ptr = - usbd_mem_alloc(device_get_dma_tag(self), - &(sc->sc_hw_page), sizeof(*(sc->sc_hw_ptr)), - LOG2(OHCI_HCCA_ALIGN)); - - if (sc->sc_hw_ptr == NULL) { - device_printf(self, "Could not allocate DMA-able " - "memory, %d bytes!\n", - (int32_t)sizeof(*(sc->sc_hw_ptr))); - return ENXIO; + if (usbd_bus_mem_setup(&(sc->sc_bus), device_get_dma_tag(self), + sizeof(*(sc->sc_bus.hw_ptr.ohci)), 32, LOG2(OHCI_HCCA_ALIGN))) { + device_printf(self, "Could not allocate DMA-able memory\n"); + return ENOMEM; } mtx_init(&sc->sc_bus.mtx, "usb lock", NULL, MTX_DEF | MTX_RECURSE); @@ -214,12 +208,6 @@ pci_enable_busmaster(self); - sc->sc_bus.dma_tag = usbd_dma_tag_alloc(device_get_dma_tag(self), - USB_PAGE_SIZE, USB_PAGE_SIZE); - if (sc->sc_bus.dma_tag == NULL) { - device_printf(self, "Could not allocate DMA tag\n"); - goto error; - } rid = PCI_CBMEM; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -365,15 +353,12 @@ sc->sc_io_res); sc->sc_io_res = NULL; } - if (sc->sc_bus.dma_tag) { - usbd_dma_tag_free(sc->sc_bus.dma_tag); - } usbd_config_td_unsetup(&(sc->sc_config_td)); + usbd_bus_mem_unsetup(&(sc->sc_bus)); + mtx_destroy(&sc->sc_bus.mtx); - usbd_mem_free(&(sc->sc_hw_page)); - return 0; } ==== //depot/projects/usb/src/sys/dev/usb/uhci.c#40 (text+ko) ==== @@ -3239,6 +3239,8 @@ xfer->qh_start = last_obj; + xfer->flags_int.bdma_enable = 1;/* enable BUS-DMA support */ + return; } ==== //depot/projects/usb/src/sys/dev/usb/uhci.h#17 (text+ko) ==== @@ -261,8 +261,10 @@ }; +#define sc_hw_page sc_bus.hw_page +#define sc_hw_ptr sc_bus.hw_ptr.uhci + typedef struct uhci_softc { - struct usbd_page sc_hw_page; struct usbd_bus sc_bus; /* base device */ struct usbd_config_td sc_config_td; LIST_HEAD(, usbd_xfer) sc_interrupt_list_head; @@ -270,7 +272,6 @@ struct usbd_std_root_transfer sc_root_ctrl; struct usbd_std_root_transfer sc_root_intr; - struct uhci_hw_softc *sc_hw_ptr; struct uhci_td *sc_isoc_p_last[UHCI_VFRAMELIST_COUNT]; /* pointer to last TD * for isochronous */ struct uhci_qh *sc_intr_p_last[UHCI_IFRAMELIST_COUNT]; /* pointer to last QH ==== //depot/projects/usb/src/sys/dev/usb/uhci_pci.c#23 (text+ko) ==== @@ -212,16 +212,10 @@ device_printf(self, "Could not allocate sc\n"); return ENXIO; } - sc->sc_hw_ptr = - usbd_mem_alloc(device_get_dma_tag(self), - &(sc->sc_hw_page), sizeof(*(sc->sc_hw_ptr)), - LOG2(UHCI_FRAMELIST_ALIGN)); - - if (sc->sc_hw_ptr == NULL) { - device_printf(self, "Could not allocate DMA-able " - "memory, %d bytes!\n", - (int32_t)sizeof(*(sc->sc_hw_ptr))); - return ENXIO; + if (usbd_bus_mem_setup(&(sc->sc_bus), device_get_dma_tag(self), + sizeof(*(sc->sc_bus.hw_ptr.uhci)), 32, LOG2(UHCI_FRAMELIST_ALIGN))) { + device_printf(self, "Could not allocate DMA-able memory\n"); + return ENOMEM; } mtx_init(&sc->sc_bus.mtx, "usb lock", NULL, MTX_DEF | MTX_RECURSE); @@ -230,12 +224,6 @@ pci_enable_busmaster(self); - sc->sc_bus.dma_tag = usbd_dma_tag_alloc(device_get_dma_tag(self), - USB_PAGE_SIZE, USB_PAGE_SIZE); - if (sc->sc_bus.dma_tag == NULL) { - device_printf(self, "Could not allocate DMA tag\n"); - goto error; - } rid = PCI_UHCI_BASE_REG; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_IOPORT, &rid, RF_ACTIVE); @@ -391,15 +379,12 @@ sc->sc_io_res); sc->sc_io_res = NULL; } - if (sc->sc_bus.dma_tag) { - usbd_dma_tag_free(sc->sc_bus.dma_tag); - } usbd_config_td_unsetup(&(sc->sc_config_td)); + usbd_bus_mem_unsetup(&(sc->sc_bus)); + mtx_destroy(&sc->sc_bus.mtx); - usbd_mem_free(&(sc->sc_hw_page)); - return 0; } ==== //depot/projects/usb/src/sys/dev/usb/usb_subr.c#49 (text+ko) ==== @@ -2088,7 +2088,7 @@ uint32_t alignment = (1 << align_power); void *ptr; - tag = usbd_dma_tag_alloc(parent, size, alignment); + tag = usbd_dma_tag_alloc(parent, size, alignment, size); if (tag == NULL) { return NULL; @@ -2140,8 +2140,8 @@ * usbd_dma_tag_alloc - allocate a bus-DMA tag *------------------------------------------------------------------------------*/ bus_dma_tag_t -usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t size, - uint32_t alignment) +usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t seg_size, + uint32_t alignment, uint32_t max_size) { bus_dma_tag_t tag; @@ -2153,9 +2153,9 @@ /* highaddr */ BUS_SPACE_MAXADDR, /* filter */ NULL, /* filterarg */ NULL, - /* maxsize */ size, + /* maxsize */ max_size, /* nsegments */ 1, - /* maxsegsz */ size, + /* maxsegsz */ seg_size, /* flags */ 0, /* lock */ NULL, /* */ NULL, @@ -2268,13 +2268,124 @@ return; } +/*---------------------------------------------------------------------------* + * usbd_dma_load_mem_callback - internal callback + *---------------------------------------------------------------------------*/ +static void +usbd_dma_load_mem_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + struct usbd_page_cache *pc; + struct usbd_xfer *xfer; + struct usbd_page *pg; + uint32_t rem; + + pc = arg; + xfer = pc->p_xfer; + + /* XXX sometimes recursive locking here */ + + mtx_lock(xfer->priv_mtx); + + if (error) { + xfer->flags_int.bdma_error = 1; + } else { + __KASSERT(nseg > 0, ("Invalid number of segments!\n")); + + pg = pc->page_start; + rem = segs->ds_addr & (USB_PAGE_SIZE - 1); + + pc->page_offset_buf += rem; + pc->page_offset_end += rem; + + pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1); + + while (1) { + + if (--nseg == 0) { + break; + } + pg++; + segs++; + pg->physaddr = segs->ds_addr & ~(USB_PAGE_SIZE - 1); + } + } + + usbd_bdma_done_event(xfer); + + mtx_unlock(xfer->priv_mtx); + return; +} + +/*---------------------------------------------------------------------------* + * usbd_dma_load_mem - load DMA memory if any + *---------------------------------------------------------------------------*/ +void +usbd_dma_load_mem(struct usbd_xfer *xfer, struct usbd_dma_load_mem_info *info) +{ + struct usbd_page_cache *pc; + struct usbd_page *pg; + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + uint32_t npg; + int error; + + pc = info->page_cache; + + if (info->frame_length == 0) { + /* not used */ + pc->page_start = NULL; + pc->page_offset_buf = 0; + pc->page_offset_end = 0; + return; + } + /* select the one byte alignment DMA tag */ + + dma_tag = xfer->udev->bus->dma_tag_1b; + if (pc->isread) { + dma_map = xfer->dma_rx_map; + } else { + dma_map = xfer->dma_tx_map; + } + + /* increment refcount */ + + xfer->dma_refcount++; + + /* initialize the "usbd_page_cache" structure */ + + pc->page_start = info->page_ptr; + pc->page_offset_buf = 0; + pc->page_offset_end = info->frame_length; + + /* initialize the "usbd_page" structure */ + + npg = (info->frame_length / USB_PAGE_SIZE) + 2; + pg = info->page_ptr; + + while (npg--) { + pg->tag = dma_tag; + pg->map = dma_map; + pg->length = USB_PAGE_SIZE; + pg++; + } + + /* update "page_ptr" to the next pointer value */ + + info->page_ptr = pg; + + error = bus_dmamap_load(dma_tag, dma_map, pc->p_buffer, + info->frame_length, usbd_dma_load_mem_callback, pc, 0); + + return; +} + #endif #ifdef __NetBSD__ bus_dma_tag_t -usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t size, - uint32_t alignment) +usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t seg_size, + uint32_t alignment, uint32_t max_size) { /* FreeBSD specific */ return parent; @@ -2283,6 +2394,7 @@ void usbd_dma_tag_free(bus_dma_tag_t tag) { + /* FreeBSD specific */ return; } @@ -2394,6 +2506,59 @@ #endif +/*---------------------------------------------------------------------------* + * usbd_pio_load_mem - load virtual memory if any + *---------------------------------------------------------------------------*/ +void +usbd_pio_load_mem(struct usbd_xfer *xfer, struct usbd_dma_load_mem_info *info) +{ + struct usbd_page_cache *pc; + struct usbd_page *pg; + uint32_t npg; + uint32_t rem; + uint8_t *ptr; + + pc = info->page_cache; + pg = info->page_ptr; + + if (info->frame_length == 0) { + /* not used */ + pc->page_start = NULL; + pc->page_offset_buf = 0; + pc->page_offset_end = 0; + return; + } + ptr = pc->p_buffer; + rem = POINTER_TO_UNSIGNED(ptr) & (USB_PAGE_SIZE - 1); + ptr -= rem; /* page align */ + info->frame_length += rem; /* adjust */ + + pc->page_start = pg; + pc->page_offset_buf = rem; + pc->page_offset_end = info->frame_length; + + npg = (info->frame_length + (USB_PAGE_SIZE - 1)) / USB_PAGE_SIZE; + + while (npg--) { + + /* + * NOTE: We only setup the fields + * we need for PIO in "struct usbd_page" + */ + pg->buffer = ptr; + pg->length = USB_PAGE_SIZE; + + ptr += USB_PAGE_SIZE; + pg++; + } + + /* update page pointer */ + + info->page_ptr = pg; + + return; +} + /*------------------------------------------------------------------------------* * usbd_make_str_desc - convert an ASCII string into a UNICODE string *------------------------------------------------------------------------------*/ @@ -2890,3 +3055,67 @@ return bus->isoc_time_last; } + +/*------------------------------------------------------------------------* + * usbd_bus_mem_setup - factored out code + * + * Return: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +uint8_t +usbd_bus_mem_setup(struct usbd_bus *bus, bus_dma_tag_t parent_tag, + uint32_t hw_mem_size, uint8_t hw_addr_lines, uint8_t hw_align_power) +{ + + if (hw_mem_size > 0) { + + bus->hw_ptr.data = + usbd_mem_alloc(parent_tag, &(bus->hw_page), + hw_mem_size, hw_align_power); + + if (bus->hw_ptr.data == NULL) { + goto error; + } + } + bus->dma_tag_1b = + usbd_dma_tag_alloc(parent_tag, USB_PAGE_SIZE, 1, + 0 - 1); + + if (bus->dma_tag_1b == NULL) { + goto error; + } + bus->dma_tag_ps = + usbd_dma_tag_alloc(parent_tag, USB_PAGE_SIZE, USB_PAGE_SIZE, + USB_PAGE_SIZE); + + if (bus->dma_tag_ps == NULL) { + goto error; + } + return 0; + +error: + usbd_bus_mem_unsetup(bus); + return 1; +} + +/*------------------------------------------------------------------------* + * usbd_bus_mem_unsetup - factored out code + *------------------------------------------------------------------------*/ +void +usbd_bus_mem_unsetup(struct usbd_bus *bus) +{ + if (bus->dma_tag_ps) { + usbd_dma_tag_free(bus->dma_tag_ps); + bus->dma_tag_ps = NULL; + } + if (bus->dma_tag_1b) { + usbd_dma_tag_free(bus->dma_tag_1b); + bus->dma_tag_1b = NULL; + } + if (bus->hw_ptr.data) { + usbd_mem_free(&(bus->hw_page)); + bus->hw_ptr.data = NULL; + } + return; +} ==== //depot/projects/usb/src/sys/dev/usb/usb_subr.h#56 (text+ko) ==== @@ -65,12 +65,16 @@ m(USBD_SHORT_XFER,)\ m(USBD_STALLED,)\ m(USBD_INTERRUPTED,)\ +m(USBD_DMA_LOAD_FAILED,)\ /**/ MAKE_ENUM(USBD_STATUS, N_USBD_STATUS); #define USBD_GET_STATE(xfer) ((xfer)->usb_state) +#define USBD_GET_DATA_ISREAD(xfer) ((xfer)->flags_int.is_dci ? \ +((xfer->endpoint & UE_DIR_IN) ? 0 : 1) : \ + ((xfer->endpoint & UE_DIR_IN) ? 1 : 0)) /* USB transfer states */ @@ -111,6 +115,9 @@ struct proc; struct usb_device; /* Linux compat */ struct cdev; +struct ehci_hw_softc; +struct uhci_hw_softc; +struct ohci_hw_softc; typedef uint8_t usbd_status; @@ -202,11 +209,14 @@ struct usbd_page_cache { struct usbd_page *page_start; - struct usbd_xfer *p_xfer; + struct usbd_xfer *p_xfer; /* this backpointer to the USB + * transfer is used when loading + * virtual buffers into DMA */ void *p_buffer; /* virtual buffer to be loaded by * BUS-DMA */ uint32_t page_offset_buf; uint32_t page_offset_end; + uint8_t isread:1; }; struct usbd_setup_params { @@ -234,9 +244,20 @@ struct usbd_bus { struct usb_device_stats stats; struct mtx mtx; + struct usbd_page hw_page; + union { + struct ehci_hw_softc *ehci; + struct uhci_hw_softc *uhci; + struct ohci_hw_softc *ohci; + void *data; + } hw_ptr; + device_t bdev; /* filled by HC driver */ - bus_dma_tag_t dma_tag; /* filled by HC driver */ + bus_dma_tag_t dma_tag_1b; /* 1 byte aligned DMA-tag, filled by + * HC driver */ + bus_dma_tag_t dma_tag_ps; /* page size aligned DMA-tag, filled + * by HC driver */ eventhandler_tag usb_clone_tag; struct usbd_bus_methods *methods; /* filled by HC driver */ struct usbd_device *devices[USB_MAX_DEVICES]; @@ -353,8 +374,9 @@ }; struct usbd_xfer_flags { - uint8_t force_short_xfer:1; /* force a short transfer last */ - uint8_t short_xfer_ok:1; /* allow short transfers */ + uint8_t force_short_xfer:1; /* force a short transmit transfer + * last */ + uint8_t short_xfer_ok:1; /* allow short receive transfers */ uint8_t short_frames_ok:1; /* allow short frames */ uint8_t pipe_bof:1; /* block pipe on failure */ uint8_t use_polling:1; /* poll until transfer is finished */ @@ -386,6 +408,13 @@ uint8_t short_frames_ok:1; /* filtered version */ uint8_t short_xfer_ok:1; /* filtered version */ uint8_t bdma_state:2; /* BUS-DMA state */ + uint8_t bdma_error:1; /* BUS-DMA error flag */ + uint8_t bdma_enable:1; /* filtered version (only set if + * hardware supports DMA) */ + uint8_t bdma_draining:1; + uint8_t isochronous_xfr:1; /* set if isochronous transfer */ + uint8_t is_dci:1; /* set if hardware is a device + * controller interface */ }; struct usbd_config { @@ -413,6 +442,8 @@ LIST_ENTRY(usbd_xfer) interrupt_list; /* used by HC driver */ LIST_ENTRY(usbd_xfer) pipe_list; /* used by HC driver */ + bus_dmamap_t dma_rx_map; + bus_dmamap_t dma_tx_map; struct usbd_page *dma_page_ptr; struct usbd_pipe *pipe; struct usbd_device *udev; @@ -432,6 +463,7 @@ struct usbd_page_cache *frbuffers; usbd_callback_t *callback; + uint32_t dma_refcount; uint32_t max_usb_frame_size; uint32_t max_data_length; uint32_t sumlen; /* sum of all lengths in bytes */ @@ -464,6 +496,12 @@ struct usbd_xfer_flags_int flags_int; }; +struct usbd_dma_load_mem_info { + struct usbd_page *page_ptr; + struct usbd_page_cache *page_cache; + uint32_t frame_length; +}; + struct usbd_memory_info { void *memory_base; struct mtx *priv_mtx; @@ -668,17 +706,19 @@ uint32_t usbd_page_fit_obj(uint32_t size, uint32_t obj_len); void *usbd_mem_alloc(bus_dma_tag_t parent, struct usbd_page *page, uint32_t size, uint8_t align_power); void usbd_mem_free(struct usbd_page *page); -bus_dma_tag_t usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t size, uint32_t alignment); +bus_dma_tag_t usbd_dma_tag_alloc(bus_dma_tag_t parent, uint32_t seg_size, uint32_t alignment, uint32_t max_size); void usbd_dma_tag_free(bus_dma_tag_t tag); void *usbd_mem_alloc_sub(bus_dma_tag_t tag, struct usbd_page *page, uint32_t size, uint32_t alignment); void usbd_mem_free_sub(struct usbd_page *page); void usbd_page_dma_exit(struct usbd_page *page); void usbd_page_dma_enter(struct usbd_page *page); +void usbd_pio_load_mem(struct usbd_xfer *xfer, struct usbd_dma_load_mem_info *info); uint8_t usbd_make_str_desc(void *ptr, uint16_t max_len, const char *s); uint32_t mtx_drop_recurse(struct mtx *mtx); void mtx_pickup_recurse(struct mtx *mtx, uint32_t recurse_level); uint8_t usbd_config_td_setup(struct usbd_config_td *ctd, void *priv_sc, struct mtx *priv_mtx, usbd_config_td_end_of_commands_t *p_func_eoc, uint16_t item_size, uint16_t item_count); void usbd_config_td_stop(struct usbd_config_td *ctd); +void usbd_transfer_drain(struct usbd_xfer *xfer); void usbd_config_td_unsetup(struct usbd_config_td *ctd); void usbd_config_td_queue_command(struct usbd_config_td *ctd, usbd_config_td_command_t *pre_func, usbd_config_td_command_t *post_func, uint16_t command_qcount, uint16_t command_ref); uint8_t usbd_config_td_is_gone(struct usbd_config_td *ctd); @@ -686,6 +726,9 @@ struct mbuf *usbd_ether_get_mbuf(void); int32_t device_delete_all_children(device_t dev); uint16_t usbd_isoc_time_expand(struct usbd_bus *bus, uint16_t isoc_time_curr); +void usbd_dma_load_mem(struct usbd_xfer *xfer, struct usbd_dma_load_mem_info *info); +uint8_t usbd_bus_mem_setup(struct usbd_bus *bus, bus_dma_tag_t parent_tag, uint32_t hw_mem_size, uint8_t hw_addr_lines, uint8_t hw_align_power); +void usbd_bus_mem_unsetup(struct usbd_bus *bus); /* prototypes from usb.c */ @@ -721,6 +764,7 @@ void usbd_transfer_unsetup(struct usbd_xfer **pxfer, uint16_t n_setup); uint8_t usbd_std_root_transfer(struct usbd_std_root_transfer *std, struct thread *ctd, usbd_std_root_transfer_func_t *func); void usbd_start_hardware(struct usbd_xfer *xfer); +void usbd_bdma_done_event(struct usbd_xfer *xfer); void usbd_transfer_start(struct usbd_xfer *xfer); void usbd_transfer_stop(struct usbd_xfer *xfer); void usbd_set_frame_data(struct usbd_xfer *xfer, void *ptr, uint32_t len, uint32_t frindex); ==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#45 (text+ko) ==== @@ -49,6 +49,16 @@ #include <dev/usb/usb_subr.h> #include <dev/usb/usb_hid.h> +/* prototypes */ + +static void usbd_pipe_enter_wrapper(struct usbd_xfer *xfer); +static void usbd_bdma_start_event(struct usbd_xfer *xfer); +static void usbd_compute_max_frame_size(struct usbd_xfer *xfer); +static void usbd_drop_refcount(struct usbd_memory_info *info); +static uint8_t usbd_start_hardware_sub(struct usbd_xfer *xfer); +static void usbd_premature_callback(struct usbd_xfer *xfer, usbd_status error); +static void usbd_delayed_transfer_start(void *arg); + #ifdef USB_DEBUG void usbd_dump_iface(struct usbd_interface *iface) @@ -277,7 +287,8 @@ { enum { REQ_SIZE = 8, - MIN_PKT = 8}; + MIN_PKT = 8, + }; struct usbd_xfer *xfer = parm->curr_xfer; const struct usbd_config *setup = parm->curr_setup; usb_endpoint_descriptor_t *edesc; @@ -362,6 +373,7 @@ uint32_t frame_limit; xfer->interval = 0; /* not used, must be zero */ + xfer->flags_int.isochronous_xfr = 1; /* set flag */ if (xfer->timeout == 0) { /* @@ -596,9 +608,30 @@ */ if (xfer->flags.bdma_enable) { - /* setup "dma_page_ptr" */ + /* + * Setup "dma_page_ptr". + * + * Proof for formula below: + * + * Assume there are three USB frames having length "a", "b" and + * "c". These USB frames will at maximum need "z" + * "usbd_page" structures. "z" is given by: + * + * z = ((a / USB_PAGE_SIZE) + 2) + ((b / USB_PAGE_SIZE) + 2) + + * ((c / USB_PAGE_SIZE) + 2); + * + * Constraining "a", "b" and "c" like this: + * + * (a + b + c) <= parm->bufsize + * + * We know that: + * + * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2)); + * + * Here is the general formula: + */ xfer->dma_page_ptr = parm->dma_page_ptr; - parm->dma_page_ptr += n_frbuffers; + parm->dma_page_ptr += (2 * n_frbuffers); parm->dma_page_ptr += (parm->bufsize / USB_PAGE_SIZE); } if (zmps) { @@ -823,7 +856,7 @@ parm.page_ptr = USBD_ADD_BYTES(buf, parm.size[2]); parm.dma_page_ptr = USBD_ADD_BYTES(buf, parm.size[3]); - if (usbd_page_alloc(udev->bus->dma_tag, + if (usbd_page_alloc(udev->bus->dma_tag_ps, parm.page_ptr, parm.total_size[1])) { free(buf, M_USB); parm.err = USBD_NOMEM; @@ -909,7 +942,9 @@ */ pxfer[n_setup] = NULL; - usbd_transfer_stop(xfer); + mtx_unlock(xfer->priv_mtx); + + usbd_transfer_drain(xfer); /* * NOTE: default pipe does not have an @@ -917,7 +952,6 @@ */ xfer->pipe->refcount--; - mtx_unlock(xfer->priv_mtx); } else { /* clear the transfer pointer */ pxfer[n_setup] = NULL; @@ -1261,7 +1295,9 @@ mtx_assert(xfer->priv_mtx, MA_OWNED); - if (!xfer->flags_int.open) { + /* sanity checks */ + + if (!xfer->flags_int.open || xfer->flags_int.transferring) { return; } /* set "transferring" and "recursed_2" flags */ @@ -1290,7 +1326,7 @@ } } - /* filter some flags */ + /* clear some internal flags */ xfer->flags_int.short_xfer_ok = 0; xfer->flags_int.short_frames_ok = 0; @@ -1303,14 +1339,25 @@ usbd_premature_callback(xfer, USBD_STALLED); return; } - if (xfer->endpoint & UE_DIR_IN) { + } >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200711241819.lAOIJ3va061137>