Received: by 2002:a25:d7c1:0:0:0:0:0 with SMTP id o184csp227816ybg; Thu, 17 Oct 2019 21:59:13 -0700 (PDT) X-Google-Smtp-Source: APXvYqxzumMZkxX6q1CwD7NHoXBHTOnjMRb4KZbZ5hOEzYQztIkEFPE7HRjKdmxrwa9SVikaDr4G X-Received: by 2002:a17:906:c443:: with SMTP id ck3mr7069776ejb.0.1571374752927; Thu, 17 Oct 2019 21:59:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571374752; cv=none; d=google.com; s=arc-20160816; b=dT3teD0hAvystz/ma/Cb5VGcBsiboXMwu98VOYEiu6PfNPhttJuTffiwQBg5YIlDFR PlS+IWRYhn5Og1E9coqYzj8TXc+644il4aT/la7oPR/rlNMw7wNJownFZp7ckaoqenJH lmjDJNb90hpzuQi1YbejuDS8u2j9hW9huLqkkOPcbSWPsqQdYaeh8w9cW8RUrBnIsaFV IsoSKIkaA0KaLWcIbM3XLcFrZMjTiKKQIovY0NlVTR0DETcElKHdrSqERCYMdkDRUXAC P9rsIr7MEPKVVbJ/hHBf8DP3Mzlfvrqr/C0n2xU5ydMUcGnDEZxtq5dtSdqXSDpxwxvb iafQ== 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=YriwY7Msgv/VP076P4CBb3bpVKRY9sCPI881bw2qOVM=; b=wbYjKlYybvhw6Wvyn6v0v2rsD8XvyV61pczZCtXKxUIc9x2HimaxG3rk0/3PalCWX0 aHbY4J2PiZU0CMwqYNZR/BWAHgHAMaOvh3+qDsAiKAkVlO3RlZPXBRx2IORQMeGRGOP/ TsDsfK4Ox1c4eXWucx/xq7yOPijjOz7aI1DldCPmkuI3FIrcuMba9ib9AqJDxl3MTKrI SjIkU0iTIA4DcjXBxbqQf/DnKNDfrLEjuXzGlfW2r5lrnAsuy1ovvvdslgdmD9Kyq5S6 m1z4PAtMerCqlCmmpXhsv93p7rC1yGAh7Bby6MTts/PBmzbLocUuMZXgv9g8gaw6rE/K 2bgA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=gsutl3id; 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 s6si2796477ejr.274.2019.10.17.21.58.11; Thu, 17 Oct 2019 21:59:12 -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=gsutl3id; 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 S2407484AbfJPWQb (ORCPT + 99 others); Wed, 16 Oct 2019 18:16:31 -0400 Received: from mail.kernel.org ([198.145.29.99]:45468 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2395187AbfJPVzH (ORCPT ); Wed, 16 Oct 2019 17:55: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 95E27218DE; Wed, 16 Oct 2019 21:55:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1571262906; bh=pBrzYawHYQSo8GOBN5dukprXQBJbBsMQHY9ZSLfj7ss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gsutl3idFuzNBUdp7DyLsQ6qDqOND0UoPgDdHgX+U7DllaAb1cMzyt2uWu5M4mlsi IgW66RU6QEdVobTrs1nM3zOHAIzZ9KMJOb36nvdZB2uV9lXzi93OWR5xXNqBbaEiod r5RrY0MQJa6QRzDHjPSeesz1BUK2ZKW8IpLRC3KA= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Yoshihiro Shimoda Subject: [PATCH 4.9 67/92] usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior Date: Wed, 16 Oct 2019 14:50:40 -0700 Message-Id: <20191016214842.627313212@linuxfoundation.org> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191016214759.600329427@linuxfoundation.org> References: <20191016214759.600329427@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) { if (list_empty(&pipe->list)) return NULL; --- 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);