From patchwork Fri Mar 17 00:08:40 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 40093 X-Patchwork-Delegate: mchehab@kernel.org Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.84_2) (envelope-from ) id 1copP3-0004W1-Cx; Fri, 17 Mar 2017 10:46:38 +0000 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.84_2/mailfrontend-6) with esmtp id 1copP1-0008BL-3r; Fri, 17 Mar 2017 11:46:37 +0100 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751160AbdCQKqd (ORCPT + 1 other); Fri, 17 Mar 2017 06:46:33 -0400 Received: from ec2-52-27-115-49.us-west-2.compute.amazonaws.com ([52.27.115.49]:58924 "EHLO osg.samsung.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751262AbdCQKqb (ORCPT ); Fri, 17 Mar 2017 06:46:31 -0400 Received: from localhost (localhost [127.0.0.1]) by osg.samsung.com (Postfix) with ESMTP id 99E09A1493 for ; Fri, 17 Mar 2017 10:36:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osg.samsung.com Received: from osg.samsung.com ([127.0.0.1]) by localhost (s-opensource.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id PKXfgv7NJClg for ; Fri, 17 Mar 2017 10:36:43 +0000 (UTC) Received: from vento.lan (unknown [186.213.245.81]) by osg.samsung.com (Postfix) with ESMTPSA id 2821EA1492 for ; Fri, 17 Mar 2017 10:36:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osg.samsung.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=Sender:Message-Id:Date:Subject:Cc:To: From:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=IMUCly9J9UV+D7hagznSgoGGTu5unxcpJHlIvLoJObU=; b=u4wtTq9bv/Y9C5tzVdguGx3irD 9LLXiv0XbshyBIUJ/9NSUkouzV5GuL1OF3UcK8AoCHa0i0JOdYD896FVsjPdDgHtpSh9C+GCpcEGR 4uwtUmfOKXBNdlA5HWlth9wov8q78Wnkyz5mLT075gbchrnVpmGRbX+KT6YB2ewUncrWGMotfPe06 +Ri8hI0svsb0vWqTa/6x0y2MriP1bb3qSx5drFJkkKFHMlWL6kFvWMX6mxFWnb9J1CGxCY2HjfWNV bcPxyKq4QCVSEWj1Aes/rAD+7tA4sbwuRusddaGfxIRnmeL0YP0tT2360R5j9dVvhwUIkzFZqYafv Rug0em6g==; From: Mauro Carvalho Chehab (by way of Mauro Carvalho Chehab ) To: Greg Kroah-Hartman Cc: Mauro Carvalho Chehab , John Youn , linux-usb@vger.kernel.org, linux-rpi-kernel@lists.infradead.org Date: Thu, 16 Mar 2017 21:08:40 -0300 Message-Id: <5c313be6d2f3c786d1f159a74758263a2ae0ad66.1489709097.git.mchehab@s-opensource.com> X-Mailer: git-send-email 2.9.3 Subject: [PATCH RFC] dwc2: Don't assume URB transfer_buffer are dword-aligned Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 6.0.0.2142326, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2017.3.17.103917 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODYTEXTP_SIZE_3000_LESS 0, BODY_SIZE_2000_2999 0, BODY_SIZE_5000_LESS 0, BODY_SIZE_7000_LESS 0, DATE_IN_PAST_06_12 0, DKIM_SIGNATURE 0, FROM_NAME_PHRASE 0, LEGITIMATE_SIGNS 0, MULTIPLE_REAL_RCPTS 0, NO_URI_HTTPS 0, __ANY_URI 0, __CC_NAME 0, __CC_NAME_DIFF_FROM_ACC 0, __CC_REAL_NAMES 0, __CP_MEDIA_BODY 0, __FROM_DOMAIN_IN_ANY_CC2 0, __FROM_DOMAIN_IN_RCPT 0, __HAS_CC_HDR 0, __HAS_FROM 0, __HAS_LIST_ID 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __MIME_TEXT_ONLY 0, __MIME_TEXT_P 0, __MIME_TEXT_P1 0, __MULTIPLE_RCPTS_CC_X2 0, __NO_HTML_TAG_RAW 0, __SANE_MSGID 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __TO_NAME 0, __TO_NAME_DIFF_FROM_ACC 0, __TO_REAL_NAMES 0, __URI_NO_WWW 0, __URI_NS ' The dwc2 hardware doesn't like to do DMA transfers without aligning data in DWORD. The driver also assumes that, even when there's no DMA, at dwc2_read_packet(). That cause buffer overflows, preventing some drivers to work. In the specific case of uvc_driver, it uses an array where it caches the content of video controls, passing it to the USB stack via usb_control_msg(). Typical controls use 1 or 2 bytes. The net result is that other values of the buffer gets overriden when this function is called. Fix it by changing the logic at dwc2_alloc_dma_aligned_buffer() to ensure that the buffer used for DMA will be DWORD-aligned. Detected with uvc driver. Signed-off-by: Mauro Carvalho Chehab --- On Raspberry Pi 3, I was unable to test dwc2_read_packet(), as this was never called there. However, the change at the second hunk, e. g. at dwc2_alloc_dma_aligned_buffer() made UVC to answer the same way as on x86, while reading the values for the device controls. drivers/usb/dwc2/hcd.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index a73722e27d07..c53d3c24d5b5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -572,20 +572,26 @@ u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg) void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes) { u32 __iomem *fifo = hsotg->regs + HCFIFO(0); - u32 *data_buf = (u32 *)dest; - int word_count = (bytes + 3) / 4; - int i; - - /* - * Todo: Account for the case where dest is not dword aligned. This - * requires reading data from the FIFO into a u32 temp buffer, then - * moving it into the data buffer. - */ + u32 *data_buf = (u32 *)dest, tmp; + int word_count = bytes >> 2; + int i, j; dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes); for (i = 0; i < word_count; i++, data_buf++) *data_buf = dwc2_readl(fifo); + + /* Handle the case where the buffer is not dword-aligned */ + if (bytes & 0x3) { + u8 *buf = (u8 *)data_buf; + + tmp = dwc2_readl(fifo); + + i <<= 2; + for (j = 0; i < bytes; j++, i++, dest++) + *buf = tmp >> (8 * j); + } + } /** @@ -2594,8 +2600,9 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) size_t kmalloc_size; if (urb->num_sgs || urb->sg || - urb->transfer_buffer_length == 0 || - !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1))) + urb->transfer_buffer_length == 0 || ( + !((uintptr_t)urb->transfer_buffer & (DWC2_USB_DMA_ALIGN - 1)) && + !((uintptr_t)(urb->transfer_buffer + urb->transfer_buffer_length) & (DWC2_USB_DMA_ALIGN - 1)))) return 0; /* Allocate a buffer with enough padding for alignment */