Date: Sun, 21 Sep 2008 15:02:43 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 150212 for review Message-ID: <200809211502.m8LF2h59066105@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=150212 Change 150212 by hselasky@hselasky_laptop001 on 2008/09/21 15:02:10 1) Significantly improve DMA allocation speed. Before DMA memory was allocated one struct at a time. Now, if multiple pieces of DMA memory should be allocated, try to fill up PAGE_SIZE bytes at a time with DMA structures. The bottleneck is slow allocation and freeing of DMA memory. 2) Add a SYSCTL variable that controls if the EHCI should disable ownership for all attached USB devices. This is useful for testing. Affected files ... .. //depot/projects/usb/src/sys/dev/usb2/controller/ehci2.c#15 edit .. //depot/projects/usb/src/sys/dev/usb2/controller/ohci2.c#14 edit .. //depot/projects/usb/src/sys/dev/usb2/controller/uhci2.c#12 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.c#28 edit .. //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.h#7 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb2/controller/ehci2.c#15 (text+ko) ==== @@ -75,10 +75,13 @@ #if USB_DEBUG static int ehcidebug = 0; +static int ehcinohighspeed = 0; SYSCTL_NODE(_hw_usb2, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, debug, CTLFLAG_RW, - &ehcidebug, 0, "ehci debug level"); + &ehcidebug, 0, "Debug level"); +SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, no_hs, CTLFLAG_RW, + &ehcinohighspeed, 0, "Disable High Speed USB"); static void ehci_dump_regs(ehci_softc_t *sc); static void ehci_dump_sqh(ehci_qh_t *sqh); @@ -3346,6 +3349,16 @@ break; case UHF_PORT_RESET: DPRINTFN(6, "reset port %d\n", index); +#if USB_DEBUG + if (ehcinohighspeed) { + /* + * Connect USB device to companion + * controller. + */ + ehci_disown(sc, index, 1); + break; + } +#endif if (EHCI_PS_IS_LOWSPEED(v)) { /* Low speed device, give up ownership. */ ehci_disown(sc, index, 1); @@ -3641,110 +3654,106 @@ */ last_obj = NULL; - for (n = 0; n != nitd; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ehci_itd_t), + EHCI_ITD_ALIGN, nitd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nitd; n++) { + ehci_itd_t *td; - register ehci_itd_t *td; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*td), - EHCI_ITD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); td = page_info.buffer; /* init TD */ td->itd_self = htole32(page_info.physaddr | EHCI_LINK_ITD); td->obj_next = last_obj; - td->page_cache = pc; + td->page_cache = pc + n; last_obj = td; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ehci_sitd_t), + EHCI_SITD_ALIGN, nsitd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nsitd; n++) { + ehci_sitd_t *td; - for (n = 0; n != nsitd; n++) { - - register ehci_sitd_t *td; + usb2_get_page(pc + n, 0, &page_info); - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*td), - EHCI_SITD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { - td = page_info.buffer; /* init TD */ td->sitd_self = htole32(page_info.physaddr | EHCI_LINK_SITD); td->obj_next = last_obj; - td->page_cache = pc; + td->page_cache = pc + n; last_obj = td; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ehci_qtd_t), + EHCI_QTD_ALIGN, nqtd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nqtd; n++) { + ehci_qtd_t *qtd; - for (n = 0; n != nqtd; n++) { - - register ehci_qtd_t *qtd; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*qtd), - EHCI_QTD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); qtd = page_info.buffer; /* init TD */ qtd->qtd_self = htole32(page_info.physaddr); qtd->obj_next = last_obj; - qtd->page_cache = pc; + qtd->page_cache = pc + n; last_obj = qtd; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; last_obj = NULL; - for (n = 0; n != nqh; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ehci_qh_t), + EHCI_QH_ALIGN, nqh)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nqh; n++) { + ehci_qh_t *qh; - register ehci_qh_t *qh; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*qh), - EHCI_QH_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); qh = page_info.buffer; /* init QH */ qh->qh_self = htole32(page_info.physaddr | EHCI_LINK_QH); qh->obj_next = last_obj; - qh->page_cache = pc; + qh->page_cache = pc + n; last_obj = qh; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; if (!xfer->flags_int.curr_dma_set) { ==== //depot/projects/usb/src/sys/dev/usb2/controller/ohci2.c#14 (text+ko) ==== @@ -2637,85 +2637,82 @@ } last_obj = NULL; - for (n = 0; n != ntd; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ohci_td_t), + OHCI_TD_ALIGN, ntd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != ntd; n++) { + ohci_td_t *td; - ohci_td_t *td; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*td), - OHCI_TD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); td = page_info.buffer; /* init TD */ td->td_self = htole32(page_info.physaddr); td->obj_next = last_obj; - td->page_cache = pc; + td->page_cache = pc + n; last_obj = td; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ohci_itd_t), + OHCI_ITD_ALIGN, nitd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nitd; n++) { + ohci_itd_t *itd; - for (n = 0; n != nitd; n++) { - - ohci_itd_t *itd; + usb2_get_page(pc + n, 0, &page_info); - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*itd), - OHCI_ITD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { - itd = page_info.buffer; /* init TD */ itd->itd_self = htole32(page_info.physaddr); itd->obj_next = last_obj; - itd->page_cache = pc; + itd->page_cache = pc + n; last_obj = itd; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; last_obj = NULL; - for (n = 0; n != nqh; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(ohci_ed_t), + OHCI_ED_ALIGN, nqh)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nqh; n++) { + ohci_ed_t *ed; - ohci_ed_t *ed; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*ed), - OHCI_ED_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); ed = page_info.buffer; /* init QH */ ed->ed_self = htole32(page_info.physaddr); ed->obj_next = last_obj; - ed->page_cache = pc; + ed->page_cache = pc + n; last_obj = ed; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; if (!xfer->flags_int.curr_dma_set) { ==== //depot/projects/usb/src/sys/dev/usb2/controller/uhci2.c#12 (text+ko) ==== @@ -3090,23 +3090,13 @@ } align = (1 << n); - for (n = 0; n != nfixup; n++) { - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, xfer->max_frame_size, - align)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (n == 0) { - /* - * We depend on some assumptions here, like how - * "sub_malloc" lays out the "usb2_page_cache" - * structures - */ - xfer->buf_fixup = pc; - } + if (usb2_transfer_setup_sub_malloc( + parm, &pc, xfer->max_frame_size, + align, nfixup)) { + parm->err = USB_ERR_NOMEM; + return; } + xfer->buf_fixup = pc; alloc_dma_set: @@ -3115,17 +3105,17 @@ } last_obj = NULL; - for (n = 0; n != ntd; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(uhci_td_t), + UHCI_TD_ALIGN, ntd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != ntd; n++) { + uhci_td_t *td; - uhci_td_t *td; - - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*td), - UHCI_TD_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { + usb2_get_page(pc + n, 0, &page_info); td = page_info.buffer; @@ -3134,49 +3124,49 @@ (parm->methods == &uhci_device_ctrl_methods) || (parm->methods == &uhci_device_intr_methods)) { /* set depth first bit */ - td->td_self = htole32(page_info.physaddr | UHCI_PTR_TD | UHCI_PTR_VF); + td->td_self = htole32(page_info.physaddr | + UHCI_PTR_TD | UHCI_PTR_VF); } else { - td->td_self = htole32(page_info.physaddr | UHCI_PTR_TD); + td->td_self = htole32(page_info.physaddr | + UHCI_PTR_TD); } td->obj_next = last_obj; - td->page_cache = pc; + td->page_cache = pc + n; last_obj = td; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; last_obj = NULL; - for (n = 0; n != nqh; n++) { + if (usb2_transfer_setup_sub_malloc( + parm, &pc, sizeof(uhci_qh_t), + UHCI_QH_ALIGN, nqh)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != nqh; n++) { + uhci_qh_t *qh; - uhci_qh_t *qh; + usb2_get_page(pc + n, 0, &page_info); - if (usb2_transfer_setup_sub_malloc( - parm, &page_info, &pc, sizeof(*qh), - UHCI_QH_ALIGN)) { - parm->err = USB_ERR_NOMEM; - break; - } - if (parm->buf) { - qh = page_info.buffer; /* init QH */ qh->qh_self = htole32(page_info.physaddr | UHCI_PTR_QH); qh->obj_next = last_obj; - qh->page_cache = pc; + qh->page_cache = pc + n; last_obj = qh; - usb2_pc_cpu_flush(pc); + usb2_pc_cpu_flush(pc + n); } } - xfer->qh_start[xfer->flags_int.curr_dma_set] = last_obj; if (!xfer->flags_int.curr_dma_set) { ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.c#28 (text+ko) ==== @@ -182,9 +182,9 @@ /*------------------------------------------------------------------------* * usb2_transfer_setup_sub_malloc * - * This function will allocate DMA'able memory and store the virtual - * and physical buffer addresses in the structure pointed to by the - * "info" argument. + * This function will allocate one or more DMA'able memory chunks + * according to "size", "align" and "count" arguments. "ppc" is + * pointed to a linear array of USB page caches afterwards. * * Returns: * 0: Success @@ -192,36 +192,112 @@ *------------------------------------------------------------------------*/ uint8_t usb2_transfer_setup_sub_malloc(struct usb2_setup_params *parm, - struct usb2_page_search *info, struct usb2_page_cache **ppc, - uint32_t size, uint32_t align) + struct usb2_page_cache **ppc, uint32_t size, uint32_t align, + uint32_t count) { + struct usb2_page_cache *pc; + struct usb2_page *pg; + void *buf; + uint32_t n_dma_pc; + uint32_t n_obj; + uint32_t x; + uint32_t y; + uint32_t r; + uint32_t z; + USB_ASSERT(align > 1, ("Invalid alignment, 0x%08x!\n", align)); USB_ASSERT(size > 0, ("Invalid size = 0!\n")); + if (count == 0) { + return (0); /* nothing to allocate */ + } + /* + * Make sure that the size is aligned properly. + */ + size = -((-size) & (-align)); + + /* + * Try multi-allocation chunks to reduce the number of DMA + * allocations, hence DMA allocations are slow. + */ + if (size >= PAGE_SIZE) { + n_dma_pc = count; + n_obj = 1; + } else { + /* compute number of objects per page */ + n_obj = (PAGE_SIZE / size); + /* + * Compute number of DMA chunks, rounded up + * to nearest one: + */ + n_dma_pc = ((count + n_obj - 1) / n_obj); + } + if (parm->buf == NULL) { /* for the future */ - parm->dma_page_ptr++; - parm->dma_page_cache_ptr++; + parm->dma_page_ptr += n_dma_pc; + parm->dma_page_cache_ptr += n_dma_pc; + parm->dma_page_ptr += count; + parm->xfer_page_cache_ptr += count; return (0); } - /* need to initialize the page cache */ - parm->dma_page_cache_ptr->tag_parent = - &parm->curr_xfer->usb2_root->dma_parent_tag; - - if (usb2_pc_alloc_mem(parm->dma_page_cache_ptr, - parm->dma_page_ptr, size, align)) { - return (1); /* failure */ + for (x = 0; x != n_dma_pc; x++) { + /* need to initialize the page cache */ + parm->dma_page_cache_ptr[x].tag_parent = + &parm->curr_xfer->usb2_root->dma_parent_tag; } - if (info) { - usb2_get_page(parm->dma_page_cache_ptr, 0, info); + for (x = 0; x != count; x++) { + /* need to initialize the page cache */ + parm->xfer_page_cache_ptr[x].tag_parent = + &parm->curr_xfer->usb2_root->dma_parent_tag; } + if (ppc) { - *ppc = parm->dma_page_cache_ptr; + *ppc = parm->xfer_page_cache_ptr; + } + r = count; /* set remainder count */ + z = n_obj * size; /* set allocation size */ + pc = parm->xfer_page_cache_ptr; + pg = parm->dma_page_ptr; + + for (x = 0; x != n_dma_pc; x++) { + + if (r < n_obj) { + /* compute last remainder */ + z = r * size; + n_obj = r; + } + if (usb2_pc_alloc_mem(parm->dma_page_cache_ptr, + pg, z, align)) { + return (1); /* failure */ + } + /* Set beginning of current buffer */ + buf = parm->dma_page_cache_ptr->buffer; + /* Make room for one DMA page cache and one page */ + parm->dma_page_cache_ptr++; + pg++; + + for (y = 0; (y != n_obj); y++, r--, pc++, pg++) { + + /* Load sub-chunk into DMA */ + if (usb2_pc_dmamap_create(pc, size)) { + return (1); /* failure */ + } + pc->buffer = USB_ADD_BYTES(buf, y * size); + pc->page_start = pg; + + mtx_lock(pc->tag_parent->mtx); + if (usb2_pc_load_mem(pc, size, 1 /* synchronous */ )) { + mtx_unlock(pc->tag_parent->mtx); + return (1); /* failure */ + } + mtx_unlock(pc->tag_parent->mtx); + } } - parm->dma_page_ptr++; - parm->dma_page_cache_ptr++; + parm->xfer_page_cache_ptr = pc; + parm->dma_page_ptr = pg; return (0); } ==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_transfer.h#7 (text+ko) ==== @@ -104,7 +104,7 @@ /* function prototypes */ uint8_t usb2_transfer_pending(struct usb2_xfer *xfer); -uint8_t usb2_transfer_setup_sub_malloc(struct usb2_setup_params *parm, struct usb2_page_search *info, struct usb2_page_cache **ppc, uint32_t size, uint32_t align); +uint8_t usb2_transfer_setup_sub_malloc(struct usb2_setup_params *parm, struct usb2_page_cache **ppc, uint32_t size, uint32_t align, uint32_t count); void usb2_command_wrapper(struct usb2_xfer_queue *pq, struct usb2_xfer *xfer); void usb2_pipe_enter(struct usb2_xfer *xfer); void usb2_pipe_start(struct usb2_xfer_queue *pq);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809211502.m8LF2h59066105>