Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp1352602ybp; Thu, 17 Oct 2019 11:29:09 -0700 (PDT) X-Google-Smtp-Source: APXvYqzdPNDp5ZU6LSc8ide87yOYWfNjNP3ez3yrG7e4CoGwW4ykXRMFyYptCiJYysidUFlJiSBF X-Received: by 2002:aa7:c259:: with SMTP id y25mr5207488edo.117.1571336949851; Thu, 17 Oct 2019 11:29:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571336949; cv=none; d=google.com; s=arc-20160816; b=CRYtxm0BrwtdD9Y0BuEVGWtuZmBozij+2YwpLdVpX5JFxBBab3RCVop1hbfrMKVTqp xIZStKMn0tDB9sPhZ4V1tRqkNwXsbijEQDnUjfvG+gtFvwTeTRK9f24Ge7qAdYhrGb0P V99JBoy5j/aocWXTZzOZAVaJAYvp5ddK2c6kFhMVl92p8StQ8bgNqcaZitV9qUT5tQou 5vZ+KSTjOTnNDlKIELU3k7DyHSE1DnyQjVY94NJc3JVUxIjr9T6l1cVQ5hmiSsib3Hj1 QFc1oVkANStw6WZKhd/qPH76Y3qL3Lg3q3E6r5MwI7FXB51gTgsv0Cz8rQWtxE6o7oge XYdA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=/5dMr8NbMghIfryq8gmX3ccXf0y612m9I79GNeEBao4=; b=vrsfVXHQtt+VkAfKV4QA5BHRK7aV7vVQlqRs/n7P+r3teFPRCSS5T8f86ht01QUtXS hBY+4CVDKvN/NmUeb+d2MJqQUe32B2TznqYCFvy4f0eB1OncNqsLolMERYVMnFopridV jMhe8u5V3RMACXD3viExv92lDEbjLHBfMkDfayj5GpghyXLt04DxtOi1Dz8aBUvgaAWc biUYK4kd3DAA++/m94+k4Tfmg4cVEQBRaHWvNkkI00HRQvDkoxX7jLo2ZDRCyhNPFu1S HIlbSuJ2/4UnI9v4KoFbIwOzieZE6f5/C3M7AKX9MfRixlUt4vvZzYceSkGhvexFL4UA OzKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=NXK5frua; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v25si2040341edy.392.2019.10.17.11.28.46; Thu, 17 Oct 2019 11:29:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=NXK5frua; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404867AbfJPWGa (ORCPT + 99 others); Wed, 16 Oct 2019 18:06:30 -0400 Received: from mail.kernel.org ([198.145.29.99]:52202 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2438177AbfJPV6c (ORCPT ); Wed, 16 Oct 2019 17:58:32 -0400 Received: from localhost (unknown [192.55.54.58]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id AB95621A49; Wed, 16 Oct 2019 21:58:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571263111; bh=KJeaUX9OZHIh7PetQFr3dApcgZNl+G9DEPPwQcylEo8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NXK5fruazsVN0mMear4djh/b+WojUswg91MjOMefPpaFkmm0LtD9clsiGSt0CzHs/ pUEvW0K7XDm76fq/aZFqJrgbwHTHm3iVt3PSu5e3AnLuXncG+zNS5uNvKvOheCbEqr uTLqR0Rm0qU0PhmNJdW3GC0WpuiDZ4ApEQSs0kIE= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Yoshihiro Shimoda Subject: [PATCH 5.3 035/112] usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior Date: Wed, 16 Oct 2019 14:50:27 -0700 Message-Id: <20191016214853.635369099@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191016214844.038848564@linuxfoundation.org> References: <20191016214844.038848564@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Yoshihiro Shimoda commit 4d599cd3a097a85a5c68a2c82b9a48cddf9953ec upstream. According to usb_ep_set_halt()'s description, __usbhsg_ep_set_halt_wedge() should return -EAGAIN if the IN endpoint has any queue or data. Otherwise, this driver is possible to cause just STALL without sending a short packet data on g_mass_storage driver, and then a few resetting a device happens on a host side during a usb enumaration. Fixes: 2f98382dcdfe ("usb: renesas_usbhs: Add Renesas USBHS Gadget") Cc: # v3.0+ Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/1569924633-322-3-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.h | 1 + drivers/usb/renesas_usbhs/fifo.c | 2 +- drivers/usb/renesas_usbhs/fifo.h | 1 + drivers/usb/renesas_usbhs/mod_gadget.c | 16 +++++++++++++++- drivers/usb/renesas_usbhs/pipe.c | 15 +++++++++++++++ drivers/usb/renesas_usbhs/pipe.h | 1 + 6 files changed, 34 insertions(+), 2 deletions(-) --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -211,6 +211,7 @@ struct usbhs_priv; /* DCPCTR */ #define BSTS (1 << 15) /* Buffer Status */ #define SUREQ (1 << 14) /* Sending SETUP Token */ +#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */ #define CSSTS (1 << 12) /* CSSTS Status */ #define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ #define SQCLR (1 << 8) /* Toggle Bit Clear */ --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -89,7 +89,7 @@ static void __usbhsf_pkt_del(struct usbh list_del_init(&pkt->node); } -static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) { return list_first_entry_or_null(&pipe->list, struct usbhs_pkt, node); } --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -97,5 +97,6 @@ void usbhs_pkt_push(struct usbhs_pipe *p void *buf, int len, int zero, int sequence); struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); void usbhs_pkt_start(struct usbhs_pipe *pipe); +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe); #endif /* RENESAS_USB_FIFO_H */ --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -722,6 +722,7 @@ static int __usbhsg_ep_set_halt_wedge(st struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); unsigned long flags; + int ret = 0; dev_dbg(dev, "set halt %d (pipe %d)\n", halt, usbhs_pipe_number(pipe)); @@ -729,6 +730,18 @@ static int __usbhsg_ep_set_halt_wedge(st /******************** spin lock ********************/ usbhs_lock(priv, flags); + /* + * According to usb_ep_set_halt()'s description, this function should + * return -EAGAIN if the IN endpoint has any queue or data. Note + * that the usbhs_pipe_is_dir_in() returns false if the pipe is an + * IN endpoint in the gadget mode. + */ + if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) || + usbhs_pipe_contains_transmittable_data(pipe))) { + ret = -EAGAIN; + goto out; + } + if (halt) usbhs_pipe_stall(pipe); else @@ -739,10 +752,11 @@ static int __usbhsg_ep_set_halt_wedge(st else usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); +out: usbhs_unlock(priv, flags); /******************** spin unlock ******************/ - return 0; + return ret; } static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -277,6 +277,21 @@ int usbhs_pipe_is_accessible(struct usbh return -EBUSY; } +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) +{ + u16 val; + + /* Do not support for DCP pipe */ + if (usbhs_pipe_is_dcp(pipe)) + return false; + + val = usbhsp_pipectrl_get(pipe); + if (val & INBUFM) + return true; + + return false; +} + /* * PID ctrl */ --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -83,6 +83,7 @@ void usbhs_pipe_clear(struct usbhs_pipe void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, int needs_bfre, int bfre_enable); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe); void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe);