usb: musb: cppi41: fire hrtimer according to programmed channel length
authorDaniel Mack <zonque@gmail.com>
Thu, 19 Jun 2014 22:20:44 +0000 (00:20 +0200)
committerFelipe Balbi <balbi@ti.com>
Mon, 30 Jun 2014 19:26:30 +0000 (14:26 -0500)
The musb/cppi41 code installs a hrtimer to work around DMA completion
interrupts that have fired too early on AM335x hardware. This timer
is currently programmed to first fire 140 microseconds after the DMA
completion callback. According to the commit which introduced it
(a655f481d83, "usb: musb: musb_cppi41: handle pre-mature TX complete
interrupt"), that value is is considered a 'rule of thumb' that worked
well with the test case described in the commit log.

Test show, however, that for USB audio devices and much smaller packet
sizes, the timer has to fire earlier in order to correctly handle the audio
stream. The original test case had output transfer sizes of 1514 bytes, and
a delay of 140 microseconds. For audio devices with 24 bytes channel size, 3
microseconds seem to work well.

Hence, let's assume that the time it takes to clear the bit correlates with
the number of bytes transferred. The referenced commit log mentions such a
suspicion as well. Let the timer fire in cppi41_channel->total_len/10
microseconds to correctly handle both cases.

Also, shorten the interval in which the timer fires again in case of
a non-empty early_tx list.

With these changes in place, both FS and HS audio devices appear to work
well on AM335x hardware.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Reported-by: Sebastian Reimers <sebastian.reimers@googlemail.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/musb/musb_cppi41.c

index a2c445608e75770d50c6d615fd551ea2e8af6f55..adfffe8848911e5c6a5013ba3a7589f8ef99c4e1 100644 (file)
@@ -200,7 +200,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
        if (!list_empty(&controller->early_tx_list)) {
                ret = HRTIMER_RESTART;
                hrtimer_forward_now(&controller->early_tx,
-                               ktime_set(0, 150 * NSEC_PER_USEC));
+                               ktime_set(0, 50 * NSEC_PER_USEC));
        }
 
        spin_unlock_irqrestore(&musb->lock, flags);
@@ -274,8 +274,10 @@ static void cppi41_dma_callback(void *private_data)
                list_add_tail(&cppi41_channel->tx_check,
                                &controller->early_tx_list);
                if (!hrtimer_active(&controller->early_tx)) {
+                       unsigned long usecs = cppi41_channel->total_len / 10;
+
                        hrtimer_start_range_ns(&controller->early_tx,
-                               ktime_set(0, 140 * NSEC_PER_USEC),
+                               ktime_set(0, usecs * NSEC_PER_USEC),
                                40 * NSEC_PER_USEC,
                                HRTIMER_MODE_REL);
                }