diff mbox series

usb: xhci-mtk: fix unreleased bandwidth data

Message ID 20201130133405.1.I9b39c0765ef95f473b4b16b1f8c7714a1eed3842@changeid (mailing list archive)
State New, archived
Headers show
Series usb: xhci-mtk: fix unreleased bandwidth data | expand

Commit Message

Ikjoon Jang Nov. 30, 2020, 5:38 a.m. UTC
xhci-mtk has hooks on add_endpoint() and drop_endpoint() from xhci
to handle its own sw bandwidth managements and stores bandwidth data
into internal table every time add_endpoint() is called,
so when one endpoint's bandwidth allocation fails, all earlier
endpoints from same interface still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), so mtk-xhci can releases all remaining
allocations in reset_bandwidth().

Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
Signed-off-by: Ikjoon Jang <ikjn@chromium.org>
---

 drivers/usb/host/xhci-mtk-sch.c | 163 ++++++++++++++++++++------------
 drivers/usb/host/xhci-mtk.h     |  13 +++
 drivers/usb/host/xhci.c         |   9 ++
 3 files changed, 123 insertions(+), 62 deletions(-)

Comments

kernel test robot Dec. 2, 2020, 3:34 p.m. UTC | #1
Hi Ikjoon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v5.10-rc6 next-20201201]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Ikjoon-Jang/usb-xhci-mtk-fix-unreleased-bandwidth-data/20201130-134136
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: nios2-randconfig-r021-20201202 (attached as .config)
compiler: nios2-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/324226ecfa4a9c871325f040e886589fbbff2262
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Ikjoon-Jang/usb-xhci-mtk-fix-unreleased-bandwidth-data/20201130-134136
        git checkout 324226ecfa4a9c871325f040e886589fbbff2262
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=nios2 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/usb/host/xhci-mtk-sch.c: In function 'xhci_mtk_add_ep_quirk':
>> drivers/usb/host/xhci-mtk-sch.c:606:27: warning: variable 'sch_array' set but not used [-Wunused-but-set-variable]
     606 |  struct mu3h_sch_bw_info *sch_array;
         |                           ^~~~~~~~~

vim +/sch_array +606 drivers/usb/host/xhci-mtk-sch.c

0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  596  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  597  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  598  		struct usb_host_endpoint *ep)
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  599  {
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  600  	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
324226ecfa4a9c8 Ikjoon Jang  2020-11-30  601  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  602  	struct xhci_ep_ctx *ep_ctx;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  603  	struct xhci_slot_ctx *slot_ctx;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  604  	struct xhci_virt_device *virt_dev;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  605  	struct mu3h_sch_ep_info *sch_ep;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24 @606  	struct mu3h_sch_bw_info *sch_array;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  607  	unsigned int ep_index;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  608  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  609  	virt_dev = xhci->devs[udev->slot_id];
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  610  	ep_index = xhci_get_endpoint_index(&ep->desc);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  611  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  612  	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  613  	sch_array = mtk->sch_array;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  614  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  615  	xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  616  		__func__, usb_endpoint_type(&ep->desc), udev->speed,
734d3ddd81902d8 Felipe Balbi 2016-09-28  617  		usb_endpoint_maxp(&ep->desc),
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  618  		usb_endpoint_dir_in(&ep->desc), ep);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  619  
b765a16a11fad6b Chunfeng Yun 2016-01-26  620  	if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) {
b765a16a11fad6b Chunfeng Yun 2016-01-26  621  		/*
b765a16a11fad6b Chunfeng Yun 2016-01-26  622  		 * set @bpkts to 1 if it is LS or FS periodic endpoint, and its
b765a16a11fad6b Chunfeng Yun 2016-01-26  623  		 * device does not connected through an external HS hub
b765a16a11fad6b Chunfeng Yun 2016-01-26  624  		 */
b765a16a11fad6b Chunfeng Yun 2016-01-26  625  		if (usb_endpoint_xfer_int(&ep->desc)
b765a16a11fad6b Chunfeng Yun 2016-01-26  626  			|| usb_endpoint_xfer_isoc(&ep->desc))
b765a16a11fad6b Chunfeng Yun 2016-01-26  627  			ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(1));
b765a16a11fad6b Chunfeng Yun 2016-01-26  628  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  629  		return 0;
b765a16a11fad6b Chunfeng Yun 2016-01-26  630  	}
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  631  
95b516c18621d16 Chunfeng Yun 2018-09-20  632  	sch_ep = create_sch_ep(udev, ep, ep_ctx);
324226ecfa4a9c8 Ikjoon Jang  2020-11-30  633  
95b516c18621d16 Chunfeng Yun 2018-09-20  634  	if (IS_ERR_OR_NULL(sch_ep))
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  635  		return -ENOMEM;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  636  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  637  	setup_sch_info(udev, ep_ctx, sch_ep);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  638  
324226ecfa4a9c8 Ikjoon Jang  2020-11-30  639  	list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  640  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  641  	ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  642  		| EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  643  	ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  644  		| EP_BREPEAT(sch_ep->repeat));
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  645  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  646  	xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  647  			sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  648  			sch_ep->offset, sch_ep->repeat);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  649  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  650  	return 0;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  651  }
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  652  EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  653  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 45c54d56ecbd..6fdc7be29420 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -49,9 +49,11 @@  static int is_fs_or_ls(enum usb_device_speed speed)
 * so the bandwidth domain array is organized as follow for simplification:
 * SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
 */
-static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
-	struct usb_host_endpoint *ep)
+static struct mu3h_sch_bw_info *get_bw_info(struct xhci_hcd_mtk *mtk,
+					     struct usb_device *udev,
+					     struct usb_host_endpoint *ep)
 {
+	struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
 	struct xhci_virt_device *virt_dev;
 	int bw_index;
 
@@ -67,7 +69,7 @@  static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
 		bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1;
 	}
 
-	return bw_index;
+	return &mtk->sch_array[bw_index];
 }
 
 static u32 get_esit(struct xhci_ep_ctx *ep_ctx)
@@ -172,7 +174,6 @@  static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
 	struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
 {
 	struct mu3h_sch_ep_info *sch_ep;
-	struct mu3h_sch_tt *tt = NULL;
 	u32 len_bw_budget_table;
 	size_t mem_size;
 
@@ -190,15 +191,6 @@  static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
 	if (!sch_ep)
 		return ERR_PTR(-ENOMEM);
 
-	if (is_fs_or_ls(udev->speed)) {
-		tt = find_tt(udev);
-		if (IS_ERR(tt)) {
-			kfree(sch_ep);
-			return ERR_PTR(-ENOMEM);
-		}
-	}
-
-	sch_ep->sch_tt = tt;
 	sch_ep->ep = ep;
 
 	return sch_ep;
@@ -375,10 +367,10 @@  static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
 	}
 }
 
-static int check_sch_tt(struct usb_device *udev,
-	struct mu3h_sch_ep_info *sch_ep, u32 offset)
+static int check_sch_tt(struct mu3h_sch_tt *tt,
+			struct mu3h_sch_ep_info *sch_ep,
+			u32 offset)
 {
-	struct mu3h_sch_tt *tt = sch_ep->sch_tt;
 	u32 extra_cs_count;
 	u32 fs_budget_start;
 	u32 start_ss, last_ss;
@@ -448,10 +440,9 @@  static int check_sch_tt(struct usb_device *udev,
 	return 0;
 }
 
-static void update_sch_tt(struct usb_device *udev,
-	struct mu3h_sch_ep_info *sch_ep)
+static void update_sch_tt(struct mu3h_sch_tt *tt,
+			  struct mu3h_sch_ep_info *sch_ep)
 {
-	struct mu3h_sch_tt *tt = sch_ep->sch_tt;
 	u32 base, num_esit;
 	int i, j;
 
@@ -463,6 +454,7 @@  static void update_sch_tt(struct usb_device *udev,
 	}
 
 	list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list);
+	sch_ep->sch_tt = tt;
 }
 
 static int check_sch_bw(struct usb_device *udev,
@@ -476,22 +468,28 @@  static int check_sch_bw(struct usb_device *udev,
 	u32 bw_boundary;
 	u32 min_num_budget;
 	u32 min_cs_count;
+	struct mu3h_sch_tt *tt = NULL;
 	bool tt_offset_ok = false;
 	int ret;
 
-	esit = sch_ep->esit;
+	if (is_fs_or_ls(udev->speed)) {
+		tt = find_tt(udev);
+		if (IS_ERR(tt))
+			return -ENOMEM;
+	}
 
 	/*
 	 * Search through all possible schedule microframes.
 	 * and find a microframe where its worst bandwidth is minimum.
 	 */
+	esit = sch_ep->esit;
 	min_bw = ~0;
 	min_index = 0;
 	min_cs_count = sch_ep->cs_count;
 	min_num_budget = sch_ep->num_budget_microframes;
 	for (offset = 0; offset < esit; offset++) {
 		if (is_fs_or_ls(udev->speed)) {
-			ret = check_sch_tt(udev, sch_ep, offset);
+			ret = check_sch_tt(tt, sch_ep, offset);
 			if (ret)
 				continue;
 			else
@@ -529,10 +527,11 @@  static int check_sch_bw(struct usb_device *udev,
 
 	if (is_fs_or_ls(udev->speed)) {
 		/* all offset for tt is not ok*/
-		if (!tt_offset_ok)
+		if (!tt_offset_ok) {
+			drop_tt(udev);
 			return -ERANGE;
-
-		update_sch_tt(udev, sch_ep);
+		}
+		update_sch_tt(tt, sch_ep);
 	}
 
 	/* update bus bandwidth info */
@@ -583,6 +582,8 @@  int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
 
 	mtk->sch_array = sch_array;
 
+	INIT_LIST_HEAD(&mtk->bw_ep_list_new);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
@@ -597,18 +598,14 @@  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
 	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
-	struct xhci_hcd *xhci;
+	struct xhci_hcd *xhci = hcd_to_xhci(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);
@@ -632,26 +629,14 @@  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 		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, &sch_bw->bw_ep_list);
+	list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new);
 
 	ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
 		| EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
@@ -666,22 +651,17 @@  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 }
 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)
+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_mtk *mtk = hcd_to_mtk(hcd);
-	struct xhci_hcd *xhci;
+	struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
 	struct xhci_slot_ctx *slot_ctx;
 	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;
-	int bw_index;
+	struct usb_host_endpoint *ep = sch_ep->ep;
 
-	xhci = hcd_to_xhci(hcd);
 	virt_dev = xhci->devs[udev->slot_id];
 	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
-	sch_array = mtk->sch_array;
 
 	xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
 		__func__, usb_endpoint_type(&ep->desc), udev->speed,
@@ -691,20 +671,79 @@  void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 	if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
 		return;
 
-	bw_index = get_bw_index(xhci, udev, ep);
-	sch_bw = &sch_array[bw_index];
+	sch_bw = get_bw_info(mtk, udev, ep);
 
-	list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
+	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)
+{
+	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+	struct mu3h_sch_bw_info *sch_bw;
+	struct mu3h_sch_ep_info *sch_ep, *tmp;
+
+	sch_bw = get_bw_info(mtk, udev, ep);
+
+	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);
+			xhci_mtk_drop_ep(mtk, udev, sch_ep);
 			break;
 		}
 	}
 }
 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 mu3h_sch_ep_info *sch_ep, *tmp;
+
+	dev_dbg(&udev->dev, "%s\n", __func__);
+
+	list_for_each_entry(sch_ep, &mtk->bw_ep_list_new, endpoint) {
+		int ret;
+		struct mu3h_sch_bw_info *sch_bw;
+
+		sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
+
+		ret = check_sch_bw(udev, sch_bw, sch_ep);
+		if (ret) {
+			xhci_err(xhci, "Not enough bandwidth!\n");
+			return ret;
+		}
+	}
+
+	list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) {
+		struct mu3h_sch_bw_info *sch_bw;
+
+		sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
+
+		list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
+	}
+
+	return 0;
+}
+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);
+	}
+}
+EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth);
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index 5ac458b7d2e0..5ba25b62bf5b 100644
--- 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 *hcd, struct usb_device *udev,
 		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_quirk(struct usb_hcd *hcd,
 {
 }
 
+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_ */
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 0e297378063b..38c3c753bdbf 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2882,6 +2882,12 @@  static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 	xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
 	virt_dev = xhci->devs[udev->slot_id];
 
+	if (xhci->quirks & XHCI_MTK_HOST) {
+		ret = xhci_mtk_check_bandwidth(hcd, udev);
+		if (ret < 0)
+			return ret;
+	}
+
 	command = xhci_alloc_command(xhci, true, GFP_KERNEL);
 	if (!command)
 		return -ENOMEM;
@@ -2970,6 +2976,9 @@  static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 		return;
 	xhci = hcd_to_xhci(hcd);
 
+	if (xhci->quirks & XHCI_MTK_HOST)
+		xhci_mtk_reset_bandwidth(hcd, udev);
+
 	xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
 	virt_dev = xhci->devs[udev->slot_id];
 	/* Free any rings allocated for added endpoints */