PERFORCE change 129799 for review

Hans Petter Selasky hselasky at FreeBSD.org
Thu Nov 29 15:32:41 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=129799

Change 129799 by hselasky at hselasky_laptop001 on 2007/11/29 23:32:21

	
	This commit shifts the USB stack towards allocating DMA control
	structures in smaller pieces. This is required to avoid syncing large
	chucks of memory at a time when only a small piece of memory is
	required to be synced.
	
	This commit implement most changes needed for the EHCI driver. OHCI
	and UHCI will follow.
	
	Due to the design of the BUS-DMA system, it is not possible to
	allocate one big memory block and then just sync parts of it.
	
	I have created an new function "ehci_iterate_hw_softc" that will
	iterate accross all the DMA structures, which simplifies setup,
	flushing and unsetup.
	
	Also I have cleaned up the flushing and invalidating of memory in the
	EHCI driver.
	
	I have discovered that there is shared data stored in the BUS-DMA tags
	(the segment list for example), and that I need separate tags for each
	bulk of USB transfers I setup, to allow parallell loading of DMA
	buffers. Also I need so serialize loading of DMA buffers within each
	bulk of USB transfer that are setup.
	
	Until I am finished working on the DMA stuff in the USB stack, the P4
	USB project will not be compilable. Sorry for the inconvenience.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/ehci.c#52 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci.h#22 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci_pci.c#26 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/ehci.c#52 (text+ko) ====

@@ -113,10 +113,6 @@
 static usbd_std_root_transfer_func_t ehci_root_intr_done;
 static usbd_std_root_transfer_func_t ehci_root_ctrl_task_td_sub;
 
-#define	SC_HW_PHYSADDR(sc,what) \
-  ((sc)->sc_hw_page.physaddr +	\
-   POINTER_TO_UNSIGNED(&(((struct ehci_hw_softc *)0)->what)))
-
 struct ehci_std_temp {
 	struct usbd_page_cache *pc;
 	ehci_qtd_t *td;
@@ -130,12 +126,73 @@
 	uint8_t	setup_alt_next;
 };
 
+void
+ehci_iterate_hw_softc(ehci_softc_t *sc, ehci_iterate_cb_t *cb)
+{
+	uint32_t i;
+
+	cb(sc, &(sc->sc_hw.pframes_pc), &(sc->sc_hw.pframes_pg),
+	    sizeof(uint32_t) * EHCI_FRAMELIST_COUNT, EHCI_FRAMELIST_ALIGN);
+
+	cb(sc, &(sc->sc_hw.async_start_pc), &(sc->sc_hw.async_start_pg),
+	    sizeof(ehci_qh_t), EHCI_QH_ALIGN);
+
+	for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
+		cb(sc, sc->sc_hw.intr_start_pc + i,
+		    sc->sc_hw.intr_start_pg + i,
+		    sizeof(ehci_qh_t), EHCI_QH_ALIGN);
+	}
+
+	for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
+		cb(sc, sc->sc_hw.isoc_hs_start_pc + i,
+		    sc->sc_hw.isoc_hs_start_pg + i,
+		    sizeof(ehci_itd_t), EHCI_ITD_ALIGN);
+	}
+
+	for (i = 0; i != EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
+		cb(sc, sc->sc_hw.isoc_fs_start_pc + i,
+		    sc->sc_hw.isoc_fs_start_pg + i,
+		    sizeof(ehci_sitd_t), EHCI_SITD_ALIGN);
+	}
+	return;
+}
+
+void
+ehci_flush_all(ehci_softc_t *sc, struct usbd_page_cache *pc,
+    struct usbd_page *pg, uint32_t size, uint32_t align)
+{
+	usbd_pc_cpu_flush(pc);
+	return;
+}
+
+void
+ehci_alloc_all(ehci_softc_t *sc, struct usbd_page_cache *pc,
+    struct usbd_page *pg, uint32_t size, uint32_t align)
+{
+	if (usbd_dma_alloc_mem(sc->sc_bus.dma_tag_parent,
+	    sc->sc_bus.dma_tag, pc, pg, size, align)) {
+		sc->sc_alloc_failed = 1;
+	}
+	return;
+}
+
+void
+ehci_free_all(ehci_softc_t *sc, struct usbd_page_cache *pc,
+    struct usbd_page *pg, uint32_t size, uint32_t align)
+{
+	usbd_dma_free_mem(pc);
+	return;
+}
+
 usbd_status
 ehci_init(ehci_softc_t *sc)
 {
-	struct ehci_hw_softc *hw_ptr;
-	uint32_t version, sparams, cparams, hcr;
-	u_int i;
+	struct usbd_page_search buf_res;
+	uint32_t version;
+	uint32_t sparams;
+	uint32_t cparams;
+	uint32_t hcr;
+	uint16_t i;
 	uint16_t x;
 	uint16_t y;
 	uint16_t bit;
@@ -143,8 +200,6 @@
 
 	mtx_lock(&sc->sc_bus.mtx);
 
-	hw_ptr = sc->sc_hw_ptr;
-
 	DPRINTF(("start\n"));
 
 	LIST_INIT(&sc->sc_interrupt_list_head);
@@ -211,30 +266,37 @@
 
 	sc->sc_eintrs = EHCI_NORMAL_INTRS;
 
-	usbd_page_cpu_invalidate(&(sc->sc_hw_page));
+	for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
+		ehci_qh_t *qh;
+
+		usbd_get_page(sc->sc_hw.intr_start_pc + i, 0, &buf_res);
+
+		qh = buf_res.buffer;
+
+		/* initialize page cache pointer */
+
+		qh->page_cache = sc->sc_hw.intr_start_pc + i;
+
+		/* store a pointer to queue head */
+
+		sc->sc_intr_p_last[i] = qh;
 
-	for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
-		hw_ptr->intr_start[i].qh_self =
-		    htole32(SC_HW_PHYSADDR(sc, intr_start[i]) | EHCI_LINK_QH);
+		qh->qh_self =
+		    htole32(buf_res.physaddr) |
+		    htole32(EHCI_LINK_QH);
 
-		hw_ptr->intr_start[i].qh_endp =
+		qh->qh_endp =
 		    htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
-		hw_ptr->intr_start[i].qh_endphub =
+		qh->qh_endphub =
 		    htole32(EHCI_QH_SET_MULT(1));
-		hw_ptr->intr_start[i].qh_curqtd = 0;
+		qh->qh_curqtd = 0;
 
-		hw_ptr->intr_start[i].qh_qtd.qtd_next =
+		qh->qh_qtd.qtd_next =
 		    htole32(EHCI_LINK_TERMINATE);
-		hw_ptr->intr_start[i].qh_qtd.qtd_altnext =
+		qh->qh_qtd.qtd_altnext =
 		    htole32(EHCI_LINK_TERMINATE);
-		hw_ptr->intr_start[i].qh_qtd.qtd_status =
+		qh->qh_qtd.qtd_status =
 		    htole32(EHCI_QTD_HALTED);
-
-		hw_ptr->intr_start[i].page =
-		    &(sc->sc_hw_page);
-
-		sc->sc_intr_p_last[i] =
-		    &(hw_ptr->intr_start[i]);
 	}
 
 	/*
@@ -245,103 +307,149 @@
 	while (bit) {
 		x = bit;
 		while (x & bit) {
+			ehci_qh_t *qh_x;
+			ehci_qh_t *qh_y;
+
 			y = (x ^ bit) | (bit / 2);
 
+			qh_x = sc->sc_intr_p_last[x];
+			qh_y = sc->sc_intr_p_last[y];
+
 			/*
 			 * the next QH has half the poll interval
 			 */
-			hw_ptr->intr_start[x].qh_link =
-			    hw_ptr->intr_start[y].qh_self;
+			qh_x->qh_link = qh_y->qh_self;
+
 			x++;
 		}
 		bit >>= 1;
 	}
 
-	/* the last (1ms) QH terminates */
-	hw_ptr->intr_start[0].qh_link = htole32(EHCI_LINK_TERMINATE);
+	if (1) {
+		ehci_qh_t *qh;
+
+		qh = sc->sc_intr_p_last[0];
 
+		/* the last (1ms) QH terminates */
+		qh->qh_link = htole32(EHCI_LINK_TERMINATE);
+	}
 	for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) {
+		ehci_sitd_t *sitd;
+		ehci_itd_t *itd;
+
+		usbd_get_page(sc->sc_hw.isoc_fs_start_pc + i, 0, &buf_res);
+
+		sitd = buf_res.buffer;
+
+		/* initialize page cache pointer */
+
+		sitd->page_cache = sc->sc_hw.isoc_fs_start_pc + i;
+
+		/* store a pointer to the transfer descriptor */
+
+		sc->sc_isoc_fs_p_last[i] = sitd;
+
 		/* initialize full speed isochronous */
 
-		hw_ptr->isoc_fs_start[i].sitd_self =
-		    htole32(SC_HW_PHYSADDR(sc, isoc_fs_start[i]) | EHCI_LINK_SITD);
+		sitd->sitd_self =
+		    htole32(buf_res.physaddr) |
+		    htole32(EHCI_LINK_SITD);
 
-		hw_ptr->isoc_fs_start[i].sitd_back =
+		sitd->sitd_back =
 		    htole32(EHCI_LINK_TERMINATE);
 
-		hw_ptr->isoc_fs_start[i].sitd_next =
-		    hw_ptr->intr_start[i | (EHCI_VIRTUAL_FRAMELIST_COUNT / 2)].qh_self;
+		sitd->sitd_next =
+		    sc->sc_intr_p_last[i | (EHCI_VIRTUAL_FRAMELIST_COUNT / 2)]->qh_self;
+
+
+		usbd_get_page(sc->sc_hw.isoc_hs_start_pc + i, 0, &buf_res);
+
+		itd = buf_res.buffer;
+
+		/* initialize page cache pointer */
 
-		hw_ptr->isoc_fs_start[i].page =
-		    &(sc->sc_hw_page);
+		itd->page_cache = sc->sc_hw.isoc_hs_start_pc + i;
 
-		sc->sc_isoc_fs_p_last[i] =
-		    &(hw_ptr->isoc_fs_start[i]);
+		/* store a pointer to the transfer descriptor */
 
+		sc->sc_isoc_hs_p_last[i] = itd;
 
 		/* initialize high speed isochronous */
 
-		hw_ptr->isoc_hs_start[i].itd_self =
-		    htole32(SC_HW_PHYSADDR(sc, isoc_hs_start[i]) | EHCI_LINK_ITD);
+		itd->itd_self =
+		    htole32(buf_res.physaddr) |
+		    htole32(EHCI_LINK_ITD);
+
+		itd->itd_next =
+		    sitd->sitd_self;
+	}
+
+	usbd_get_page(&(sc->sc_hw.pframes_pc), 0, &buf_res);
 
-		hw_ptr->isoc_hs_start[i].itd_next =
-		    hw_ptr->isoc_fs_start[i].sitd_self;
+	if (1) {
+		uint32_t *pframes;
 
-		hw_ptr->isoc_hs_start[i].page =
-		    &(sc->sc_hw_page);
+		pframes = buf_res.buffer;
 
-		sc->sc_isoc_hs_p_last[i] =
-		    &(hw_ptr->isoc_hs_start[i]);
+		/*
+		 * execution order:
+		 * pframes -> high speed isochronous ->
+		 *    full speed isochronous -> interrupt QH's
+		 */
+		for (i = 0; i < EHCI_FRAMELIST_COUNT; i++) {
+			pframes[i] = sc->sc_isoc_hs_p_last
+			    [i & (EHCI_VIRTUAL_FRAMELIST_COUNT - 1)]->itd_self;
+		}
 	}
+	/* setup sync list pointer */
+	EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr);
+
+	usbd_get_page(&(sc->sc_hw.async_start_pc), 0, &buf_res);
+
+	if (1) {
+
+		ehci_qh_t *qh;
 
-	/*
-	 * execution order:
-	 * pframes -> high speed isochronous ->
-	 *    full speed isochronous -> interrupt QH's
-	 */
-	for (i = 0; i < EHCI_FRAMELIST_COUNT; i++) {
-		hw_ptr->pframes[i] = hw_ptr->isoc_hs_start
-		    [i & (EHCI_VIRTUAL_FRAMELIST_COUNT - 1)].itd_self;
-	}
+		qh = buf_res.buffer;
 
-	/* setup sync list pointer */
-	EOWRITE4(sc, EHCI_PERIODICLISTBASE, SC_HW_PHYSADDR(sc, pframes[0]));
+		/* initialize page cache pointer */
 
+		qh->page_cache = &(sc->sc_hw.async_start_pc);
 
-	/* init dummy QH that starts the async list */
+		/* store a pointer to the queue head */
 
-	hw_ptr->async_start.qh_self =
-	    htole32(SC_HW_PHYSADDR(sc, async_start) | EHCI_LINK_QH);
+		sc->sc_async_p_last = qh;
 
-	/* fill the QH */
-	hw_ptr->async_start.qh_endp =
-	    htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
-	hw_ptr->async_start.qh_endphub = htole32(EHCI_QH_SET_MULT(1));
-	hw_ptr->async_start.qh_link = hw_ptr->async_start.qh_self;
-	hw_ptr->async_start.qh_curqtd = 0;
+		/* init dummy QH that starts the async list */
 
-	/* fill the overlay qTD */
-	hw_ptr->async_start.qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
-	hw_ptr->async_start.qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
-	hw_ptr->async_start.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
+		qh->qh_self =
+		    htole32(buf_res.physaddr) |
+		    htole32(EHCI_LINK_QH);
 
-	/* fill the page pointer */
-	hw_ptr->async_start.page =
-	    &(sc->sc_hw_page);
+		/* fill the QH */
+		qh->qh_endp =
+		    htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
+		qh->qh_endphub = htole32(EHCI_QH_SET_MULT(1));
+		qh->qh_link = qh->qh_self;
+		qh->qh_curqtd = 0;
 
-	sc->sc_async_p_last =
-	    &(hw_ptr->async_start);
+		/* fill the overlay qTD */
+		qh->qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
+		qh->qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
+		qh->qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
+	}
+	/* flush all cache into memory */
 
-	usbd_page_cpu_flush(&(sc->sc_hw_page));
+	ehci_iterate_hw_softc(sc, &ehci_flush_all);
 
 #ifdef USB_DEBUG
 	if (ehcidebug) {
-		ehci_dump_sqh(&(hw_ptr->async_start));
+		ehci_dump_sqh(sc->sc_async_p_last);
 	}
 #endif
 
 	/* setup async list pointer */
-	EOWRITE4(sc, EHCI_ASYNCLISTADDR, SC_HW_PHYSADDR(sc, async_start) | EHCI_LINK_QH);
+	EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH);
 
 
 	/* enable interrupts */
@@ -461,6 +569,7 @@
 void
 ehci_resume(struct ehci_softc *sc)
 {
+	struct usbd_page_search buf_res;
 	uint32_t cmd;
 	uint32_t hcr;
 	uint8_t i;
@@ -469,8 +578,12 @@
 
 	/* restore things in case the bios doesn't */
 	EOWRITE4(sc, EHCI_CTRLDSSEGMENT, 0);
-	EOWRITE4(sc, EHCI_PERIODICLISTBASE, SC_HW_PHYSADDR(sc, pframes[0]));
-	EOWRITE4(sc, EHCI_ASYNCLISTADDR, SC_HW_PHYSADDR(sc, async_start) | EHCI_LINK_QH);
+
+	usbd_get_page(&(sc->sc_hw.pframes_pc), 0, &buf_res);
+	EOWRITE4(sc, EHCI_PERIODICLISTBASE, buf_res.physaddr);
+
+	usbd_get_page(&(sc->sc_hw.async_start_pc), 0, &buf_res);
+	EOWRITE4(sc, EHCI_ASYNCLISTADDR, buf_res.physaddr | EHCI_LINK_QH);
 
 	EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 
@@ -684,11 +797,10 @@
 {
 	uint8_t temp;
 
-	usbd_page_cpu_invalidate(sqtd->page);
+	usbd_pc_cpu_invalidate(sqtd->page_cache);
 	printf("QTD(%p) at 0x%08x:\n", sqtd, le32toh(sqtd->qtd_self));
 	ehci_dump_qtd(sqtd);
 	temp = (sqtd->qtd_next & htole32(EHCI_LINK_TERMINATE)) ? 1 : 0;
-	usbd_page_cpu_flush(sqtd->page);
 	return (temp);
 }
 
@@ -713,7 +825,7 @@
 {
 	uint32_t endp, endphub;
 
-	usbd_page_cpu_invalidate(qh->page);
+	usbd_pc_cpu_invalidate(qh->page_cache);
 	printf("QH(%p) at 0x%08x:\n", qh, le32toh(qh->qh_self) & ~0x1F);
 	printf("  link=");
 	ehci_dump_link(qh->qh_link, 1);
@@ -738,14 +850,13 @@
 	printf("\n");
 	printf("Overlay qTD:\n");
 	ehci_dump_qtd((void *)&qh->qh_qtd);
-	usbd_page_cpu_flush(qh->page);
 	return;
 }
 
 static void
 ehci_dump_sitd(ehci_sitd_t *sitd)
 {
-	usbd_page_cpu_invalidate(sitd->page);
+	usbd_pc_cpu_invalidate(sitd->page_cache);
 	printf("SITD(%p) at 0x%08x\n", sitd, le32toh(sitd->sitd_self) & ~0x1F);
 	printf(" next=0x%08x\n", le32toh(sitd->sitd_next));
 	printf(" portaddr=0x%08x dir=%s addr=%d endpt=0x%x port=0x%x huba=0x%x\n",
@@ -766,14 +877,13 @@
 	    le32toh(sitd->sitd_bp[1]),
 	    le32toh(sitd->sitd_bp_hi[0]),
 	    le32toh(sitd->sitd_bp_hi[1]));
-	usbd_page_cpu_flush(sitd->page);
 	return;
 }
 
 static void
 ehci_dump_itd(ehci_itd_t *itd)
 {
-	usbd_page_cpu_invalidate(itd->page);
+	usbd_pc_cpu_invalidate(itd->page_cache);
 	printf("ITD(%p) at 0x%08x\n", itd, le32toh(itd->itd_self) & ~0x1F);
 	printf(" next=0x%08x\n", le32toh(itd->itd_next));
 	printf(" status[0]=0x%08x; <%s>\n", le32toh(itd->itd_status[0]),
@@ -815,7 +925,6 @@
 	    le32toh(itd->itd_bp_hi[4]),
 	    le32toh(itd->itd_bp_hi[5]),
 	    le32toh(itd->itd_bp_hi[6]));
-	usbd_page_cpu_flush(itd->page);
 	return;
 }
 
@@ -858,15 +967,12 @@
 
 	/* (sc->sc_bus.mtx) must be locked */
 
-	usbd_page_cpu_invalidate(std->page);
-
 	std->next = last->next;
 	std->sitd_next = last->sitd_next;
 
 	std->prev = last;
 
-	usbd_page_cpu_flush(std->page);
-	usbd_page_cpu_invalidate(last->page);
+	usbd_pc_cpu_flush(std->page_cache);
 
 	/*
 	 * the last->next->prev is never followed: std->next->prev = std;
@@ -874,7 +980,7 @@
 	last->next = std;
 	last->sitd_next = std->sitd_self;
 
-	usbd_page_cpu_flush(last->page);
+	usbd_pc_cpu_flush(last->page_cache);
 
 	return (std);
 }
@@ -887,15 +993,12 @@
 
 	/* (sc->sc_bus.mtx) must be locked */
 
-	usbd_page_cpu_invalidate(std->page);
-
 	std->next = last->next;
 	std->itd_next = last->itd_next;
 
 	std->prev = last;
 
-	usbd_page_cpu_flush(std->page);
-	usbd_page_cpu_invalidate(last->page);
+	usbd_pc_cpu_flush(std->page_cache);
 
 	/*
 	 * the last->next->prev is never followed: std->next->prev = std;
@@ -903,7 +1006,7 @@
 	last->next = std;
 	last->itd_next = std->itd_self;
 
-	usbd_page_cpu_flush(last->page);
+	usbd_pc_cpu_flush(last->page_cache);
 
 	return (std);
 }
@@ -916,15 +1019,12 @@
 
 	/* (sc->sc_bus.mtx) must be locked */
 
-	usbd_page_cpu_invalidate(sqh->page);
-
 	sqh->next = last->next;
 	sqh->qh_link = last->qh_link;
 
 	sqh->prev = last;
 
-	usbd_page_cpu_flush(sqh->page);
-	usbd_page_cpu_invalidate(last->page);
+	usbd_pc_cpu_flush(sqh->page_cache);
 
 	/*
 	 * the last->next->prev is never followed: sqh->next->prev = sqh;
@@ -933,7 +1033,7 @@
 	last->next = sqh;
 	last->qh_link = sqh->qh_self;
 
-	usbd_page_cpu_flush(last->page);
+	usbd_pc_cpu_flush(last->page_cache);
 
 #ifdef USB_DEBUG
 	if (ehcidebug > 5) {
@@ -952,17 +1052,14 @@
 
 	/* (sc->sc_bus.mtx) must be locked */
 
-	usbd_page_cpu_invalidate(std->prev->page);
-
 	std->prev->next = std->next;
 	std->prev->sitd_next = std->sitd_next;
 
-	usbd_page_cpu_flush(std->prev->page);
+	usbd_pc_cpu_flush(std->prev->page_cache);
 
 	if (std->next) {
-		usbd_page_cpu_invalidate(std->next->page);
 		std->next->prev = std->prev;
-		usbd_page_cpu_flush(std->next->page);
+		usbd_pc_cpu_flush(std->next->page_cache);
 	}
 	return ((last == std) ? std->prev : last);
 }
@@ -975,17 +1072,14 @@
 
 	/* (sc->sc_bus.mtx) must be locked */
 
-	usbd_page_cpu_invalidate(std->prev->page);
-
 	std->prev->next = std->next;
 	std->prev->itd_next = std->itd_next;
 
-	usbd_page_cpu_flush(std->prev->page);
+	usbd_pc_cpu_flush(std->prev->page_cache);
 
 	if (std->next) {
-		usbd_page_cpu_invalidate(std->next->page);
 		std->next->prev = std->prev;
-		usbd_page_cpu_flush(std->next->page);
+		usbd_pc_cpu_flush(std->next->page_cache);
 	}
 	return ((last == std) ? std->prev : last);
 }
@@ -1000,20 +1094,16 @@
 
 	/* only remove if not removed from a queue */
 	if (sqh->prev) {
-		usbd_page_cpu_invalidate(sqh->prev->page);
 
 		sqh->prev->next = sqh->next;
 		sqh->prev->qh_link = sqh->qh_link;
 
-		usbd_page_cpu_flush(sqh->prev->page);
+		usbd_pc_cpu_flush(sqh->prev->page_cache);
 
 		if (sqh->next) {
-			usbd_page_cpu_invalidate(sqh->next->page);
 			sqh->next->prev = sqh->prev;
-			usbd_page_cpu_flush(sqh->next->page);
+			usbd_pc_cpu_flush(sqh->next->page_cache);
 		}
-		usbd_page_cpu_invalidate(sqh->page);
-
 		/*
 		 * set the Terminate-bit in the e_next of the QH, in case
 		 * the transferred packet was short so that the QH still
@@ -1022,7 +1112,7 @@
 
 		sqh->qh_qtd.qtd_next = htole32(EHCI_LINK_TERMINATE);
 
-		usbd_page_cpu_flush(sqh->page);
+		usbd_pc_cpu_flush(sqh->page_cache);
 
 		last = ((last == sqh) ? sqh->prev : last);
 
@@ -1044,9 +1134,8 @@
 
 	while (1) {
 
-		usbd_page_cpu_invalidate(td->page);
+		usbd_pc_cpu_invalidate(td->page_cache);
 		status = le32toh(td->qtd_status);
-		usbd_page_cpu_flush(td->page);
 
 		len = EHCI_QTD_GET_BYTES(status);
 
@@ -1211,12 +1300,10 @@
 
 		/* isochronous full speed transfer */
 
-		usbd_page_cpu_invalidate(td->page);
+		usbd_pc_cpu_invalidate(td->page_cache);
 
 		status = le32toh(td->sitd_status);
 
-		usbd_page_cpu_flush(td->page);
-
 		if (!(status & EHCI_SITD_ACTIVE)) {
 			ehci_device_done(xfer, USBD_NORMAL_COMPLETION);
 			goto transferred;
@@ -1226,7 +1313,7 @@
 
 		/* isochronous high speed transfer */
 
-		usbd_page_cpu_invalidate(td->page);
+		usbd_pc_cpu_invalidate(td->page_cache);
 
 		status = ((!(td->itd_status[0] & htole32(EHCI_ITD_ACTIVE))) &&
 		    (!(td->itd_status[1] & htole32(EHCI_ITD_ACTIVE))) &&
@@ -1237,8 +1324,6 @@
 		    (!(td->itd_status[6] & htole32(EHCI_ITD_ACTIVE))) &&
 		    (!(td->itd_status[7] & htole32(EHCI_ITD_ACTIVE))));
 
-		usbd_page_cpu_flush(td->page);
-
 		if (status) {
 			ehci_device_done(xfer, USBD_NORMAL_COMPLETION);
 			goto transferred;
@@ -1255,9 +1340,8 @@
 		td = xfer->td_transfer_cache;
 
 		while (1) {
-			usbd_page_cpu_invalidate(td->page);
+			usbd_pc_cpu_invalidate(td->page_cache);
 			status = le32toh(td->qtd_status);
-			usbd_page_cpu_flush(td->page);
 
 			/*
 			 * if there is an active TD the transfer isn't done
@@ -1598,8 +1682,6 @@
 
 			continue;
 		}
-		usbd_page_cpu_invalidate(td->page);
-
 		/* fill out current TD */
 
 		td->qtd_status =
@@ -1678,7 +1760,7 @@
 		td->qtd_altnext = qtd_altnext;
 		td->alt_next = td_alt_next;
 
-		usbd_page_cpu_flush(td->page);
+		usbd_pc_cpu_flush(td->page_cache);
 	}
 
 	if (precompute) {
@@ -1838,14 +1920,12 @@
 	}
 	td = temp.td;
 
-	usbd_page_cpu_invalidate(td->page);
-
 	/* the last TD terminates the transfer: */
 	td->qtd_next = htole32(EHCI_LINK_TERMINATE);
 	td->qtd_altnext = htole32(EHCI_LINK_TERMINATE);
 	td->qtd_status |= htole32(EHCI_QTD_IOC);
 
-	usbd_page_cpu_flush(td->page);
+	usbd_pc_cpu_flush(td->page_cache);
 
 	/* must have at least one frame! */
 
@@ -1863,8 +1943,6 @@
 
 	qh = xfer->qh_start;
 
-	usbd_page_cpu_invalidate(qh->page);
-
 	/* the "qh_link" field is filled when the QH is added */
 
 	qh_endp =
@@ -1925,7 +2003,7 @@
 	qh->qh_qtd.qtd_next = td->qtd_self;
 	qh->qh_qtd.qtd_altnext = htole32(EHCI_LINK_TERMINATE);
 
-	usbd_page_cpu_flush(qh->page);
+	usbd_pc_cpu_flush(qh->page_cache);
 
 	EHCI_APPEND_QH(qh, *qh_last);
 	return;
@@ -1999,9 +2077,8 @@
 			ehci_dump_sitd(td);
 		}
 #endif
-		usbd_page_cpu_invalidate(td->page);
+		usbd_pc_cpu_invalidate(td->page_cache);
 		status = le32toh(td->sitd_status);
-		usbd_page_cpu_flush(td->page);
 
 		/* check for active transfers */
 		if (status & EHCI_SITD_ACTIVE) {
@@ -2060,9 +2137,8 @@
 		}
 #endif
 
-		usbd_page_cpu_invalidate(td->page);
+		usbd_pc_cpu_invalidate(td->page_cache);
 		status = le32toh(td->itd_status[td_no]);
-		usbd_page_cpu_flush(td->page);
 
 		if (status & EHCI_ITD_ACTIVE) {
 			need_delay = 1;
@@ -2453,7 +2529,6 @@
 	/* initialize all TD's */
 
 	for (td = xfer->td_start; td; td = td->obj_next) {
-		usbd_page_cpu_invalidate(td->page);
 
 		td->sitd_portaddr = sitd_portaddr;
 
@@ -2465,7 +2540,7 @@
 		 */
 		td->sitd_back = htole32(EHCI_LINK_TERMINATE);
 
-		usbd_page_cpu_flush(td->page);
+		usbd_pc_cpu_flush(td->page_cache);
 	}
 	return;
 }
@@ -2548,7 +2623,7 @@
 	nframes = xfer->nframes;
 
 	buf_offset = 0;
-	usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res);
+	usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res);
 
 	plen = xfer->frlengths;
 
@@ -2593,12 +2668,10 @@
 		 */
 		sa = usbd_fs_isoc_schedule_alloc(fss, *plen);
 
-		usbd_page_cpu_invalidate(td->page);
-
 		td->sitd_bp[0] = htole32(buf_res.physaddr);
 
 		buf_offset += *plen;
-		usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res);
+		usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res);
 
 		temp = buf_res.physaddr & (~0xFFF);
 
@@ -2647,7 +2720,7 @@
 			    (EHCI_SITD_ACTIVE |
 			    EHCI_SITD_SET_LEN(*plen));
 		}
-		usbd_page_cpu_flush(td->page);
+		usbd_pc_cpu_flush(td->page_cache);
 
 #ifdef USB_DEBUG
 		if (ehcidebug > 15) {
@@ -2712,7 +2785,6 @@
 	/* initialize all TD's */
 
 	for (td = xfer->td_start; td; td = td->obj_next) {
-		usbd_page_cpu_invalidate(td->page);
 
 		/* set TD inactive */
 		td->itd_status[0] = 0;
@@ -2741,7 +2813,7 @@
 		/* set transfer multiplier */
 		td->itd_bp[2] = htole32(xfer->max_packet_count & 3);
 
-		usbd_page_cpu_flush(td->page);
+		usbd_pc_cpu_flush(td->page_cache);
 	}
 	return;
 }
@@ -2819,7 +2891,7 @@
 	nframes = xfer->nframes;
 
 	buf_offset = 0;
-	usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res);
+	usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res);
 
 	page_addr = buf_res.physaddr & ~0xFFF;
 	page_no = 0;
@@ -2856,7 +2928,6 @@
 			*plen = xfer->max_frame_size;
 		}
 		if (td_no == 0) {
-			usbd_page_cpu_invalidate(td->page);
 
 			/* update page address */
 			td->itd_bp[page_no] &= htole32(0xFFF);
@@ -2894,7 +2965,7 @@
 		}
 
 		buf_offset += *plen;
-		usbd_get_page(&(xfer->buf_data), buf_offset, &buf_res);
+		usbd_get_page(xfer->frbuffers + 0, buf_offset, &buf_res);
 
 		if ((buf_res.physaddr ^ page_addr) & ~0xFFF) {
 			/* new page needed */
@@ -2928,7 +2999,7 @@
 		td_no++;
 
 		if ((td_no == 8) || (nframes == 0)) {
-			usbd_page_cpu_flush(td->page);
+			usbd_pc_cpu_flush(td->page_cache);
 #ifdef USB_DEBUG
 			if (ehcidebug > 15) {
 				DPRINTFN(15, ("HS-TD %d\n", nframes));
@@ -3590,6 +3661,26 @@
 	.start = ehci_root_intr_start,
 };
 
+static uint8_t
+ehci_dma_alloc_mem(struct usbd_setup_params *parm, uint32_t size,
+    uint32_t align, struct usbd_page_search *info)
+{
+	ehci_softc_t *sc;
+
+	sc = EHCI_BUS2SC(parm->udev->bus);
+
+	/* FIXME sc->sc_bus.dma_tag to xfer->dma_tags */
+
+	if (usbd_dma_alloc_mem(sc->sc_bus.dma_tag_parent,
+	    sc->sc_bus.dma_tag, parm->dma_page_cache_ptr,
+	    parm->dma_page_ptr, size, align)) {
+		return (1);		/* failure */
+	}
+	usbd_get_page(parm->dma_page_cache_ptr, 0, info);
+
+	return (0);
+}
+
 static void
 ehci_xfer_setup(struct usbd_setup_params *parm)
 {
@@ -3625,8 +3716,16 @@
 		 * The proof for the "nqtd" formula is illustrated like
 		 * this:
 		 *
-		 * | remainder +-----+---+ frm 0 | xxx | x | +-----+---++ frm 1
-		 * | xxx | xx | +-----+----+ ...        |
+		 * +------------------------------------+
+		 * |                                    |
+		 * |         |remainder ->              |
+		 * |   +-----+---+                      |
+		 * |   | xxx | x | frm 0                |
+		 * |   +-----+---++                     |
+		 * |   | xxx | xx | frm 1               |
+		 * |   +-----+----+                     |
+		 * |            ...                     |
+		 * +------------------------------------+
 		 *
 		 * "xxx" means a completely full USB transfer descriptor
 		 *
@@ -3652,6 +3751,8 @@
 		nqtd = ((2 * xfer->nframes) + 1	/* STATUS */
 		    + (xfer->max_data_length / xfer->max_usb_frame_size));
 
+		xfer->flags_int.bdma_enable = 1;
+
 	} else if (parm->methods == &ehci_device_bulk_methods) {
 
 		parm->hc_max_packet_size = 0x400;
@@ -3664,6 +3765,8 @@
 		nqtd = ((2 * xfer->nframes)
 		    + (xfer->max_data_length / xfer->max_usb_frame_size));
 
+		xfer->flags_int.bdma_enable = 1;
+
 	} else if (parm->methods == &ehci_device_intr_methods) {
 
 		if (parm->speed == USB_SPEED_HIGH) {
@@ -3685,6 +3788,8 @@
 		nqtd = ((2 * xfer->nframes)
 		    + (xfer->max_data_length / xfer->max_usb_frame_size));
 
+		xfer->flags_int.bdma_enable = 1;
+
 	} else if (parm->methods == &ehci_device_isoc_fs_methods) {
 
 		parm->hc_max_packet_size = 0x3FF;
@@ -3695,6 +3800,8 @@
 
 		nsitd = xfer->nframes;
 
+		xfer->flags_int.bdma_enable = 1;
+
 	} else if (parm->methods == &ehci_device_isoc_hs_methods) {
 
 		parm->hc_max_packet_size = 0x400;
@@ -3705,6 +3812,8 @@
 
 		nitd = (xfer->nframes + 7) / 8;
 
+		xfer->flags_int.bdma_enable = 1;
+
 	} else {
 
 		parm->hc_max_packet_size = 0x400;
@@ -3718,138 +3827,126 @@
 		return;
 	}
 	/*
-	 * memory is allocated at highest alignment which is first
+	 * Allocate queue heads and transfer descriptors
 	 */
-	if (nitd) {
-		/* align data */
-		parm->size[1] += ((-parm->size[1]) & (EHCI_ITD_ALIGN - 1));
-	}
-	if (nsitd) {
-		/* align data */
-		parm->size[1] += ((-parm->size[1]) & (EHCI_SITD_ALIGN - 1));
-	}
-	if (nqtd) {
-		/* align data */
-		parm->size[1] += ((-parm->size[1]) & (EHCI_QTD_ALIGN - 1));
-	}
 	last_obj = NULL;
 
-	for (n = 0; n < nitd; n++) {
-
-		parm->size[1] += usbd_page_fit_obj(parm->size[1], sizeof(ehci_itd_t));
+	for (n = 0; n != nitd; n++) {
 
 		if (parm->buf) {
 
 			register ehci_itd_t *td;
 
-			usbd_get_page(&(parm->pc), parm->size[1], &page_info);
-
-			usbd_page_cpu_invalidate(page_info.page);
-
+			if (ehci_dma_alloc_mem(parm, sizeof(*td),
+			    EHCI_ITD_ALIGN, &page_info)) {
+				parm->err = USBD_NOMEM;
+				break;
+			}
 			td = page_info.buffer;
 
 			/* init TD */
 			td->itd_self = htole32(page_info.physaddr | EHCI_LINK_ITD);
 			td->obj_next = last_obj;
-			td->page = page_info.page;
+			td->page_cache = parm->dma_page_cache_ptr;
 
 			last_obj = td;
 
-			usbd_page_cpu_flush(page_info.page);
+			usbd_pc_cpu_flush(parm->dma_page_cache_ptr);

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list