Fwd: [musb] A few questions regarding musb host code when shared fifo is used

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---------- Forwarded message ----------
From:  <linux-usb-devel-owner@xxxxxxxxxxxxxxxxxxxxx>
Date: Thu, Jan 28, 2010 at 11:28 AM
Subject: [musb] A few questions regarding musb host code when shared
fifo is used
To: freeman.wang@xxxxxxxxx


This list is now closed.

Please post to the linux-usb list as described at
http://vger.kernel.org/vger-lists.html#linux-usb instead.



---------- Forwarded message ----------
From: Freeman Wang <freeman.wang@xxxxxxxxx>
To: linux-usb-devel@xxxxxxxxxxxxxxxxxxxxx
Date: Thu, 28 Jan 2010 11:27:47 -0800
Subject: [musb] A few questions regarding musb host code when shared
fifo is used
Hi


I just started working on musb and hope to get help from the group on
a few questions.


The code shows this in function musb_advance_schedule() of kernel 2.6.31.6


c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  359) static void
musb_advance_schedule(struct musb *musb, struct urb *urb,
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  360)
                  struct musb_hw_ep *hw_ep, int is_in)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  361) {
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  362)      struct
musb_qh          *qh = musb_ep_get_qh(hw_ep, is_in);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  363)      struct
musb_hw_ep       *ep = qh->hw_ep;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  364)      int
                ready = qh->is_ready;
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  365)      int
                status;
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  366)
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  367)      status
= (urb->status == -EINPROGRESS) ? 0 : urb->status;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  368)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  369)      /*
save toggle eagerly, for paranoia */
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  370)      switch
(qh->type) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  371)      case
USB_ENDPOINT_XFER_BULK:
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  372)      case
USB_ENDPOINT_XFER_INT:
846099a6 (Sergei Shtylyov  2009-03-27 12:54:21 -0700  373)
 musb_save_toggle(qh, is_in, urb);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  374)              break;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  375)      case
USB_ENDPOINT_XFER_ISOC:
1fe975f9 (Sergei Shtylyov  2009-07-10 20:02:44 +0300  376)
 if (status == 0 && urb->error_count)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  377)
        status = -EXDEV;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  378)              break;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  379)      }
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  380)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  381)
qh->is_ready = 0;
c9cd06b3 (Sergei Shtylyov  2009-03-27 12:58:31 -0700  382)
musb_giveback(musb, urb, status);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  383)
qh->is_ready = ready;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  384)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  385)      /*
reclaim resources (and bandwidth) ASAP; deschedule it, and
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  386)       *
invalidate qh as soon as list_empty(&hep->urb_list)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  387)       */
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  388)      if
(list_empty(&qh->hep->urb_list)) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  389)
 struct list_head        *head;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  390)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  391)
 if (is_in)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  392)
        ep->rx_reinit = 1;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  393)              else
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  394)
        ep->tx_reinit = 1;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  395)



My understanding of this piece of code is: after the last urb in a
host_endpoint urb_list is finished, we need to reinit the endpoint
when picking up the next possible qh.  However, there is only a
musb_rx_reinit() implemented in the code ever since Felipe initially
checked in the first version of this code, and tx_reinit has never
been there. What confuses me most is, if rx_reinit (cleanup) is
necessary, why tx_reinit is not? Is it possible the hw_ep be switched
from tx to rx or rx to tx? Maybe in the bulk out case, the endpoint
never gets stuck and we do not need to save the states, but do we need
some kind of mode switch when fifo is shared?


The chip I work on is using shared fifo for every endpoint. And this
is another code snippet from the same file.


550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  558)
musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct
musb_hw_ep *ep)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  559) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  560)      u16     csr;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  561)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  562)      /*
NOTE:  we know the "rx" fifo reinit never triggers for ep0.
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  563)       *
That always uses tx_reinit since ep0 repurposes TX register
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  564)       *
offsets; the initial SETUP packet is also a kind of OUT.
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  565)       */
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  566)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  567)      /* if
programmed for Tx, put it in RX mode */
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  568)      if
(ep->is_shared_fifo) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  569)
 csr = musb_readw(ep->regs, MUSB_TXCSR);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  570)
 if (csr & MUSB_TXCSR_MODE) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  571)
        musb_h_tx_flush_fifo(ep);
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  572)
        csr = musb_readw(ep->regs, MUSB_TXCSR);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  573)
        musb_writew(ep->regs, MUSB_TXCSR,
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  574)
                    csr | MUSB_TXCSR_FRCDATATOG);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  575)              }
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  576)
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  577)              /*
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  578)
 * Clear the MODE bit (and everything else) to enable Rx.
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  579)
 * NOTE: we mustn't clear the DMAMODE bit before DMAENAB.
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  580)               */
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  581)
 if (csr & MUSB_TXCSR_DMAMODE)
b6e434a5 (Sergei Shtylyov  2009-03-26 18:27:47 -0700  582)
        musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  583)
 musb_writew(ep->regs, MUSB_TXCSR, 0);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  584)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  585)      /*
scrub all previous state, clearing toggle */
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  586)      } else {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  587)
 csr = musb_readw(ep->regs, MUSB_RXCSR);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  588)
 if (csr & MUSB_RXCSR_RXPKTRDY)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  589)
        WARNING("rx%d, packet/%d ready?\n", ep->epnum,
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  590)
                musb_readw(ep->regs, MUSB_RXCOUNT));
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  591)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  592)
 musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  593)      }
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300  594)


If it is not using shared fifo, we will clear the rxfifo, which makes
a lot sense to me. But if the ep is configured to use shared fifo,
shouldn’t we clear the rx fifo too? The last urb is very possible to
be an IN transfer.


Felipe told me that he thought rx actually uses tx fifo but he never
actually tested it on a shared fifo chip, so he recommended me to ask
the group for help. I checked the code and found there are only two
cases is_shared_fifo is checked in the host mode, excepting selecting
the qh. One is in musb_core.c when deciding the fifo size, the other
is the above musb_rx_reinit() function. It does not seem to be the
case that we use TXCSR and tx fifo for rx processing in the .31 code,
maybe long time ago.

My third question came up when I read the function musb_schedule().

23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1813)      /* use
bulk reserved ep1 if no other ep is free */
aa5cbbec (Felipe Balbi     2008-11-17 09:08:16 +0200 1814)      if
(best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1815)
 hw_ep = musb->bulk_ep;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1816)
 if (is_in)
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1817)
        head = &musb->in_bulk;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1818)              else
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1819)
        head = &musb->out_bulk;
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1820)
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1821)
 /* Enable bulk RX NAK timeout scheme when bulk requests are
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1822)
 * multiplexed.  This scheme doen't work in high speed to full
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1823)
 * speed scenario as NAK interrupts are not coming from a
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1824)
 * full speed device connected to a high speed device.
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1825)
 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1826)
 * 4 (8 frame or 8ms) for FS device.
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1827)               */
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1828)
 if (is_in && qh->dev)
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1829)
        qh->intv_reg =
1e0320f0 (Ajay Kumar Gupta 2009-02-24 15:26:13 -0800 1830)
                (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1831)
 goto success;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1832)      } else
if (best_end < 0) {
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1833)
 return -ENOSPC;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1834)      }
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1835)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1836)      idle = 1;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1837)      qh->mux = 0;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1838)      hw_ep
= musb->endpoints + best_end;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1839)      DBG(4,
"qh %p periodic slot %d\n", qh, best_end);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1840) success:
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1841)      if (head) {
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1842)
 idle = list_empty(head);
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1843)
 list_add_tail(&qh->ring, head);
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1844)
 qh->mux = 1;
23d15e07 (Ajay Kumar Gupta 2008-10-29 15:10:35 +0200 1845)      }
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1846)
qh->hw_ep = hw_ep;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1847)
qh->hep->hcpriv = qh;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1848)      if (idle)
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1849)
 musb_start_urb(musb, is_in, qh);
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1850)      return 0;
550a7375 (Felipe Balbi     2008-07-24 12:27:36 +0300 1851) }

Again, it seems very confusing when shared fifo is used. In the case
of dedicated fifo, the bulk endpoint actually has two independant set
of registers, it is fine. However, if the bulk endpoint is using
shared fifo,  I'm afraid it will mess the hw_ep up.

Say, I have a few qhs backloged in the in_bulk list and out_bulk is
empty. If a new BULK OUT urb comes in, it will set head to out_bulk at
line 1819 and move to line 1842 where idle is set to 1 because
out_bulk is empty. Then at line 1848, idle is evaluated to be true and
musb_start_urb is called. That will cause TXCSR to be written and
switch the endpoint to TX mode. I'm afraid it will mess the internal
states up, at least allow the shared fifo to be filled with the
outgoing data while the IN transfers are still alive.

It could be a big change to fix if my analysis right. Given that I’ve
only worked on musb code for about a week, I really doubt my capability
and hope to get help/suggestions from those who are more familiar with
this chip.

Thanks a lot.
Freeman
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux