From patchwork Thu Jul 5 14:31:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?QW50dGkgU2VwcMOkbMOk?= X-Patchwork-Id: 10509521 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 A64366024A for ; Thu, 5 Jul 2018 14:32:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 947D528FA6 for ; Thu, 5 Jul 2018 14:32:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 880692915F; Thu, 5 Jul 2018 14:32:50 +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 0F0F028FA6 for ; Thu, 5 Jul 2018 14:32:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753801AbeGEOcr (ORCPT ); Thu, 5 Jul 2018 10:32:47 -0400 Received: from mail-lj1-f196.google.com ([209.85.208.196]:40599 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753525AbeGEOcn (ORCPT ); Thu, 5 Jul 2018 10:32:43 -0400 Received: by mail-lj1-f196.google.com with SMTP id a6-v6so6841290ljj.7 for ; Thu, 05 Jul 2018 07:32:42 -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:in-reply-to:references :mime-version:content-transfer-encoding; bh=VCcByU5UxWoAbZ9wNdXd1qMjOjT/43Rcx6V1KGcJ2L4=; b=dixHm+KeJDDpmbCEKQ7k4LzB76K64lNd84BbDRxrpQNBq+AAaYQhf7JBNDHZbYcrN+ jcfELkA5cR5rqARFLgQzmRa33B+s7pLDIbXrda9Rsax8KvxQqm1BgpQ5ffrVqgrbdejc ALpRMcldzVi/D5Stc1otMDYDagN1ySXhJ/kjSA9ZFtc7fsmVQaWRMQrVQaowVl0tA6xL 1//XFGtn8n5Lpxi6x4Nj3WXTeZbW/LIOYjabXk3ILAFsvax0lOS6tbEalMPnkTgRnW9y Ku/mgObWRSo48mxaC9rM86xvMSsvS8NhYvvYMwgJuobY7gTgxq1QWZMfOtfh94TnTiA6 qnDg== 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:in-reply-to :references:mime-version:content-transfer-encoding; bh=VCcByU5UxWoAbZ9wNdXd1qMjOjT/43Rcx6V1KGcJ2L4=; b=c54dhnEoJeuLDFLNMVugNF+bvPq1PDKsXthfrGMdPH0VdYits1veiiI/o/3OQ5bzCQ Yms0O2mZpSHxfiEB6IzwNhdHooJUk2hZVV6jrrgfmzsQuTO3kM5oDYVWC+RhqIcLDhuI X7yYJ1uZW8IAqftccTwDxbGokNzWyx/zEUN2ACufQ1Hvm/wCGhtaLafZTg2Da/d2TgPA nDowMTg9pAqbLqojZrF/FD2j0qFmYfh/figs2hHspDzSdD7pNRhdusDQ9rPeddlVCG2w MfTp5YIdXN/qaQTID+IhLBfYQlUGGi21bdqEcS1NSag65YGSQJyyWu18AwdGf6eSKoA1 Dcxg== X-Gm-Message-State: APt69E3Ax6gqUc+LsjBsn5qLJntiyhTqJ/ViUUS8mBZGuESd+hCf+BLB BXNoDxlMNeT6X3E3rhG/5U4= X-Google-Smtp-Source: AAOMgpdzOLMY1MVWMNn6O9VJc1w5s+g9h7iGdMGNc9emv0RCrqdM5jRoTA00yYUESGnn8WzROY+AxA== X-Received: by 2002:a2e:8257:: with SMTP id j23-v6mr4303152ljh.49.1530801161837; Thu, 05 Jul 2018 07:32:41 -0700 (PDT) Received: from griffin.lan (dtyqvkyyyyyyyyyyyyydt-3.rev.dnainternet.fi. [2001:14ba:801b:1400::7]) by smtp.gmail.com with ESMTPSA id z5-v6sm1426029lff.96.2018.07.05.07.32.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Jul 2018 07:32:40 -0700 (PDT) From: =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= To: Minas Harutyunyan , John Youn , Felipe Balbi Cc: Grigor Tovmasyan , Vardan Mikayelyan , Douglas Anderson , William Wu , Greg Kroah-Hartman , linux-usb@vger.kernel.org, =?UTF-8?q?Antti=20Sepp=C3=A4l=C3=A4?= Subject: [PATCH 1/2] usb: dwc2: Fix DMA alignment to start at allocated boundary Date: Thu, 5 Jul 2018 17:31:53 +0300 Message-Id: <20180705143154.8734-2-a.seppala@gmail.com> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180705143154.8734-1-a.seppala@gmail.com> References: <20180705143154.8734-1-a.seppala@gmail.com> MIME-Version: 1.0 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The commit 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more supported way") introduced a common way to align DMA allocations. The code in the commit aligns the struct dma_aligned_buffer but the actual DMA address pointed by data[0] gets aligned to an offset from the allocated boundary by the kmalloc_ptr and the old_xfer_buffer pointers. This is against the recommendation in Documentation/DMA-API.txt which states: Therefore, it is recommended that driver writers who don't take special care to determine the cache line size at run time only map virtual regions that begin and end on page boundaries (which are guaranteed also to be cache line boundaries). The effect of this is that architectures with non-coherent DMA caches may run into memory corruption or kernel crashes with Unhandled kernel unaligned accesses exceptions. Fix the alignment by positioning the DMA area in front of the allocation and use memory at the end of the area for storing the orginal transfer_buffer pointer. This may have the added benefit of increased performance as the DMA area is now fully aligned on all architectures. Tested with Lantiq xRX200 (MIPS) and RPi Model B Rev 2 (ARM). Fixes: 3bc04e28a030 ("usb: dwc2: host: Get aligned DMA in a more supported way") Signed-off-by: Antti Seppälä Reviewed-by: Douglas Anderson --- drivers/usb/dwc2/hcd.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index b1104be3429c..2ed0ac18e053 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2665,34 +2665,29 @@ static int dwc2_alloc_split_dma_aligned_buf(struct dwc2_hsotg *hsotg, #define DWC2_USB_DMA_ALIGN 4 -struct dma_aligned_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[0]; -}; - static void dwc2_free_dma_aligned_buffer(struct urb *urb) { - struct dma_aligned_buffer *temp; + void *stored_xfer_buffer; if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) return; - temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); + /* Restore urb->transfer_buffer from the end of the allocated area */ + memcpy(&stored_xfer_buffer, urb->transfer_buffer + + urb->transfer_buffer_length, sizeof(urb->transfer_buffer)); if (usb_urb_dir_in(urb)) - memcpy(temp->old_xfer_buffer, temp->data, + memcpy(stored_xfer_buffer, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); + kfree(urb->transfer_buffer); + urb->transfer_buffer = stored_xfer_buffer; urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; } static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) { - struct dma_aligned_buffer *temp, *kmalloc_ptr; + void *kmalloc_ptr; size_t kmalloc_size; if (urb->num_sgs || urb->sg || @@ -2700,22 +2695,29 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1))) return 0; - /* Allocate a buffer with enough padding for alignment */ + /* + * Allocate a buffer with enough padding for original transfer_buffer + * pointer. This allocation is guaranteed to be aligned properly for + * DMA + */ kmalloc_size = urb->transfer_buffer_length + - sizeof(struct dma_aligned_buffer) + DWC2_USB_DMA_ALIGN - 1; + sizeof(urb->transfer_buffer); kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); if (!kmalloc_ptr) return -ENOMEM; - /* Position our struct dma_aligned_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr + 1, DWC2_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; + /* + * Position value of original urb->transfer_buffer pointer to the end + * of allocation for later referencing + */ + memcpy(kmalloc_ptr + urb->transfer_buffer_length, + &urb->transfer_buffer, sizeof(urb->transfer_buffer)); + if (usb_urb_dir_out(urb)) - memcpy(temp->data, urb->transfer_buffer, + memcpy(kmalloc_ptr, urb->transfer_buffer, urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; + urb->transfer_buffer = kmalloc_ptr; urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;