Hello.

On 06-03-2013 8:45, B, Ravi wrote:

     All bulk endpoint transfers are sheduled using the single MUSB EP 1,
AFAIR.

2.  Is there a software work around ("Interrupt endpoint scheduling")
that works with devices that need Interrupt EPs?  If so what kernel
version do I need?

"Interrupt endpoint scheduling" was implemented for very early v2.6.10
based MV kernels that TI used to ship. Recently Ravi up-ported that to
v3.3 but was only tested it on DA850 as per my knowledge. Here is the
link:
http://arago-project.org/git/projects/?p=linux-davinci.git;a=commit;h=0795c14aa91650d778a27fe7b2ef23e2d9ff8c89

     This code seems to have the same mistake I fixed for 2.6.18 MV release
--
it tries to schedule several URBs concurrently on the same endpoint. It
seems
TI engineers have learned nothing from my work. :-(

Is there different approach to this ? Can you explain in detail ?

You can't execute several URBs to one endpoint in parallel, trying to "interleave" them -- that's totally incorrect. Please find the sources of 2.6.18 based TI PSP and compare with your 3.3 code. Although, here's the changes I did to the original interrupt scheduling patch (extracted from so called patch #47) back then:

diff -u linux-2.6.18/drivers/usb/musb/musb_host.c linux-2.6.18/drivers/usb/musb/musb_host.c
--- linux-2.6.18/drivers/usb/musb/musb_host.c
+++ 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.
diff -u linux-2.6.18/drivers/usb/musb/musb_host.h linux-2.6.18/drivers/usb/musb/musb_host.h
--- linux-2.6.18/drivers/usb/musb/musb_host.h
+++ 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 */

--
Ravi B

WBR, Sergei

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to