linux-2.6.18/drivers/usb/musb/musb_host.c
@@ -269,6 +269,11 @@
else
musb->intr_hold = 1;
}
+
+ qh->interval = urb->interval;
+ if ((musb->port1_status & USB_PORT_STAT_HIGH_SPEED) &&
+ urb->dev->speed != USB_SPEED_HIGH)
+ qh->interval *= 8;
}
/* FALLTHROUGH */
#endif /* CONFIG_MUSB_SCHEDULE_INTR_EP */
@@ -341,8 +346,6 @@
__releases(musb->lock)
__acquires(musb->lock)
{
- struct musb_qh *qh = urb->hcpriv;
-
if ((urb->transfer_flags & URB_SHORT_NOT_OK)
&& (urb->actual_length < urb->transfer_buffer_length)
&& status == 0
@@ -350,10 +353,8 @@
status = -EREMOTEIO;
spin_lock(&urb->lock);
-
urb->hcpriv = NULL;
- if (urb->status == -EINPROGRESS ||
- (musb->intr_ep == qh->hw_ep && urb->status == -EPROTO))
+ if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock(&urb->lock);
@@ -507,9 +508,10 @@
static void musb_host_intr_schedule(struct musb *musb)
{
struct musb_hw_ep *hw_ep = musb->intr_ep;
+ void __iomem *epio = hw_ep->regs;
struct urb *purb, *hurb = NULL;
struct musb_qh *pqh, *hqh = NULL;
- u16 csr = 0;
+ u16 csr;
/*
* Hold the current interrupt request until the IN token is sent to
@@ -517,50 +519,44 @@
* for scheduling other device's interrupt requests.
*/
if (musb->intr_hold != 0 && --musb->intr_hold == 0) {
- csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
-
+ csr = musb_readw(epio, MUSB_RXCSR);
csr &= ~(MUSB_RXCSR_H_ERROR | MUSB_RXCSR_DATAERROR |
MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_REQPKT);
/* Avoid clearing RXPKTRDY */
- musb_writew(hw_ep->regs, MUSB_RXCSR, csr | MUSB_RXCSR_RXPKTRDY);
+ musb_writew(epio, MUSB_RXCSR, csr | MUSB_RXCSR_RXPKTRDY);
}
- list_for_each_entry(pqh, &musb->in_intr, ring)
- list_for_each_entry(purb, &pqh->hep->urb_list, urb_list) {
-
- if (purb->number_of_packets)
- purb->number_of_packets--;
- /*
- * If a contention occurs in the same frame period
- * between several Interrupt requests expiring
- * then look for speed as the primary yardstick.
- * If they are of the same speed then look for the
- * lesser polling interval request.
- */
- if (purb->number_of_packets <= 0 && !musb->intr_hold &&
- purb->status != -EPROTO) {
- if (hurb) {
- if (hurb->dev->speed ==
- purb->dev->speed) {
- if (hurb->interval <=
- purb->interval)
- continue;
- } else if (hurb->dev->speed >
- purb->dev->speed)
+ list_for_each_entry(pqh, &musb->in_intr, ring) {
+ if (pqh->interval)
+ pqh->interval--;
+ /*
+ * If a contention occurs in the same frame period
+ * between several Interrupt requests expiring
+ * then look for speed as the primary yardstick.
+ * If they are of the same speed then look for the
+ * lesser polling interval request.
+ */
+ if (pqh->interval <= 0 && musb->intr_hold == 0) {
+ purb = next_urb(pqh);
+ if (hurb) {
+ if (hurb->dev->speed == purb->dev->speed) {
+ if (hurb->interval <= purb->interval)
continue;
- }
- hurb = purb;
- hqh = pqh;
+ } else if (hurb->dev->speed > purb->dev->speed)
+ continue;
}
+ hurb = purb;
+ hqh = pqh;
}
+ }
/*
* If a request is chosen to be scheduled, check to see if RXPKTRDY
* is set. If so, delay until this can be processed by the driver.
*/
if (hqh && hurb) {
- csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
+ csr = musb_readw(epio, MUSB_RXCSR);
if (csr & MUSB_RXCSR_RXPKTRDY)
return;
@@ -569,14 +565,6 @@
if (pqh)
musb_save_toggle(pqh, 1, next_urb(pqh));
- if (hurb->urb_list.prev != &hqh->hep->urb_list)
- list_move(&hurb->urb_list, &hqh->hep->urb_list);
-
- hurb->number_of_packets = hurb->interval;
- if ((musb->port1_status & USB_PORT_STAT_HIGH_SPEED) &&
- hurb->dev->speed != USB_SPEED_HIGH)
- hurb->number_of_packets *= 8;
-
hw_ep->rx_reinit = 1;
musb_start_urb(musb, 1, hqh);
}
@@ -840,7 +828,6 @@
void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out);
u16 packet_sz = qh->maxpacket;
- int need_dma = 1;
DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d\n",
@@ -850,16 +837,17 @@
qh->h_addr_reg, qh->h_port_reg,
len);
-#ifdef CONFIG_MUSB_SCHEDULE_INTR_EP
- if (qh->type == USB_ENDPOINT_XFER_INT)
- need_dma = 0;
-#endif
-
musb_ep_select(mbase, epnum);
/* candidate for DMA? */
dma_controller = musb->dma_controller;
- if (is_dma_capable() && epnum && dma_controller && need_dma) {
+#ifdef CONFIG_MUSB_SCHEDULE_INTR_EP
+ if (qh->type == USB_ENDPOINT_XFER_INT)
+ /* Interrupt EP scheduling fails at least with CPPI DMA */
+ dma_channel = NULL;
+ else
+#endif
+ if (is_dma_capable() && epnum && dma_controller) {
dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
if (!dma_channel) {
dma_channel = dma_controller->channel_alloc(
@@ -1902,14 +1890,6 @@
finish:
urb->actual_length += xfer_len;
qh->offset += xfer_len;
-
-#ifdef CONFIG_MUSB_SCHEDULE_INTR_EP
- if (hw_ep == musb->intr_ep && status == -EPROTO) {
- urb->status = status;
- return;
- }
-#endif
-
if (done) {
if (urb->status == -EINPROGRESS)
urb->status = status;
@@ -2071,15 +2051,6 @@
if (!is_host_active(musb) || !musb->is_active)
return -ENODEV;
-#ifdef CONFIG_MUSB_SCHEDULE_INTR_EP
- if (usb_pipeint(urb->pipe) && usb_pipein(urb->pipe)) {
- urb->number_of_packets = urb->interval;
- if ((musb->port1_status & USB_PORT_STAT_HIGH_SPEED) &&
- urb->dev->speed != USB_SPEED_HIGH)
- urb->number_of_packets *= 8;
- }
-#endif
-
/* DMA mapping was already done, if needed, and this urb is on
* hep->urb_list ... so there's little to do unless hep wasn't
* yet scheduled onto a live qh.
linux-2.6.18/drivers/usb/musb/musb_host.h
@@ -81,6 +81,9 @@
u16 maxpacket;
u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */
+#ifdef CONFIG_MUSB_SCHEDULE_INTR_EP
+ int interval;
+#endif
};
/* map from control or bulk queue head to the first qh on that ring */