Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp1366474ybp; Thu, 17 Oct 2019 11:42:22 -0700 (PDT) X-Google-Smtp-Source: APXvYqxuKCgEYWgUk3Ay/GPomiiWPhC4EOxHfokdvVVRYUmToMyp6lFkWiJPLrWCFtz8d4330WyG X-Received: by 2002:aa7:d90d:: with SMTP id a13mr5400752edr.2.1571337742715; Thu, 17 Oct 2019 11:42:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571337742; cv=none; d=google.com; s=arc-20160816; b=DjpKmMLlazeHaUfwl69cEX7tNC2f37XQSOR7J//UHgUKYQqkvdP8cGKerPPQ5yTD23 EUjKvgP5K/lzAcjWjFffd2Xm8OOkFKNDljOoFZCs4WDGCPHoaq+LaLp9Kl+1SBAylI86 9I6SJkepFFyXHdctLpRaikehd68lc/05xqlyAEWj/wxP4xjkqYJTwxn5dmNddDGwfruf cdtYKWPcwMnXpb4e1fN9Y0WpZaSY9sgHEPHesKHEj6aT1mpbXITxVDnxnZhFlrh/rvm9 DfDubkisYS06P2BvaTiGBmWLE1hRn5l/Igt456mhfK9QV8qh5dNpw/NaFykKPw9U1Czn RQNg== 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=kUVJwLSFJrhNBYFO+Ce5j1uy5UsT1fTXAanatlrR9eY=; b=w1jbiAFw56AyqaGT0KufJWIz+qBaDYXwb/jbtVawzAT8KlVOaQvzGuf0nvrhrDKVlE 4efbzLxuwNT46G+0a7JeCieXFfvngqU/BkiF8xiF//PesN0iNW25TtpSJIr4x6s8fM9U Xh4o7ET/tJkKzVUcpr06Km2OUqM2CkWs5lQL5aZSdzRWthFICGIfMVazDEjE2GaqHU40 nYQEfHmTAL5tgsP2s9jNlRerMMqkDzqj7U0K0efOmctTs4OA2K8HLc8VmtW8Dg3C9K9h 92Tba3iqwt6P70mET52VMEZWPblbJbXwuiMRCwYlXaSSRB6tkD1kja/YZNTcsmm3zc9z 6jPA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=DWnP5xPC; 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 qh28si1813492ejb.210.2019.10.17.11.41.59; Thu, 17 Oct 2019 11:42:22 -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=DWnP5xPC; 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 S2407201AbfJPWKa (ORCPT + 99 others); Wed, 16 Oct 2019 18:10:30 -0400 Received: from mail.kernel.org ([198.145.29.99]:49676 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2437963AbfJPV5N (ORCPT ); Wed, 16 Oct 2019 17:57:13 -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 C248D21D7D; Wed, 16 Oct 2019 21:57:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571263032; bh=1V/MXXtzlL2Kw94mARl0j4IePYU5lmLrRUjQj9pGouE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DWnP5xPCmrj4JT0fMINWb+DFGRrAjxIoDBGMfgS6TGJ3CBAVDtZGbE/Vi+Ql6obGq ORW6AC+pCSu7vy7IS3CTsVmJlyPdGs1LIQBb0Ped4htPnC1xVFcd0UGEkbmHLEZhBB L4lk8FKgSq/V3rR2DbVupVREsjkS7AniYnAjvtXU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Yoshihiro Shimoda Subject: [PATCH 4.19 34/81] usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior Date: Wed, 16 Oct 2019 14:50:45 -0700 Message-Id: <20191016214834.753707258@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191016214805.727399379@linuxfoundation.org> References: <20191016214805.727399379@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 @@ -207,6 +207,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 @@ -721,6 +721,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)); @@ -728,6 +729,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 @@ -738,10 +751,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);