Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp1397589ybp; Thu, 17 Oct 2019 12:11:06 -0700 (PDT) X-Google-Smtp-Source: APXvYqyDcAaq7BluDa+IhbTs/U7WKeseo8LWp3MuVzKMYr0HiFnF+D7f3WPjbamCW/x0QUydCybC X-Received: by 2002:a17:906:af8e:: with SMTP id mj14mr5184126ejb.45.1571339466576; Thu, 17 Oct 2019 12:11:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571339466; cv=none; d=google.com; s=arc-20160816; b=lE0al+6sh1LT28zQGWUg3xxVGaBTY840xaQi+POwCk5nO9AO6d2+IyloC4it2DKV6m vMQqt1g7QnOgKynzBhg9zZheSa+7j+ua5Qr/eC9fqnW10pr3rtEjxTj29cF8KsjbnASt veZxdvQWOC+6sZSL9CBlOnpb3AffBJQDmQwnNsHmQG64hh7h7gTLSd47kyDevVlAWbLJ RyOQhduZck8spQ3AKaB2GM99VBgeqLVTi7uk4Y6/Fns1kP/kcxick4FNzg8ccNwgEnNA IK/WaZqAgsbXrz+ABl6VtCfHGDYeMdZ7j6UiVDKaSZjDdXTcYZbBJ8o+dVIqG/HQoG/B 8a9w== 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=qBYBtG+gAL5ygWkwBamd2jngvHzaTnkAq6JtG1JfQiA=; b=xW8ttIrydtH+N+RtdS0s2NEWPU3I7z/jUP8vtmy9f+56T7vhpMVeXqLE5fkCvc2vbH rtCaR4QRKSvO/5LkIUMZfQ7Mk2PdA53z6AWTLaw9WlZ3JnVG7/kHftiSu2VaEfAud4zM FOIZnObND+9rq0vgPw1WOy5BNDicashWBNNKFO+dAk8REsMElC4iFJg3YslAFeHbhvZn Zki2RoL+GO4mMdan2wV3m3RNn09lwbPu5GhHMaVDzj//kVXS32CwXu+cOJ0gjgWFVNyI //gNuANJ4lsupMeQoZr7gXktKX6cuJXZehL3gWCpp5y3Y9gA9I0VpUhEmBUS/0aDX+Nu r05A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=kbODp3uN; 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 f14si2266484edf.102.2019.10.17.12.10.42; Thu, 17 Oct 2019 12:11:06 -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=kbODp3uN; 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 S2439289AbfJPWNC (ORCPT + 99 others); Wed, 16 Oct 2019 18:13:02 -0400 Received: from mail.kernel.org ([198.145.29.99]:47418 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2437912AbfJPV4H (ORCPT ); Wed, 16 Oct 2019 17:56:07 -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 7286221925; Wed, 16 Oct 2019 21:56:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571262966; bh=PmMXG0Rjttli7NwOYnslNIp6s5sFnaoTILcf/WVlRNM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kbODp3uNRcOUy95xqqBUIqlQbA5FO5Y+vtKb3vdcUULIz0gXpGeglNy/H8hxQNPVx M/ta0nLA8hxLere08thNLLGFohMuT2Bmc+KfFBUo4HGAQSzCgrOSispGS3y0Upzotr hPjeDrdReLfITd78ylI5fegFje/Adx4gSJmOnmwE= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Yoshihiro Shimoda Subject: [PATCH 4.14 33/65] usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior Date: Wed, 16 Oct 2019 14:50:47 -0700 Message-Id: <20191016214826.713679994@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191016214756.457746573@linuxfoundation.org> References: <20191016214756.457746573@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 @@ -213,6 +213,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 @@ -98,7 +98,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 @@ -106,5 +106,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 @@ -729,6 +729,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)); @@ -736,6 +737,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 @@ -746,10 +759,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 @@ -286,6 +286,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 @@ -90,6 +90,7 @@ void usbhs_pipe_init(struct usbhs_priv * int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); void usbhs_pipe_clear(struct usbhs_pipe *pipe); 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);