[PATCH 1/4] USB ehci: make cache handling simpler

Sascha Hauer s.hauer at pengutronix.de
Thu Apr 12 15:40:02 EDT 2012


for chache handling the ehci driver iterates over the hardware lists
of QHs/TDs. As we have a fixed number of maximum entries in this lists
we can allocate them as arrays and and clean/invalidate the arrays
instead which is much simpler. While at it, move the allocation to
ehci_probe so that we do not lose memory each time ehci_init is called.
Also, use memalign to allocate the QHs/TDs.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/usb/host/ehci-hcd.c |   96 ++++++++++++++-----------------------------
 1 file changed, 30 insertions(+), 66 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 81e3a42..505d919 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -42,13 +42,16 @@ struct ehci_priv {
 	struct ehci_hcor *hcor;
 	struct usb_host host;
 	struct QH *qh_list;
-	void *qhp;
+	struct qTD *td;
 	int portreset;
 	unsigned long flags;
 };
 
 #define to_ehci(ptr) container_of(ptr, struct ehci_priv, host)
 
+#define NUM_QH	2
+#define NUM_TD	3
+
 static struct descriptor {
 	struct usb_hub_descriptor hub;
 	struct usb_device_descriptor device;
@@ -125,10 +128,11 @@ static struct descriptor {
  */
 static void flush_invalidate(void *addr, int size, int flush)
 {
-	if (flush)
+	if (flush) {
 		dma_flush_range((unsigned long)addr, (unsigned long)(addr + size));
-	else
+	} else {
 		dma_inv_range((unsigned long)addr, (unsigned long)(addr + size));
+	}
 }
 
 static void cache_qtd(struct qTD *qtd, int flush)
@@ -136,76 +140,39 @@ static void cache_qtd(struct qTD *qtd, int flush)
 	u32 *ptr = (u32 *)qtd->qt_buffer[0];
 	int len = (qtd->qt_token & 0x7fff0000) >> 16;
 
-	flush_invalidate(qtd, sizeof(struct qTD), flush);
 	if (ptr && len)
 		flush_invalidate(ptr, len, flush);
 }
 
-
-static inline struct QH *qh_addr(struct QH *qh)
+static void cache_qh(struct ehci_priv *ehci, int flush)
 {
-	return (struct QH *)((u32)qh & 0xffffffe0);
-}
-
-static void cache_qh(struct QH *qh, int flush)
-{
-	struct qTD *qtd;
-	struct qTD *next;
-	static struct qTD *first_qtd;
-
-	/*
-	 * Walk the QH list and flush/invalidate all entries
-	 */
-	while (1) {
-		flush_invalidate(qh_addr(qh), sizeof(struct QH), flush);
-		if ((u32)qh & QH_LINK_TYPE_QH)
-			break;
-		qh = qh_addr(qh);
-		qh = (struct QH *)qh->qh_link;
-	}
-	qh = qh_addr(qh);
+	int i;
 
-	/*
-	 * Save first qTD pointer, needed for invalidating pass on this QH
-	 */
-	if (flush)
-		first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
-						 0xffffffe0);
-	else
-		qtd = first_qtd;
+	flush_invalidate(ehci->qh_list, sizeof(struct QH) * NUM_QH, flush);
+	flush_invalidate(ehci->td, sizeof(struct qTD) * NUM_TD, flush);
 
-	/*
-	 * Walk the qTD list and flush/invalidate all entries
-	 */
-	while (1) {
-		if (qtd == NULL)
-			break;
-		cache_qtd(qtd, flush);
-		next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
-		if (next == qtd)
-			break;
-		qtd = next;
-	}
+	for (i = 0; i < NUM_TD; i ++)
+		cache_qtd(&ehci->td[i], flush);
 }
 
-static inline void ehci_flush_dcache(struct QH *qh)
+static inline void ehci_flush_dcache(struct ehci_priv *ehci)
 {
-	cache_qh(qh, 1);
+	cache_qh(ehci, 1);
 }
 
-static inline void ehci_invalidate_dcache(struct QH *qh)
+static inline void ehci_invalidate_dcache(struct ehci_priv *ehci)
 {
-	cache_qh(qh, 0);
+	cache_qh(ehci, 0);
 }
 #else /* CONFIG_MMU */
 /*
  *
  */
-static inline void ehci_flush_dcache(struct QH *qh)
+static inline void ehci_flush_dcache(struct ehci_priv *ehci)
 {
 }
 
-static inline void ehci_invalidate_dcache(struct QH *qh)
+static inline void ehci_invalidate_dcache(struct ehci_priv *ehci)
 {
 }
 #endif /* CONFIG_MMU */
@@ -299,8 +266,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t cmd;
 	int ret = 0;
 	uint64_t start, timeout_val;
-	static struct QH __qh __attribute__((aligned(32)));
-	static struct qTD __td[3] __attribute__((aligned(32)));
 
 	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
 	      buffer, length, req);
@@ -311,10 +276,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		      le16_to_cpu(req->value), le16_to_cpu(req->value),
 		      le16_to_cpu(req->index));
 
-	memset(&__qh, 0, sizeof(struct QH));
-	memset(&__td, 0, sizeof(struct qTD) * 3);
+	memset(&ehci->qh_list[1], 0, sizeof(struct QH));
+	memset(ehci->td, 0, sizeof(struct qTD) * NUM_TD);
 
-	qh = &__qh;
+	qh = &ehci->qh_list[1];
 	qh->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH);
 	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
 	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
@@ -341,7 +306,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	    usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
 	if (req != NULL) {
-		td = &__td[0];
+		td = &ehci->td[0];
 
 		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -360,7 +325,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	if (length > 0 || req == NULL) {
-		td = &__td[1];
+		td = &ehci->td[1];
 
 		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -380,7 +345,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	}
 
 	if (req) {
-		td = &__td[2];
+		td = &ehci->td[2];
 
 		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
 		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -398,7 +363,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	ehci->qh_list->qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
 
 	/* Flush dcache */
-	ehci_flush_dcache(ehci->qh_list);
+	ehci_flush_dcache(ehci);
 
 	usbsts = ehci_readl(&ehci->hcor->or_usbsts);
 	ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f));
@@ -420,7 +385,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 	vtd = td;
 	do {
 		/* Invalidate dcache */
-		ehci_invalidate_dcache(ehci->qh_list);
+		ehci_invalidate_dcache(ehci);
 		token = hc32_to_cpu(vtd->qt_token);
 		if (is_timeout(start, timeout_val)) {
 			/* Disable async schedule. */
@@ -802,10 +767,6 @@ static int ehci_init(struct usb_host *host)
 	if (ehci_reset(ehci) != 0)
 		return -1;
 
-	/* Set head of reclaim list */
-	ehci->qhp = xzalloc(sizeof(struct QH) + 32);
-	ehci->qh_list = (struct QH *)(((unsigned long)ehci->qhp + 32) & ~31);
-
 	ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH);
 	ehci->qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
 	ehci->qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
@@ -917,6 +878,9 @@ static int ehci_probe(struct device_d *dev)
 	ehci->hccr = dev_request_mem_region(dev, 0);
 	ehci->hcor = dev_request_mem_region(dev, 1);
 
+	ehci->qh_list = xmemalign(32, sizeof(struct QH) * NUM_QH);
+	ehci->td = xmemalign(32, sizeof(struct qTD) * NUM_TD);
+
 	host->init = ehci_init;
 	host->submit_int_msg = submit_int_msg;
 	host->submit_control_msg = submit_control_msg;
-- 
1.7.10




More information about the barebox mailing list