PERFORCE change 150212 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Sep 21 15:02:44 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=150212
Change 150212 by hselasky at 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);
More information about the p4-projects
mailing list