From patchwork Thu Jul 5 15:21:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre Le Magourou X-Patchwork-Id: 10509639 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DBA896024A for ; Thu, 5 Jul 2018 15:22:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CA49C28682 for ; Thu, 5 Jul 2018 15:22:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C89D62920E; Thu, 5 Jul 2018 15:22:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2F0B128EC7 for ; Thu, 5 Jul 2018 15:22:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753451AbeGEPWl (ORCPT ); Thu, 5 Jul 2018 11:22:41 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:39395 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753231AbeGEPVm (ORCPT ); Thu, 5 Jul 2018 11:21:42 -0400 Received: by mail-wm0-f65.google.com with SMTP id p11-v6so11548454wmc.4 for ; Thu, 05 Jul 2018 08:21:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=apaDj708haYXlHBqnM0koCzihrRG36zfo3eMIzPy4Ik=; b=cY/R6nWh6CWZeyIBo/D0Z5an2ggnUWjePk91QWLe6VewiDPulFgA1Kose3BQ7aVN5E naBGgXOigf/QYUuaQBKb5Dq/Hajfgd/1HaOu3Cbt6us0tq+8YGGuQG7+OwIxvpXJ92gC TAubd77XDVoFCMWs9BRVKO8GhCbAg9FO0jl0kvM4NQCJtrBvBqcBa81L47Udr2IhILB5 pAm+JltrXcftqr5OSFA2F3fkTdBLKbmMelTcdPa99GTJ/n6tjhg/xxJmPRFNIkY3C9N5 8V3Dj8mt91p/M5evz9YdYSFf1iyfmF+gdAMCs06LnfHVoP83uiIRDMv/qLmxhcMu5lcy y8BA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=apaDj708haYXlHBqnM0koCzihrRG36zfo3eMIzPy4Ik=; b=ZoPT1wKWPjR+GfDCCvRHyUlLPr2ZUiFLGqrmVj237TsWuabyVPrcdUq9AhFumAJjTn f6/+nGlhBWPip1V4R3e4/wW5gcz1VPa6z76XPYhV+gvmVYQGqlPDVe8uz8cYncoF00RV 8romay8Tp1wQIcHrHK8gPpMTn+zB4R2KailrS/0fpXsu/p7har5J4wkf2qnBa+qDzGkY uu44G9t7Q9H3ZjPT0WJgeGE+1pT/CWhFwWzpwDowjQVgg0ppkihtQtWyaLfjGroB/t6r HCzMH3MZ9ZCC0FMEIosk7UStWlisbcGrzis5a964JFHJgsi0q2h9/zsjjaolpjWMbwp5 rWxQ== X-Gm-Message-State: APt69E3Gf9buCVl3V4RLyyWedkxKjTy2IycoRbBploA4UNJEc/OGNlV0 HmAc90C3eH/nxYIkJTXK6SsYdA== X-Google-Smtp-Source: AAOMgpemVtqXyZ55fqWNRotHccv7atHPh991xC1GhPAGfxoIWlVVrCLZEHtT0FId5Z+pOoQZ9iJB7w== X-Received: by 2002:a1c:ad4:: with SMTP id 203-v6mr4098040wmk.98.1530804100850; Thu, 05 Jul 2018 08:21:40 -0700 (PDT) Received: from lemagoup-desktop.localdomain (softbank-robotics-gw1.ter4.eqx2.par.cust.as8218.eu. [158.255.112.194]) by smtp.gmail.com with ESMTPSA id t124-v6sm8547734wmt.29.2018.07.05.08.21.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Jul 2018 08:21:39 -0700 (PDT) From: lemagoup@gmail.com X-Google-Original-From: plemagourou@softbankrobotics.com To: linux-arm-msm@vger.kernel.org Cc: felipe.balbi@linux.intel.com, Pierre Le Magourou Subject: [PATCH] dwc3: Remove wait for wait_end_transfer event. Date: Thu, 5 Jul 2018 17:21:30 +0200 Message-Id: <20180705152130.12554-1-plemagourou@softbankrobotics.com> X-Mailer: git-send-email 2.16.2 Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Pierre Le Magourou We can't wait for END_OF_TRANSFER event in dwc3_gadget_ep_dequeue() because it can be called in an interruption context. TRBs are now cleared after the END_OF_TRANSFER completion, in the interrupt handler. Signed-off-by: Pierre Le Magourou --- drivers/usb/dwc3/core.h | 14 ++++++ drivers/usb/dwc3/gadget.c | 122 +++++++++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 51 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7a217a36c36b..5e2070183e3a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -627,6 +627,7 @@ struct dwc3_event_buffer { * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete * @lock: spinlock for endpoint request queue traversal * @regs: pointer to first endpoint register + * @pending_trb: pointer to pending TRB structure * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool * @trb_enqueue: enqueue 'pointer' into TRB array @@ -654,6 +655,7 @@ struct dwc3_ep { void __iomem *regs; struct dwc3_trb *trb_pool; + struct dwc3_pending_trb *pending_trb; dma_addr_t trb_pool_dma; struct dwc3 *dwc; @@ -777,6 +779,18 @@ struct dwc3_trb { u32 ctrl; } __packed; +/** + * struct dwc3_pending_trb + * @dirty_trb: pointer to TRB waiting for END_TRANSFER completion + * @extra_trb: true if extra TRB was set to align transfer + * @num_pending_sgs: number of pending SGs + */ +struct dwc3_pending_trb { + struct dwc3_trb *dirty_trb; + bool extra_trb; + unsigned int num_pending_sgs; +}; + /** * struct dwc3_hwparams - copy of HWPARAMS registers * @hwparams0: GHWPARAMS0 diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 69bf137aab37..dd1f2b74723b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1341,6 +1341,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; + struct dwc3_pending_trb *p_trb; unsigned long flags; int ret = 0; @@ -1367,63 +1368,29 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, * If request was already started, this means we had to * stop the transfer. With that we also need to ignore * all TRBs used by the request, however TRBs can only - * be modified after completion of END_TRANSFER - * command. So what we do here is that we wait for - * END_TRANSFER completion and only after that, we jump - * over TRBs by clearing HWO and incrementing dequeue - * pointer. + * be modified after completion of END_TRANSFER command. * - * Note that we have 2 possible types of transfers here: - * - * i) Linear buffer request - * ii) SG-list based request - * - * SG-list based requests will have r->num_pending_sgs - * set to a valid number (> 0). Linear requests, - * normally use a single TRB. - * - * For each of these two cases, if r->unaligned flag is - * set, one extra TRB has been used to align transfer - * size to wMaxPacketSize. - * - * All of these cases need to be taken into - * consideration so we don't mess up our TRB ring - * pointers. + * Don't wait for END_TRANSFER completion here because + * dwc3_gadget_ep_dequeue() can be called from within + * the controller's interrupt handler. Save the TRB + * pointer, the number of pending sgs, and the + * extra_trb flag, so that TRBs HWO can be cleared and + * dequeue pointer incremented when the END_TRANSFER + * completion is received. */ - wait_event_lock_irq(dep->wait_end_transfer, - !(dep->flags & DWC3_EP_END_TRANSFER_PENDING), - dwc->lock); if (!r->trb) goto out0; - if (r->num_pending_sgs) { - struct dwc3_trb *trb; - int i = 0; - - for (i = 0; i < r->num_pending_sgs; i++) { - trb = r->trb + i; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - - if (r->unaligned || r->zero) { - trb = r->trb + r->num_pending_sgs + 1; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - } else { - struct dwc3_trb *trb = r->trb; - - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - - if (r->unaligned || r->zero) { - trb = r->trb + 1; - trb->ctrl &= ~DWC3_TRB_CTRL_HWO; - dwc3_ep_inc_deq(dep); - } - } + p_trb = kzalloc(sizeof(*p_trb), GFP_KERNEL|GFP_ATOMIC); + p_trb->dirty_trb = r->trb; + p_trb->num_pending_sgs = r->num_pending_sgs; + + if (r->unaligned || r->zero) + p_trb->extra_trb = true; + + dep->pending_trb = p_trb; + goto out1; } dev_err(dwc->dev, "request %pK was not queued to %s\n", @@ -2430,6 +2397,56 @@ static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, __dwc3_gadget_start_isoc(dep); } +/* Clear HWO and increment dequeue pointer. + * + * 2 types of transfers are possible: + * + * i) Linear buffer request + * ii) SG-list based request + * + * SG-list based requests have p_trb->num_pending_sgs set to a valid number + * (> 0). Linear requests, normally use a single TRB. + * + * For each of these two cases, if p_trb->extra_trb flag is set, one + * extra TRB has been used to align transfer size to wMaxPacketSize. + * + * All of these cases need to be taken into consideration so TRB ring pointers + * are not messed up. + */ +static void dwc3_clear_pending_trbs(struct dwc3_ep *dep) +{ + struct dwc3_pending_trb *p_trb = dep->pending_trb; + struct dwc3_trb *trb; + + if (p_trb->num_pending_sgs) { + int i; + + for (i = 0; i < p_trb->num_pending_sgs; i++) { + trb = p_trb->dirty_trb + i; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_deq(dep); + } + + if (p_trb->extra_trb) { + trb = p_trb->dirty_trb + p_trb->num_pending_sgs + 1; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_deq(dep); + } + } else { + trb = p_trb->dirty_trb; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_deq(dep); + + if (p_trb->extra_trb) { + trb = p_trb->dirty_trb + 1; + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + dwc3_ep_inc_deq(dep); + } + } + kfree(p_trb); + dep->pending_trb = NULL; +} + static void dwc3_endpoint_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { @@ -2466,6 +2483,9 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, if (cmd == DWC3_DEPCMD_ENDTRANSFER) { dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; wake_up(&dep->wait_end_transfer); + + if (dep->pending_trb) + dwc3_clear_pending_trbs(dep); } break; case DWC3_DEPEVT_STREAMEVT: