Commit 4f650496 authored by Alan Stern's avatar Alan Stern Committed by Deepak Saxena

[PATCH] USB: Even out distribution of UHCI interrupt transfers

This patch evens out the distribution of interrupt transfers for the UHCI
driver.  It insures that no frame must handle interrupt queues for more
than two different periods, thus improving the bandwidth utilization.

It also simplifies the initialization code by replacing a multi-nested
"if" statement with a simple bit-operation (thanks to Eric Piel for
suggesting this approach).
parent a0afbda3
......@@ -418,7 +418,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
{
unsigned long flags;
char *out = buf;
int i;
int i, j;
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
......@@ -473,10 +473,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
continue;
}
j = (i < 7) ? 7 : i+1; /* Next skeleton */
if (list_empty(&qh->list)) {
if (i < UHCI_NUM_SKELQH - 1) {
if (qh->link !=
(cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH)) {
(cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
show_qh_name();
out += sprintf(out, " skeleton QH not linked to next skeleton QH!\n");
}
......@@ -500,7 +501,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (i < UHCI_NUM_SKELQH - 1) {
if (qh->link !=
(cpu_to_le32(uhci->skelqh[i + 1]->dma_handle) | UHCI_PTR_QH))
(cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
out += sprintf(out, " last QH not linked to next skeleton!\n");
}
}
......
......@@ -48,6 +48,7 @@
#endif
#include <linux/usb.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
......@@ -2316,16 +2317,17 @@ static int uhci_start(struct usb_hcd *hcd)
}
/*
* 8 Interrupt queues; link int2 to int1, int4 to int2, etc
* 8 Interrupt queues; link all higher int queues to int1,
* then link int1 to control and control to bulk
*/
uhci->skel_int128_qh->link = cpu_to_le32(uhci->skel_int64_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int64_qh->link = cpu_to_le32(uhci->skel_int32_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int32_qh->link = cpu_to_le32(uhci->skel_int16_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int16_qh->link = cpu_to_le32(uhci->skel_int8_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int8_qh->link = cpu_to_le32(uhci->skel_int4_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int4_qh->link = cpu_to_le32(uhci->skel_int2_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int2_qh->link = cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int128_qh->link =
uhci->skel_int64_qh->link =
uhci->skel_int32_qh->link =
uhci->skel_int16_qh->link =
uhci->skel_int8_qh->link =
uhci->skel_int4_qh->link =
uhci->skel_int2_qh->link =
cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH;
......@@ -2341,39 +2343,33 @@ static int uhci_start(struct usb_hcd *hcd)
uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
/*
* Fill the frame list: make all entries point to
* the proper interrupt queue.
* Fill the frame list: make all entries point to the proper
* interrupt queue.
*
* This is probably silly, but it's a simple way to
* scatter the interrupt queues in a way that gives
* us a reasonable dynamic range for irq latencies.
* The interrupt queues will be interleaved as evenly as possible.
* There's not much to be done about period-1 interrupts; they have
* to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
int irq = 0;
if (i & 1) {
irq++;
if (i & 2) {
irq++;
if (i & 4) {
irq++;
if (i & 8) {
irq++;
if (i & 16) {
irq++;
if (i & 32) {
irq++;
if (i & 64)
irq++;
}
}
}
}
}
}
int irq;
/*
* ffs (Find First bit Set) does exactly what we need:
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[6],
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
* ffs > 6 => not on any high-period queue, so use
* skel_int1_qh = skelqh[7].
* Add UHCI_NUMFRAMES to insure at least one bit is set.
*/
irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
if (irq < 0)
irq = 7;
/* Only place we don't use the frame list routines */
uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[7 - irq]->dma_handle);
uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle);
}
start_hc(uhci);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment