linux/drivers/usb/musb
Thomas Gleixner c58d80f523 usb: musb: Ensure that cppi41 timer gets armed on premature DMA TX irq
Some TI chips raise the DMA complete interrupt before the actual
transfer has been completed. The code tries to busy wait for a few
microseconds and if that fails it arms an hrtimer to recheck. So far
so good, but that has the following issue:

CPU 0					CPU1

start_next_transfer(RQ1);

DMA interrupt
  if (premature_irq(RQ1))
    if (!hrtimer_active(timer))
       hrtimer_start(timer);

hrtimer expires
  timer->state = CALLBACK_RUNNING;
  timer->fn()
    cppi41_recheck_tx_req()
      complete_request(RQ1);
      if (requests_pending())
        start_next_transfer(RQ2);

					DMA interrupt
					  if (premature_irq(RQ2))
					    if (!hrtimer_active(timer))
					       hrtimer_start(timer);
  timer->state = INACTIVE;

The premature interrupt of request2 on CPU1 does not arm the timer and
therefor the request completion never happens because it checks for
!hrtimer_active(). hrtimer_active() evaluates:

  timer->state != HRTIMER_STATE_INACTIVE

which of course evaluates to true in the above case as timer->state is
CALLBACK_RUNNING.

That's clearly documented:

 * A timer is active, when it is enqueued into the rbtree or the
 * callback function is running or it's in the state of being migrated
 * to another cpu.

But that's not what the code wants to check. The code wants to check
whether the timer is queued, i.e. whether its armed and waiting for
expiry.

We have a helper function for this: hrtimer_is_queued(). This
evaluates:

  timer->state & HRTIMER_STATE_QUEUED

So in the above case this evaluates to false and therefor forces the
DMA interrupt on CPU1 to call hrtimer_start().

Use hrtimer_is_queued() instead of hrtimer_active() and evrything is
good.

Reported-by: Torben Hohn <torbenh@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Signed-off-by: Felipe Balbi <balbi@ti.com>
2014-06-27 10:53:37 -05:00
..
am35x.c usb: phy: generic: allow multiples calls to usb_phy_generic_register() 2014-04-21 14:07:25 -05:00
blackfin.c usb: phy: generic: allow multiples calls to usb_phy_generic_register() 2014-04-21 14:07:25 -05:00
blackfin.h
cppi_dma.c usb: musb: dma: merge ->start/stop into create/destroy 2013-07-29 13:53:18 +03:00
cppi_dma.h
da8xx.c usb: phy: generic: allow multiples calls to usb_phy_generic_register() 2014-04-21 14:07:25 -05:00
davinci.c usb: musb: move usb_phy_generic_{un,}register calls to probe()/remove() 2014-04-21 14:07:25 -05:00
davinci.h
jz4740.c usb: musb: add support for JZ4740 usb device controller 2013-12-20 09:53:24 -06:00
Kconfig usb: musb: omap2plus bus glue needs USB host support 2014-05-14 09:23:32 -05:00
Makefile usb: musb: add support for JZ4740 usb device controller 2013-12-20 09:53:24 -06:00
musb_am335x.c usb: musb: Fix panic upon musb_am335x module removal 2014-06-27 10:53:06 -05:00
musb_core.c usb: musb: core: Handle Babble condition only in HOST mode 2014-06-19 15:43:07 -05:00
musb_core.h usb: musb: tusb6010: Add tusb_revision to struct musb to store the revision. 2014-05-16 12:14:55 -05:00
musb_cppi41.c usb: musb: Ensure that cppi41 timer gets armed on premature DMA TX irq 2014-06-27 10:53:37 -05:00
musb_debug.h
musb_debugfs.c usb: remove use of __devinit 2012-11-21 13:27:16 -08:00
musb_dma.h usb: musb dma: add cppi41 dma driver 2013-08-09 17:40:16 +03:00
musb_dsps.c usb: patches for v3.16 merge window 2014-05-23 11:28:21 +09:00
musb_gadget_ep0.c usb: musb: gadget: read ep0 fifo only if rxcount is non zero 2013-04-02 11:42:50 +03:00
musb_gadget.c usb: musb: fix setting JZ4740 gadget periphal mode on reset 2013-12-20 09:53:59 -06:00
musb_gadget.h usb: musb: add Kconfig options for HOST, GAGDET or DUAL_ROLE modes 2013-05-28 19:22:23 +03:00
musb_host.c usb: patches for v3.15 2014-03-07 16:47:36 -08:00
musb_host.h usb: musb: fix prototype for musb_port_reset 2013-12-20 15:05:43 -06:00
musb_io.h usb: musb: use io{read,write}*_rep accessors 2012-12-17 17:15:13 -08:00
musb_regs.h
musb_virthub.c usb: musb: correct use of schedule_delayed_work() 2014-02-20 09:17:24 -06:00
musbhsdma.c usb: musb: dma: merge ->start/stop into create/destroy 2013-07-29 13:53:18 +03:00
musbhsdma.h usb: musb: remove generic_interrupt 2012-11-06 15:32:13 +02:00
omap2430.c usb: musb: omap2430: make sure clocks are enabled when running mailbox 2014-04-15 12:08:02 -05:00
omap2430.h usb: start using the control module driver 2013-01-25 12:27:24 +02:00
tusb6010_omap.c usb: musb: tusb6010: Use musb->tusb_revision instead of tusb_get_revision call. 2014-05-16 12:16:31 -05:00
tusb6010.c usb: musb: tusb6010: Use musb->tusb_revision instead of tusb_get_revision call. 2014-05-16 12:16:31 -05:00
tusb6010.h usb: musb: tusb6010: Use musb->tusb_revision instead of tusb_get_revision call. 2014-05-16 12:16:31 -05:00
ux500_dma.c usb: musb: ux500_dma: fix potential NULL dereference error 2013-12-17 13:17:42 -06:00
ux500.c usb: musb: ux500: don't propagate the OF node 2014-06-19 10:06:47 -05:00