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