Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932332AbaGHBSp (ORCPT ); Mon, 7 Jul 2014 21:18:45 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:55225 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752574AbaGGXxo (ORCPT ); Mon, 7 Jul 2014 19:53:44 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Torben Hohn , Thomas Gleixner , Felipe Balbi Subject: [PATCH 3.15 014/122] usb: musb: Ensure that cppi41 timer gets armed on premature DMA TX irq Date: Mon, 7 Jul 2014 16:56:16 -0700 Message-Id: <20140707235734.675542467@linuxfoundation.org> X-Mailer: git-send-email 2.0.0.254.g50f84e3 In-Reply-To: <20140707235734.234226883@linuxfoundation.org> References: <20140707235734.234226883@linuxfoundation.org> User-Agent: quilt/0.63-1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.15-stable review patch. If anyone has any objections, please let me know. ------------------ From: Thomas Gleixner commit c58d80f523ffc15ef4d062fc7aeb03793fe39701 upstream. 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 Signed-off-by: Thomas Gleixner Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_cppi41.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -318,7 +318,7 @@ static void cppi41_dma_callback(void *pr } list_add_tail(&cppi41_channel->tx_check, &controller->early_tx_list); - if (!hrtimer_active(&controller->early_tx)) { + if (!hrtimer_is_queued(&controller->early_tx)) { hrtimer_start_range_ns(&controller->early_tx, ktime_set(0, 140 * NSEC_PER_USEC), 40 * NSEC_PER_USEC, -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/