usb-serial-cp210x-add-new-vid-pid-for-supporting-teraoka-ad2000.patch
usb-serial-option-adding-support-for-cinterion-mv31.patch
usb-host-xhci-mvebu-make-usb-3.0-phy-optional-for-armada-3720.patch
-usb-host-xhci-mvebu-make-usb-3.0-phy-optional-for-ar.patch
+usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch
+usb-gadget-aspeed-add-missing-of_node_put.patch
+usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch
+usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch
+usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch
+usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch
+usb-xhci-mtk-fix-unreleased-bandwidth-data.patch
+usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch
+usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch
arm-omap1-osk-fix-ohci-omap-breakage.patch
arm64-dts-qcom-c630-keep-both-touchpad-devices-enabl.patch
input-i8042-unbreak-pegatron-c15b.patch
--- /dev/null
+From f670e9f9c8cac716c3506c6bac9e997b27ad441a Mon Sep 17 00:00:00 2001
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Date: Wed, 27 Jan 2021 11:39:19 +0100
+Subject: usb: dwc2: Fix endpoint direction check in ep_from_windex
+
+From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+
+commit f670e9f9c8cac716c3506c6bac9e997b27ad441a upstream.
+
+dwc2_hsotg_process_req_status uses ep_from_windex() to retrieve
+the endpoint for the index provided in the wIndex request param.
+
+In a test-case with a rndis gadget running and sending a malformed
+packet to it like:
+ dev.ctrl_transfer(
+ 0x82, # bmRequestType
+ 0x00, # bRequest
+ 0x0000, # wValue
+ 0x0001, # wIndex
+ 0x00 # wLength
+ )
+it is possible to cause a crash:
+
+[ 217.533022] dwc2 ff300000.usb: dwc2_hsotg_process_req_status: USB_REQ_GET_STATUS
+[ 217.559003] Unable to handle kernel read from unreadable memory at virtual address 0000000000000088
+...
+[ 218.313189] Call trace:
+[ 218.330217] ep_from_windex+0x3c/0x54
+[ 218.348565] usb_gadget_giveback_request+0x10/0x20
+[ 218.368056] dwc2_hsotg_complete_request+0x144/0x184
+
+This happens because ep_from_windex wants to compare the endpoint
+direction even if index_to_ep() didn't return an endpoint due to
+the direction not matching.
+
+The fix is easy insofar that the actual direction check is already
+happening when calling index_to_ep() which will return NULL if there
+is no endpoint for the targeted direction, so the offending check
+can go away completely.
+
+Fixes: c6f5c050e2a7 ("usb: dwc2: gadget: add bi-directional endpoint support")
+Cc: stable@vger.kernel.org
+Reported-by: Gerhard Klostermeier <gerhard.klostermeier@syss.de>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
+Link: https://lore.kernel.org/r/20210127103919.58215-1-heiko@sntech.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc2/gadget.c | 8 +-------
+ 1 file changed, 1 insertion(+), 7 deletions(-)
+
+--- a/drivers/usb/dwc2/gadget.c
++++ b/drivers/usb/dwc2/gadget.c
+@@ -1543,7 +1543,6 @@ static void dwc2_hsotg_complete_oursetup
+ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
+ u32 windex)
+ {
+- struct dwc2_hsotg_ep *ep;
+ int dir = (windex & USB_DIR_IN) ? 1 : 0;
+ int idx = windex & 0x7F;
+
+@@ -1553,12 +1552,7 @@ static struct dwc2_hsotg_ep *ep_from_win
+ if (idx > hsotg->num_of_eps)
+ return NULL;
+
+- ep = index_to_ep(hsotg, idx, dir);
+-
+- if (idx && ep->dir_in != dir)
+- return NULL;
+-
+- return ep;
++ return index_to_ep(hsotg, idx, dir);
+ }
+
+ /**
--- /dev/null
+From 0e5a3c8284a30f4c43fd81d7285528ece74563b5 Mon Sep 17 00:00:00 2001
+From: Gary Bisson <gary.bisson@boundarydevices.com>
+Date: Mon, 25 Jan 2021 17:19:34 +0100
+Subject: usb: dwc3: fix clock issue during resume in OTG mode
+
+From: Gary Bisson <gary.bisson@boundarydevices.com>
+
+commit 0e5a3c8284a30f4c43fd81d7285528ece74563b5 upstream.
+
+Commit fe8abf332b8f ("usb: dwc3: support clocks and resets for DWC3
+core") introduced clock support and a new function named
+dwc3_core_init_for_resume() which enables the clock before calling
+dwc3_core_init() during resume as clocks get disabled during suspend.
+
+Unfortunately in this commit the DWC3_GCTL_PRTCAP_OTG case was forgotten
+and therefore during resume, a platform could call dwc3_core_init()
+without re-enabling the clocks first, preventing to resume properly.
+
+So update the resume path to call dwc3_core_init_for_resume() as it
+should.
+
+Fixes: fe8abf332b8f ("usb: dwc3: support clocks and resets for DWC3 core")
+Cc: stable@vger.kernel.org
+Signed-off-by: Gary Bisson <gary.bisson@boundarydevices.com>
+Link: https://lore.kernel.org/r/20210125161934.527820-1-gary.bisson@boundarydevices.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc3/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -1758,7 +1758,7 @@ static int dwc3_resume_common(struct dwc
+ if (PMSG_IS_AUTO(msg))
+ break;
+
+- ret = dwc3_core_init(dwc);
++ ret = dwc3_core_init_for_resume(dwc);
+ if (ret)
+ return ret;
+
--- /dev/null
+From a55a9a4c5c6253f6e4dea268af728664ac997790 Mon Sep 17 00:00:00 2001
+From: kernel test robot <lkp@intel.com>
+Date: Thu, 21 Jan 2021 19:12:54 +0100
+Subject: usb: gadget: aspeed: add missing of_node_put
+
+From: kernel test robot <lkp@intel.com>
+
+commit a55a9a4c5c6253f6e4dea268af728664ac997790 upstream.
+
+Breaking out of for_each_child_of_node requires a put on the
+child value.
+
+Generated by: scripts/coccinelle/iterators/for_each_child.cocci
+
+Fixes: 82c2d81361ec ("coccinelle: iterators: Add for_each_child.cocci script")
+CC: Sumera Priyadarsini <sylphrenadin@gmail.com>
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Julia Lawall <julia.lawall@inria.fr>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/alpine.DEB.2.22.394.2101211907060.14700@hadrien
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/udc/aspeed-vhub/hub.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c
++++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
+@@ -999,8 +999,10 @@ static int ast_vhub_of_parse_str_desc(st
+ str_array[offset].s = NULL;
+
+ ret = ast_vhub_str_alloc_add(vhub, &lang_str);
+- if (ret)
++ if (ret) {
++ of_node_put(child);
+ break;
++ }
+ }
+
+ return ret;
--- /dev/null
+From 3e1f4a2e1184ae6ad7f4caf682ced9554141a0f4 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 28 Jan 2021 12:33:42 +0300
+Subject: USB: gadget: legacy: fix an error code in eth_bind()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 3e1f4a2e1184ae6ad7f4caf682ced9554141a0f4 upstream.
+
+This code should return -ENOMEM if the allocation fails but it currently
+returns success.
+
+Fixes: 9b95236eebdb ("usb: gadget: ether: allocate and init otg descriptor by otg capabilities")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Link: https://lore.kernel.org/r/YBKE9rqVuJEOUWpW@mwanda
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/legacy/ether.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/gadget/legacy/ether.c
++++ b/drivers/usb/gadget/legacy/ether.c
+@@ -403,8 +403,10 @@ static int eth_bind(struct usb_composite
+ struct usb_descriptor_header *usb_desc;
+
+ usb_desc = usb_otg_descriptor_alloc(gadget);
+- if (!usb_desc)
++ if (!usb_desc) {
++ status = -ENOMEM;
+ goto fail1;
++ }
+ usb_otg_descriptor_init(gadget, usb_desc);
+ otg_desc[0] = usb_desc;
+ otg_desc[1] = NULL;
+++ /dev/null
-From bec5fbb439c63738153b186dea9e487db9b5259b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 1 Feb 2021 16:08:03 +0100
-Subject: usb: host: xhci: mvebu: make USB 3.0 PHY optional for Armada 3720
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-From: Pali Rohár <pali@kernel.org>
-
-commit 3241929b67d28c83945d3191c6816a3271fd6b85 upstream.
-
-Older ATF does not provide SMC call for USB 3.0 phy power on functionality
-and therefore initialization of xhci-hcd is failing when older version of
-ATF is used. In this case phy_power_on() function returns -EOPNOTSUPP.
-
-[ 3.108467] mvebu-a3700-comphy d0018300.phy: unsupported SMC call, try updating your firmware
-[ 3.117250] phy phy-d0018300.phy.0: phy poweron failed --> -95
-[ 3.123465] xhci-hcd: probe of d0058000.usb failed with error -95
-
-This patch introduces a new plat_setup callback for xhci platform drivers
-which is called prior calling usb_add_hcd() function. This function at its
-beginning skips PHY init if hcd->skip_phy_initialization is set.
-
-Current init_quirk callback for xhci platform drivers is called from
-xhci_plat_setup() function which is called after chip reset completes.
-It happens in the middle of the usb_add_hcd() function and therefore this
-callback cannot be used for setting if PHY init should be skipped or not.
-
-For Armada 3720 this patch introduce a new xhci_mvebu_a3700_plat_setup()
-function configured as a xhci platform plat_setup callback. This new
-function calls phy_power_on() and in case it returns -EOPNOTSUPP then
-XHCI_SKIP_PHY_INIT quirk is set to instruct xhci-plat to skip PHY
-initialization.
-
-This patch fixes above failure by ignoring 'not supported' error in
-xhci-hcd driver. In this case it is expected that phy is already power on.
-
-It fixes initialization of xhci-hcd on Espressobin boards where is older
-Marvell's Arm Trusted Firmware without SMC call for USB 3.0 phy power.
-
-This is regression introduced in commit bd3d25b07342 ("arm64: dts: marvell:
-armada-37xx: link USB hosts with their PHYs") where USB 3.0 phy was defined
-and therefore xhci-hcd on Espressobin with older ATF started failing.
-
-Fixes: bd3d25b07342 ("arm64: dts: marvell: armada-37xx: link USB hosts with their PHYs")
-Cc: <stable@vger.kernel.org> # 5.1+: ea17a0f153af: phy: marvell: comphy: Convert internal SMCC firmware return codes to errno
-Cc: <stable@vger.kernel.org> # 5.1+: f768e718911e: usb: host: xhci-plat: add priv quirk for skip PHY initialization
-Tested-by: Tomasz Maciej Nowak <tmn505@gmail.com>
-Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> # On R-Car
-Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> # xhci-plat
-Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
-Signed-off-by: Pali Rohár <pali@kernel.org>
-Link: https://lore.kernel.org/r/20210201150803.7305-1-pali@kernel.org
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/usb/host/xhci-mvebu.c | 42 +++++++++++++++++++++++++++++++++++
- drivers/usb/host/xhci-mvebu.h | 6 +++++
- drivers/usb/host/xhci-plat.c | 20 ++++++++++++++++-
- drivers/usb/host/xhci-plat.h | 1 +
- 4 files changed, 68 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c
-index 60651a50770f9..8ca1a235d1645 100644
---- a/drivers/usb/host/xhci-mvebu.c
-+++ b/drivers/usb/host/xhci-mvebu.c
-@@ -8,6 +8,7 @@
- #include <linux/mbus.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
-+#include <linux/phy/phy.h>
-
- #include <linux/usb.h>
- #include <linux/usb/hcd.h>
-@@ -74,6 +75,47 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
- return 0;
- }
-
-+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
-+{
-+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-+ struct device *dev = hcd->self.controller;
-+ struct phy *phy;
-+ int ret;
-+
-+ /* Old bindings miss the PHY handle */
-+ phy = of_phy_get(dev->of_node, "usb3-phy");
-+ if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+ else if (IS_ERR(phy))
-+ goto phy_out;
-+
-+ ret = phy_init(phy);
-+ if (ret)
-+ goto phy_put;
-+
-+ ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
-+ if (ret)
-+ goto phy_exit;
-+
-+ ret = phy_power_on(phy);
-+ if (ret == -EOPNOTSUPP) {
-+ /* Skip initializatin of XHCI PHY when it is unsupported by firmware */
-+ dev_warn(dev, "PHY unsupported by firmware\n");
-+ xhci->quirks |= XHCI_SKIP_PHY_INIT;
-+ }
-+ if (ret)
-+ goto phy_exit;
-+
-+ phy_power_off(phy);
-+phy_exit:
-+ phy_exit(phy);
-+phy_put:
-+ of_phy_put(phy);
-+phy_out:
-+
-+ return 0;
-+}
-+
- int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
- {
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h
-index 3be021793cc8b..01bf3fcb3eca5 100644
---- a/drivers/usb/host/xhci-mvebu.h
-+++ b/drivers/usb/host/xhci-mvebu.h
-@@ -12,6 +12,7 @@ struct usb_hcd;
-
- #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
- int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
-+int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd);
- int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
- #else
- static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
-@@ -19,6 +20,11 @@ static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
- return 0;
- }
-
-+static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
-+{
-+ return 0;
-+}
-+
- static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
- {
- return 0;
-diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
-index 4d34f6005381e..c1edcc9b13cec 100644
---- a/drivers/usb/host/xhci-plat.c
-+++ b/drivers/usb/host/xhci-plat.c
-@@ -44,6 +44,16 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd)
- priv->plat_start(hcd);
- }
-
-+static int xhci_priv_plat_setup(struct usb_hcd *hcd)
-+{
-+ struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
-+
-+ if (!priv->plat_setup)
-+ return 0;
-+
-+ return priv->plat_setup(hcd);
-+}
-+
- static int xhci_priv_init_quirk(struct usb_hcd *hcd)
- {
- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
-@@ -111,6 +121,7 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = {
- };
-
- static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
-+ .plat_setup = xhci_mvebu_a3700_plat_setup,
- .init_quirk = xhci_mvebu_a3700_init_quirk,
- };
-
-@@ -330,7 +341,14 @@ static int xhci_plat_probe(struct platform_device *pdev)
-
- hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
- xhci->shared_hcd->tpl_support = hcd->tpl_support;
-- if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
-+
-+ if (priv) {
-+ ret = xhci_priv_plat_setup(hcd);
-+ if (ret)
-+ goto disable_usb_phy;
-+ }
-+
-+ if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
- hcd->skip_phy_initialization = 1;
-
- if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
-diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
-index 1fb149d1fbcea..561d0b7bce098 100644
---- a/drivers/usb/host/xhci-plat.h
-+++ b/drivers/usb/host/xhci-plat.h
-@@ -13,6 +13,7 @@
- struct xhci_plat_priv {
- const char *firmware_name;
- unsigned long long quirks;
-+ int (*plat_setup)(struct usb_hcd *);
- void (*plat_start)(struct usb_hcd *);
- int (*init_quirk)(struct usb_hcd *);
- int (*suspend_quirk)(struct usb_hcd *);
---
-2.27.0
-
--- /dev/null
+From 9917f0e3cdba7b9f1a23f70e3f70b1a106be54a8 Mon Sep 17 00:00:00 2001
+From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Date: Mon, 1 Feb 2021 21:47:20 +0900
+Subject: usb: renesas_usbhs: Clear pipe running flag in usbhs_pkt_pop()
+
+From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+
+commit 9917f0e3cdba7b9f1a23f70e3f70b1a106be54a8 upstream.
+
+Should clear the pipe running flag in usbhs_pkt_pop(). Otherwise,
+we cannot use this pipe after dequeue was called while the pipe was
+running.
+
+Fixes: 8355b2b3082d ("usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle")
+Reported-by: Tho Vu <tho.vu.wh@renesas.com>
+Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
+Link: https://lore.kernel.org/r/1612183640-8898-1-git-send-email-yoshihiro.shimoda.uh@renesas.com
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/renesas_usbhs/fifo.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/renesas_usbhs/fifo.c
++++ b/drivers/usb/renesas_usbhs/fifo.c
+@@ -126,6 +126,7 @@ struct usbhs_pkt *usbhs_pkt_pop(struct u
+ }
+
+ usbhs_pipe_clear_without_sequence(pipe, 0, 0);
++ usbhs_pipe_running(pipe, 0);
+
+ __usbhsf_pkt_del(pkt);
+ }
--- /dev/null
+From d8c6edfa3f4ee0d45d7ce5ef18d1245b78774b9d Mon Sep 17 00:00:00 2001
+From: Jeremy Figgins <kernel@jeremyfiggins.com>
+Date: Sat, 23 Jan 2021 18:21:36 -0600
+Subject: USB: usblp: don't call usb_set_interface if there's a single alt
+
+From: Jeremy Figgins <kernel@jeremyfiggins.com>
+
+commit d8c6edfa3f4ee0d45d7ce5ef18d1245b78774b9d upstream.
+
+Some devices, such as the Winbond Electronics Corp. Virtual Com Port
+(Vendor=0416, ProdId=5011), lockup when usb_set_interface() or
+usb_clear_halt() are called. This device has only a single
+altsetting, so it should not be necessary to call usb_set_interface().
+
+Acked-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Jeremy Figgins <kernel@jeremyfiggins.com>
+Link: https://lore.kernel.org/r/YAy9kJhM/rG8EQXC@watson
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/class/usblp.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/class/usblp.c
++++ b/drivers/usb/class/usblp.c
+@@ -1329,14 +1329,17 @@ static int usblp_set_protocol(struct usb
+ if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL)
+ return -EINVAL;
+
+- alts = usblp->protocol[protocol].alt_setting;
+- if (alts < 0)
+- return -EINVAL;
+- r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
+- if (r < 0) {
+- printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
+- alts, usblp->ifnum);
+- return r;
++ /* Don't unnecessarily set the interface if there's a single alt. */
++ if (usblp->intf->num_altsetting > 1) {
++ alts = usblp->protocol[protocol].alt_setting;
++ if (alts < 0)
++ return -EINVAL;
++ r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
++ if (r < 0) {
++ printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
++ alts, usblp->ifnum);
++ return r;
++ }
+ }
+
+ usblp->bidir = (usblp->protocol[protocol].epread != NULL);
--- /dev/null
+From a50ea34d6dd00a12c9cd29cf7b0fa72816bffbcb Mon Sep 17 00:00:00 2001
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Date: Tue, 2 Feb 2021 16:38:24 +0800
+Subject: usb: xhci-mtk: break loop when find the endpoint to drop
+
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+
+commit a50ea34d6dd00a12c9cd29cf7b0fa72816bffbcb upstream.
+
+No need to check the following endpoints after finding the endpoint
+wanted to drop.
+
+Fixes: 54f6a8af3722 ("usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints")
+Cc: stable <stable@vger.kernel.org>
+Reported-by: Ikjoon Jang <ikjn@chromium.org>
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Link: https://lore.kernel.org/r/1612255104-5363-1-git-send-email-chunfeng.yun@mediatek.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-mtk-sch.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-mtk-sch.c
++++ b/drivers/usb/host/xhci-mtk-sch.c
+@@ -689,8 +689,10 @@ void xhci_mtk_drop_ep_quirk(struct usb_h
+ sch_bw = &sch_array[bw_index];
+
+ list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
+- if (sch_ep->ep == ep)
++ if (sch_ep->ep == ep) {
+ destroy_sch_ep(udev, sch_bw, sch_ep);
++ break;
++ }
+ }
+ }
+ EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
--- /dev/null
+From 1d69f9d901ef14d81c3b004e3282b8cc7b456280 Mon Sep 17 00:00:00 2001
+From: Ikjoon Jang <ikjn@chromium.org>
+Date: Wed, 13 Jan 2021 18:05:11 +0800
+Subject: usb: xhci-mtk: fix unreleased bandwidth data
+
+From: Ikjoon Jang <ikjn@chromium.org>
+
+commit 1d69f9d901ef14d81c3b004e3282b8cc7b456280 upstream.
+
+xhci-mtk needs XHCI_MTK_HOST quirk functions in add_endpoint() and
+drop_endpoint() to handle its own sw bandwidth management.
+
+It stores bandwidth data into an internal table every time
+add_endpoint() is called, and drops those in drop_endpoint().
+But when bandwidth allocation fails at one endpoint, all earlier
+allocation from the same interface could still remain at the table.
+
+This patch moves bandwidth management codes to check_bandwidth() and
+reset_bandwidth() path. To do so, this patch also adds those functions
+to xhci_driver_overrides and lets mtk-xhci to release all failed
+endpoints in reset_bandwidth() path.
+
+Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with multi-TT")
+Signed-off-by: Ikjoon Jang <ikjn@chromium.org>
+Link: https://lore.kernel.org/r/20210113180444.v6.1.Id0d31b5f3ddf5e734d2ab11161ac5821921b1e1e@changeid
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-mtk-sch.c | 123 +++++++++++++++++++++++++++-------------
+ drivers/usb/host/xhci-mtk.c | 2
+ drivers/usb/host/xhci-mtk.h | 13 ++++
+ drivers/usb/host/xhci.c | 8 +-
+ drivers/usb/host/xhci.h | 4 +
+ 5 files changed, 111 insertions(+), 39 deletions(-)
+
+--- a/drivers/usb/host/xhci-mtk-sch.c
++++ b/drivers/usb/host/xhci-mtk-sch.c
+@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_s
+
+ sch_ep->sch_tt = tt;
+ sch_ep->ep = ep;
++ INIT_LIST_HEAD(&sch_ep->tt_endpoint);
+
+ return sch_ep;
+ }
+@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mt
+
+ mtk->sch_array = sch_array;
+
++ INIT_LIST_HEAD(&mtk->bw_ep_list_new);
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
+@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd
+ struct xhci_ep_ctx *ep_ctx;
+ struct xhci_slot_ctx *slot_ctx;
+ struct xhci_virt_device *virt_dev;
+- struct mu3h_sch_bw_info *sch_bw;
+ struct mu3h_sch_ep_info *sch_ep;
+- struct mu3h_sch_bw_info *sch_array;
+ unsigned int ep_index;
+- int bw_index;
+- int ret = 0;
+
+ xhci = hcd_to_xhci(hcd);
+ virt_dev = xhci->devs[udev->slot_id];
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+ slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
+ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+- sch_array = mtk->sch_array;
+
+ xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
+ __func__, usb_endpoint_type(&ep->desc), udev->speed,
+@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd
+ return 0;
+ }
+
+- bw_index = get_bw_index(xhci, udev, ep);
+- sch_bw = &sch_array[bw_index];
+-
+ sch_ep = create_sch_ep(udev, ep, ep_ctx);
+ if (IS_ERR_OR_NULL(sch_ep))
+ return -ENOMEM;
+
+ setup_sch_info(udev, ep_ctx, sch_ep);
+
+- ret = check_sch_bw(udev, sch_bw, sch_ep);
+- if (ret) {
+- xhci_err(xhci, "Not enough bandwidth!\n");
+- if (is_fs_or_ls(udev->speed))
+- drop_tt(udev);
+-
+- kfree(sch_ep);
+- return -ENOSPC;
+- }
++ list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new);
+
+- list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
++ return 0;
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
+
+- ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
+- | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
+- ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
+- | EP_BREPEAT(sch_ep->repeat));
++static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
++ struct mu3h_sch_ep_info *sch_ep)
++{
++ struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
++ int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
++ struct mu3h_sch_bw_info *sch_bw = &mtk->sch_array[bw_index];
+
+- xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
+- sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
+- sch_ep->offset, sch_ep->repeat);
++ update_bus_bw(sch_bw, sch_ep, 0);
++ list_del(&sch_ep->endpoint);
+
+- return 0;
++ if (sch_ep->sch_tt) {
++ list_del(&sch_ep->tt_endpoint);
++ drop_tt(udev);
++ }
++ kfree(sch_ep);
+ }
+-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
+
+ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+@@ -675,7 +668,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_h
+ struct xhci_virt_device *virt_dev;
+ struct mu3h_sch_bw_info *sch_array;
+ struct mu3h_sch_bw_info *sch_bw;
+- struct mu3h_sch_ep_info *sch_ep;
++ struct mu3h_sch_ep_info *sch_ep, *tmp;
+ int bw_index;
+
+ xhci = hcd_to_xhci(hcd);
+@@ -694,17 +687,73 @@ void xhci_mtk_drop_ep_quirk(struct usb_h
+ bw_index = get_bw_index(xhci, udev, ep);
+ sch_bw = &sch_array[bw_index];
+
+- list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
++ list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
+ if (sch_ep->ep == ep) {
+- update_bus_bw(sch_bw, sch_ep, 0);
+- list_del(&sch_ep->endpoint);
+- if (is_fs_or_ls(udev->speed)) {
+- list_del(&sch_ep->tt_endpoint);
+- drop_tt(udev);
+- }
+- kfree(sch_ep);
+- break;
++ xhci_mtk_drop_ep(mtk, udev, sch_ep);
+ }
+ }
+ }
+ EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
++
++int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
++{
++ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
++ struct mu3h_sch_bw_info *sch_bw;
++ struct mu3h_sch_ep_info *sch_ep, *tmp;
++ int bw_index, ret;
++
++ dev_dbg(&udev->dev, "%s\n", __func__);
++
++ list_for_each_entry(sch_ep, &mtk->bw_ep_list_new, endpoint) {
++ bw_index = get_bw_index(xhci, udev, sch_ep->ep);
++ sch_bw = &mtk->sch_array[bw_index];
++
++ ret = check_sch_bw(udev, sch_bw, sch_ep);
++ if (ret) {
++ xhci_err(xhci, "Not enough bandwidth!\n");
++ return -ENOSPC;
++ }
++ }
++
++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) {
++ struct xhci_ep_ctx *ep_ctx;
++ struct usb_host_endpoint *ep = sch_ep->ep;
++ unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
++
++ bw_index = get_bw_index(xhci, udev, ep);
++ sch_bw = &mtk->sch_array[bw_index];
++
++ list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
++
++ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
++ ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
++ | EP_BCSCOUNT(sch_ep->cs_count)
++ | EP_BBM(sch_ep->burst_mode));
++ ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
++ | EP_BREPEAT(sch_ep->repeat));
++
++ xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
++ sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
++ sch_ep->offset, sch_ep->repeat);
++ }
++
++ return xhci_check_bandwidth(hcd, udev);
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth);
++
++void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
++{
++ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++ struct mu3h_sch_ep_info *sch_ep, *tmp;
++
++ dev_dbg(&udev->dev, "%s\n", __func__);
++
++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) {
++ xhci_mtk_drop_ep(mtk, udev, sch_ep);
++ }
++
++ xhci_reset_bandwidth(hcd, udev);
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth);
+--- a/drivers/usb/host/xhci-mtk.c
++++ b/drivers/usb/host/xhci-mtk.c
+@@ -347,6 +347,8 @@ static void usb_wakeup_set(struct xhci_h
+ static int xhci_mtk_setup(struct usb_hcd *hcd);
+ static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
+ .reset = xhci_mtk_setup,
++ .check_bandwidth = xhci_mtk_check_bandwidth,
++ .reset_bandwidth = xhci_mtk_reset_bandwidth,
+ };
+
+ static struct hc_driver __read_mostly xhci_mtk_hc_driver;
+--- a/drivers/usb/host/xhci-mtk.h
++++ b/drivers/usb/host/xhci-mtk.h
+@@ -130,6 +130,7 @@ struct mu3c_ippc_regs {
+ struct xhci_hcd_mtk {
+ struct device *dev;
+ struct usb_hcd *hcd;
++ struct list_head bw_ep_list_new;
+ struct mu3h_sch_bw_info *sch_array;
+ struct mu3c_ippc_regs __iomem *ippc_regs;
+ bool has_ippc;
+@@ -166,6 +167,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd
+ struct usb_host_endpoint *ep);
+ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
++int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
++void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+
+ #else
+ static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd,
+@@ -179,6 +182,16 @@ static inline void xhci_mtk_drop_ep_quir
+ {
+ }
+
++static inline int xhci_mtk_check_bandwidth(struct usb_hcd *hcd,
++ struct usb_device *udev)
++{
++ return 0;
++}
++
++static inline void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd,
++ struct usb_device *udev)
++{
++}
+ #endif
+
+ #endif /* _XHCI_MTK_H_ */
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -2861,7 +2861,7 @@ static void xhci_check_bw_drop_ep_stream
+ * else should be touching the xhci->devs[slot_id] structure, so we
+ * don't need to take the xhci->lock for manipulating that.
+ */
+-static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
++int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+ {
+ int i;
+ int ret = 0;
+@@ -2959,7 +2959,7 @@ command_cleanup:
+ return ret;
+ }
+
+-static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
++void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+ {
+ struct xhci_hcd *xhci;
+ struct xhci_virt_device *virt_dev;
+@@ -5385,6 +5385,10 @@ void xhci_init_driver(struct hc_driver *
+ drv->reset = over->reset;
+ if (over->start)
+ drv->start = over->start;
++ if (over->check_bandwidth)
++ drv->check_bandwidth = over->check_bandwidth;
++ if (over->reset_bandwidth)
++ drv->reset_bandwidth = over->reset_bandwidth;
+ }
+ }
+ EXPORT_SYMBOL_GPL(xhci_init_driver);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1916,6 +1916,8 @@ struct xhci_driver_overrides {
+ size_t extra_priv_size;
+ int (*reset)(struct usb_hcd *hcd);
+ int (*start)(struct usb_hcd *hcd);
++ int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
++ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
+ };
+
+ #define XHCI_CFC_DELAY 10
+@@ -2070,6 +2072,8 @@ int xhci_gen_setup(struct usb_hcd *hcd,
+ void xhci_shutdown(struct usb_hcd *hcd);
+ void xhci_init_driver(struct hc_driver *drv,
+ const struct xhci_driver_overrides *over);
++int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
++void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
+ int xhci_ext_cap_init(struct xhci_hcd *xhci);
+
--- /dev/null
+From 54f6a8af372213a254af6609758d99f7c0b6b5ad Mon Sep 17 00:00:00 2001
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Date: Mon, 1 Feb 2021 13:57:44 +0800
+Subject: usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints
+
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+
+commit 54f6a8af372213a254af6609758d99f7c0b6b5ad upstream.
+
+For those unchecked endpoints, we don't allocate bandwidth for
+them, so no need free the bandwidth, otherwise will decrease
+the allocated bandwidth.
+Meanwhile use xhci_dbg() instead of dev_dbg() to print logs and
+rename bw_ep_list_new as bw_ep_chk_list.
+
+Fixes: 1d69f9d901ef ("usb: xhci-mtk: fix unreleased bandwidth data")
+Cc: stable <stable@vger.kernel.org>
+Reviewed-and-tested-by: Ikjoon Jang <ikjn@chromium.org>
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Link: https://lore.kernel.org/r/1612159064-28413-1-git-send-email-chunfeng.yun@mediatek.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-mtk-sch.c | 61 +++++++++++++++++++++-------------------
+ drivers/usb/host/xhci-mtk.h | 4 +-
+ 2 files changed, 36 insertions(+), 29 deletions(-)
+
+--- a/drivers/usb/host/xhci-mtk-sch.c
++++ b/drivers/usb/host/xhci-mtk-sch.c
+@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_s
+
+ sch_ep->sch_tt = tt;
+ sch_ep->ep = ep;
++ INIT_LIST_HEAD(&sch_ep->endpoint);
+ INIT_LIST_HEAD(&sch_ep->tt_endpoint);
+
+ return sch_ep;
+@@ -374,6 +375,7 @@ static void update_bus_bw(struct mu3h_sc
+ sch_ep->bw_budget_table[j];
+ }
+ }
++ sch_ep->allocated = used;
+ }
+
+ static int check_sch_tt(struct usb_device *udev,
+@@ -542,6 +544,22 @@ static int check_sch_bw(struct usb_devic
+ return 0;
+ }
+
++static void destroy_sch_ep(struct usb_device *udev,
++ struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
++{
++ /* only release ep bw check passed by check_sch_bw() */
++ if (sch_ep->allocated)
++ update_bus_bw(sch_bw, sch_ep, 0);
++
++ list_del(&sch_ep->endpoint);
++
++ if (sch_ep->sch_tt) {
++ list_del(&sch_ep->tt_endpoint);
++ drop_tt(udev);
++ }
++ kfree(sch_ep);
++}
++
+ static bool need_bw_sch(struct usb_host_endpoint *ep,
+ enum usb_device_speed speed, int has_tt)
+ {
+@@ -584,7 +602,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mt
+
+ mtk->sch_array = sch_array;
+
+- INIT_LIST_HEAD(&mtk->bw_ep_list_new);
++ INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
+
+ return 0;
+ }
+@@ -636,29 +654,12 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd
+
+ setup_sch_info(udev, ep_ctx, sch_ep);
+
+- list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new);
++ list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list);
+
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
+
+-static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
+- struct mu3h_sch_ep_info *sch_ep)
+-{
+- struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
+- int bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+- struct mu3h_sch_bw_info *sch_bw = &mtk->sch_array[bw_index];
+-
+- update_bus_bw(sch_bw, sch_ep, 0);
+- list_del(&sch_ep->endpoint);
+-
+- if (sch_ep->sch_tt) {
+- list_del(&sch_ep->tt_endpoint);
+- drop_tt(udev);
+- }
+- kfree(sch_ep);
+-}
+-
+ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+ {
+@@ -688,9 +689,8 @@ void xhci_mtk_drop_ep_quirk(struct usb_h
+ sch_bw = &sch_array[bw_index];
+
+ list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
+- if (sch_ep->ep == ep) {
+- xhci_mtk_drop_ep(mtk, udev, sch_ep);
+- }
++ if (sch_ep->ep == ep)
++ destroy_sch_ep(udev, sch_bw, sch_ep);
+ }
+ }
+ EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
+@@ -704,9 +704,9 @@ int xhci_mtk_check_bandwidth(struct usb_
+ struct mu3h_sch_ep_info *sch_ep, *tmp;
+ int bw_index, ret;
+
+- dev_dbg(&udev->dev, "%s\n", __func__);
++ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
+
+- list_for_each_entry(sch_ep, &mtk->bw_ep_list_new, endpoint) {
++ list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) {
+ bw_index = get_bw_index(xhci, udev, sch_ep->ep);
+ sch_bw = &mtk->sch_array[bw_index];
+
+@@ -717,7 +717,7 @@ int xhci_mtk_check_bandwidth(struct usb_
+ }
+ }
+
+- list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) {
++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
+ struct xhci_ep_ctx *ep_ctx;
+ struct usb_host_endpoint *ep = sch_ep->ep;
+ unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
+@@ -746,12 +746,17 @@ EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwid
+ void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+ {
+ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++ struct mu3h_sch_bw_info *sch_bw;
+ struct mu3h_sch_ep_info *sch_ep, *tmp;
++ int bw_index;
+
+- dev_dbg(&udev->dev, "%s\n", __func__);
++ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
+
+- list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) {
+- xhci_mtk_drop_ep(mtk, udev, sch_ep);
++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
++ bw_index = get_bw_index(xhci, udev, sch_ep->ep);
++ sch_bw = &mtk->sch_array[bw_index];
++ destroy_sch_ep(udev, sch_bw, sch_ep);
+ }
+
+ xhci_reset_bandwidth(hcd, udev);
+--- a/drivers/usb/host/xhci-mtk.h
++++ b/drivers/usb/host/xhci-mtk.h
+@@ -59,6 +59,7 @@ struct mu3h_sch_bw_info {
+ * @ep_type: endpoint type
+ * @maxpkt: max packet size of endpoint
+ * @ep: address of usb_host_endpoint struct
++ * @allocated: the bandwidth is aready allocated from bus_bw
+ * @offset: which uframe of the interval that transfer should be
+ * scheduled first time within the interval
+ * @repeat: the time gap between two uframes that transfers are
+@@ -86,6 +87,7 @@ struct mu3h_sch_ep_info {
+ u32 ep_type;
+ u32 maxpkt;
+ void *ep;
++ bool allocated;
+ /*
+ * mtk xHCI scheduling information put into reserved DWs
+ * in ep context
+@@ -130,8 +132,8 @@ struct mu3c_ippc_regs {
+ struct xhci_hcd_mtk {
+ struct device *dev;
+ struct usb_hcd *hcd;
+- struct list_head bw_ep_list_new;
+ struct mu3h_sch_bw_info *sch_array;
++ struct list_head bw_ep_chk_list;
+ struct mu3c_ippc_regs __iomem *ippc_regs;
+ bool has_ippc;
+ int num_u2_ports;