[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>
This commit is contained in:
parent
8b4cd42134
commit
a1d59ce842
|
@ -445,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||||
out += sprintf(out, "Frame List\n");
|
out += sprintf(out, "Frame List\n");
|
||||||
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
|
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
|
||||||
int shown = 0;
|
int shown = 0;
|
||||||
td = uhci->fl->frame_cpu[i];
|
td = uhci->frame_cpu[i];
|
||||||
if (!td)
|
if (!td)
|
||||||
continue;
|
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();
|
show_frame_num();
|
||||||
out += sprintf(out, " frame list does not match td->dma_handle!\n");
|
out += sprintf(out, " frame list does not match td->dma_handle!\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,7 +212,7 @@ static void configure_hc(struct uhci_hcd *uhci)
|
||||||
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
|
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
|
||||||
|
|
||||||
/* Store the frame list base address */
|
/* 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 */
|
/* Set the current frame number */
|
||||||
outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
|
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_pool_destroy(uhci->td_pool);
|
||||||
|
|
||||||
dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
|
kfree(uhci->frame_cpu);
|
||||||
uhci->fl, uhci->fl->dma_handle);
|
|
||||||
|
dma_free_coherent(uhci_dev(uhci),
|
||||||
|
UHCI_NUMFRAMES * sizeof(*uhci->frame),
|
||||||
|
uhci->frame, uhci->frame_dma_handle);
|
||||||
|
|
||||||
debugfs_remove(uhci->dentry);
|
debugfs_remove(uhci->dentry);
|
||||||
}
|
}
|
||||||
|
@ -527,7 +530,6 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||||
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
|
||||||
int retval = -EBUSY;
|
int retval = -EBUSY;
|
||||||
int i;
|
int i;
|
||||||
dma_addr_t dma_handle;
|
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
hcd->uses_new_polling = 1;
|
hcd->uses_new_polling = 1;
|
||||||
|
@ -561,17 +563,23 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||||
|
|
||||||
init_waitqueue_head(&uhci->waitqh);
|
init_waitqueue_head(&uhci->waitqh);
|
||||||
|
|
||||||
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
|
uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
|
||||||
&dma_handle, 0);
|
UHCI_NUMFRAMES * sizeof(*uhci->frame),
|
||||||
if (!uhci->fl) {
|
&uhci->frame_dma_handle, 0);
|
||||||
|
if (!uhci->frame) {
|
||||||
dev_err(uhci_dev(uhci), "unable to allocate "
|
dev_err(uhci_dev(uhci), "unable to allocate "
|
||||||
"consistent memory for frame list\n");
|
"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->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu),
|
||||||
|
GFP_KERNEL);
|
||||||
uhci->fl->dma_handle = dma_handle;
|
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),
|
uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
|
||||||
sizeof(struct uhci_td), 16, 0);
|
sizeof(struct uhci_td), 16, 0);
|
||||||
|
@ -654,7 +662,7 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||||
irq = 7;
|
irq = 7;
|
||||||
|
|
||||||
/* Only place we don't use the frame list routines */
|
/* 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);
|
cpu_to_le32(uhci->skelqh[irq]->dma_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,10 +694,14 @@ err_create_qh_pool:
|
||||||
dma_pool_destroy(uhci->td_pool);
|
dma_pool_destroy(uhci->td_pool);
|
||||||
|
|
||||||
err_create_td_pool:
|
err_create_td_pool:
|
||||||
dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
|
kfree(uhci->frame_cpu);
|
||||||
uhci->fl, uhci->fl->dma_handle);
|
|
||||||
|
|
||||||
err_alloc_fl:
|
err_alloc_frame_cpu:
|
||||||
|
dma_free_coherent(uhci_dev(uhci),
|
||||||
|
UHCI_NUMFRAMES * sizeof(*uhci->frame),
|
||||||
|
uhci->frame, uhci->frame_dma_handle);
|
||||||
|
|
||||||
|
err_alloc_frame:
|
||||||
debugfs_remove(uhci->dentry);
|
debugfs_remove(uhci->dentry);
|
||||||
|
|
||||||
err_create_debug_entry:
|
err_create_debug_entry:
|
||||||
|
|
|
@ -359,7 +359,11 @@ struct uhci_hcd {
|
||||||
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
|
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
|
||||||
|
|
||||||
spinlock_t lock;
|
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 */
|
int fsbr; /* Full-speed bandwidth reclamation */
|
||||||
unsigned long fsbrtimeout; /* FSBR delay */
|
unsigned long fsbrtimeout; /* FSBR delay */
|
||||||
|
|
||||||
|
|
|
@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
|
||||||
td->frame = framenum;
|
td->frame = framenum;
|
||||||
|
|
||||||
/* Is there a TD already mapped there? */
|
/* Is there a TD already mapped there? */
|
||||||
if (uhci->fl->frame_cpu[framenum]) {
|
if (uhci->frame_cpu[framenum]) {
|
||||||
struct uhci_td *ftd, *ltd;
|
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);
|
ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
|
||||||
|
|
||||||
list_add_tail(&td->fl_list, &ftd->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();
|
wmb();
|
||||||
ltd->link = cpu_to_le32(td->dma_handle);
|
ltd->link = cpu_to_le32(td->dma_handle);
|
||||||
} else {
|
} else {
|
||||||
td->link = uhci->fl->frame[framenum];
|
td->link = uhci->frame[framenum];
|
||||||
wmb();
|
wmb();
|
||||||
uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
|
uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
|
||||||
uhci->fl->frame_cpu[framenum] = td;
|
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))
|
if (td->frame == -1 && list_empty(&td->fl_list))
|
||||||
return;
|
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)) {
|
if (list_empty(&td->fl_list)) {
|
||||||
uhci->fl->frame[td->frame] = td->link;
|
uhci->frame[td->frame] = td->link;
|
||||||
uhci->fl->frame_cpu[td->frame] = NULL;
|
uhci->frame_cpu[td->frame] = NULL;
|
||||||
} else {
|
} else {
|
||||||
struct uhci_td *ntd;
|
struct uhci_td *ntd;
|
||||||
|
|
||||||
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
|
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
|
||||||
uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
|
uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
|
||||||
uhci->fl->frame_cpu[td->frame] = ntd;
|
uhci->frame_cpu[td->frame] = ntd;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct uhci_td *ptd;
|
struct uhci_td *ptd;
|
||||||
|
|
Loading…
Reference in New Issue