From a1d59ce842a35b552f22868404e4e7c923242257 Mon Sep 17 00:00:00 2001
From: Alan Stern <stern@rowland.harvard.edu>
Date: Fri, 16 Sep 2005 14:22:51 -0400
Subject: [PATCH] USB: UHCI: Split apart the physical and logical framelist
 arrays

This patch (as563) splits the physical and logical framelist arrays in
uhci-hcd into two separate pieces.  This will allow slightly better memory
utilization, since each piece is no larger than a single page whereas
before the whole thing was a little bigger than two pages.  It also allows
the logical array to be allocated in non-DMA-coherent memory.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/usb/host/uhci-debug.c |  4 ++--
 drivers/usb/host/uhci-hcd.c   | 42 +++++++++++++++++++++++++++---------------
 drivers/usb/host/uhci-hcd.h   |  6 +++++-
 drivers/usb/host/uhci-q.c     | 20 ++++++++++----------
 4 files changed, 44 insertions(+), 28 deletions(-)

(limited to 'drivers')

diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 04eddd7..151154d 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -445,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 		int shown = 0;
-		td = uhci->fl->frame_cpu[i];
+		td = uhci->frame_cpu[i];
 		if (!td)
 			continue;
 
-		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
+		if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
 			show_frame_num();
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
 		}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 17de9ee..b44094f 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -212,7 +212,7 @@ static void configure_hc(struct uhci_hcd *uhci)
 	outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
 	/* Store the frame list base address */
-	outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
+	outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
 
 	/* Set the current frame number */
 	outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
@@ -445,8 +445,11 @@ static void release_uhci(struct uhci_hcd *uhci)
 
 	dma_pool_destroy(uhci->td_pool);
 
-	dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-			uhci->fl, uhci->fl->dma_handle);
+	kfree(uhci->frame_cpu);
+
+	dma_free_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			uhci->frame, uhci->frame_dma_handle);
 
 	debugfs_remove(uhci->dentry);
 }
@@ -527,7 +530,6 @@ static int uhci_start(struct usb_hcd *hcd)
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	int retval = -EBUSY;
 	int i;
-	dma_addr_t dma_handle;
 	struct dentry *dentry;
 
 	hcd->uses_new_polling = 1;
@@ -561,17 +563,23 @@ static int uhci_start(struct usb_hcd *hcd)
 
 	init_waitqueue_head(&uhci->waitqh);
 
-	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-			&dma_handle, 0);
-	if (!uhci->fl) {
+	uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			&uhci->frame_dma_handle, 0);
+	if (!uhci->frame) {
 		dev_err(uhci_dev(uhci), "unable to allocate "
 				"consistent memory for frame list\n");
-		goto err_alloc_fl;
+		goto err_alloc_frame;
 	}
+	memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame));
 
-	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
-
-	uhci->fl->dma_handle = dma_handle;
+	uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu),
+			GFP_KERNEL);
+	if (!uhci->frame_cpu) {
+		dev_err(uhci_dev(uhci), "unable to allocate "
+				"memory for frame pointers\n");
+		goto err_alloc_frame_cpu;
+	}
 
 	uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
 			sizeof(struct uhci_td), 16, 0);
@@ -654,7 +662,7 @@ static int uhci_start(struct usb_hcd *hcd)
 			irq = 7;
 
 		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] = UHCI_PTR_QH |
+		uhci->frame[i] = UHCI_PTR_QH |
 				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
 	}
 
@@ -686,10 +694,14 @@ err_create_qh_pool:
 	dma_pool_destroy(uhci->td_pool);
 
 err_create_td_pool:
-	dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-			uhci->fl, uhci->fl->dma_handle);
+	kfree(uhci->frame_cpu);
+
+err_alloc_frame_cpu:
+	dma_free_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			uhci->frame, uhci->frame_dma_handle);
 
-err_alloc_fl:
+err_alloc_frame:
 	debugfs_remove(uhci->dentry);
 
 err_create_debug_entry:
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1c161b4..b04d99d 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -359,7 +359,11 @@ struct uhci_hcd {
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
 	spinlock_t lock;
-	struct uhci_frame_list *fl;		/* P: uhci->lock */
+
+	dma_addr_t frame_dma_handle;		/* Hardware frame list */
+	__le32 *frame;				/* P: uhci->lock */
+	void **frame_cpu;			/* CPU's frame list */
+
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index d540382..51de06b 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
 	td->frame = framenum;
 
 	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
+	if (uhci->frame_cpu[framenum]) {
 		struct uhci_td *ftd, *ltd;
 
-		ftd = uhci->fl->frame_cpu[framenum];
+		ftd = uhci->frame_cpu[framenum];
 		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
 
 		list_add_tail(&td->fl_list, &ftd->fl_list);
@@ -101,10 +101,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
 		wmb();
 		ltd->link = cpu_to_le32(td->dma_handle);
 	} else {
-		td->link = uhci->fl->frame[framenum];
+		td->link = uhci->frame[framenum];
 		wmb();
-		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
-		uhci->fl->frame_cpu[framenum] = td;
+		uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
+		uhci->frame_cpu[framenum] = td;
 	}
 }
 
@@ -114,16 +114,16 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
 	if (td->frame == -1 && list_empty(&td->fl_list))
 		return;
 
-	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+	if (td->frame != -1 && uhci->frame_cpu[td->frame] == td) {
 		if (list_empty(&td->fl_list)) {
-			uhci->fl->frame[td->frame] = td->link;
-			uhci->fl->frame_cpu[td->frame] = NULL;
+			uhci->frame[td->frame] = td->link;
+			uhci->frame_cpu[td->frame] = NULL;
 		} else {
 			struct uhci_td *ntd;
 
 			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-			uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
-			uhci->fl->frame_cpu[td->frame] = ntd;
+			uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+			uhci->frame_cpu[td->frame] = ntd;
 		}
 	} else {
 		struct uhci_td *ptd;
-- 
cgit v1.1