diff mbox series

[v2,3/3] usb: xhci-mtk: fix unreleased bandwidth data

Message ID 20201210184700.v2.3.Id0d31b5f3ddf5e734d2ab11161ac5821921b1e1e@changeid (mailing list archive)
State New, archived
Headers show
Series Release allocated periodic bandwidth data from reset_bandwidth() | expand

Commit Message

Ikjoon Jang Dec. 10, 2020, 10:47 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 bandwidth allocation fails at one endpoint, all earlier
allocation from the same interface could still remain at the table.

This patch adds two more hooks from check_bandwidth() and
reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
from reset_bandwidth().

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

---

Changes in v2:
- fix wrong offset in mediatek hw flags
- fix 0-day warnings

 drivers/usb/host/xhci-mtk-sch.c | 120 ++++++++++++++++++++++----------
 drivers/usb/host/xhci-mtk.h     |  13 ++++
 drivers/usb/host/xhci.c         |   9 +++
 3 files changed, 107 insertions(+), 35 deletions(-)

Comments

Greg Kroah-Hartman Dec. 10, 2020, 10:58 a.m. UTC | #1
On Thu, Dec 10, 2020 at 06:47:47PM +0800, Ikjoon Jang wrote:
> 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 bandwidth allocation fails at one endpoint, all earlier
> allocation from the same interface could still remain at the table.
> 
> This patch adds two more hooks from check_bandwidth() and
> reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> from reset_bandwidth().
> 
> Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
> Signed-off-by: Ikjoon Jang <ikjn@chromium.org>

Shouldn't this be the first patch in the series?  You don't want a fix
to be dependent on code style changes, otherwise it is really really
hard to backport it to older kernels that might need this fix, right?

Can you re-order these patches please?

thanks,

greg k-h
kernel test robot Dec. 10, 2020, 2:33 p.m. UTC | #2
Hi Ikjoon,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on balbi-usb/testing/next peter.chen-usb/ci-for-usb-next v5.10-rc7 next-20201210]
[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/Release-allocated-periodic-bandwidth-data-from-reset_bandwidth/20201210-185329
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: xtensa-randconfig-r011-20201209 (attached as .config)
compiler: xtensa-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/a99b1fe33b427dd2ca384c78d50b6d05fb04e56d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Ikjoon-Jang/Release-allocated-periodic-bandwidth-data-from-reset_bandwidth/20201210-185329
        git checkout a99b1fe33b427dd2ca384c78d50b6d05fb04e56d
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=xtensa 

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_bw' set but not used [-Wunused-but-set-variable]
     606 |  struct mu3h_sch_bw_info *sch_bw;
         |                           ^~~~~~

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

0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  597  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  598  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  599  		struct usb_host_endpoint *ep)
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  600  {
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  601  	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
a99b1fe33b427dd Ikjoon Jang  2020-12-10  602  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  603  	struct xhci_ep_ctx *ep_ctx;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  604  	struct xhci_slot_ctx *slot_ctx;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  605  	struct xhci_virt_device *virt_dev;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24 @606  	struct mu3h_sch_bw_info *sch_bw;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  607  	struct mu3h_sch_ep_info *sch_ep;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  608  	unsigned int ep_index;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  609  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  610  	virt_dev = xhci->devs[udev->slot_id];
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  611  	ep_index = xhci_get_endpoint_index(&ep->desc);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  612  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  613  	ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
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  
06cc7c739674e71 Ikjoon Jang  2020-12-10  632  	sch_bw = get_bw_info(mtk, udev, ep);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  633  
95b516c18621d16 Chunfeng Yun 2018-09-20  634  	sch_ep = create_sch_ep(udev, ep, ep_ctx);
95b516c18621d16 Chunfeng Yun 2018-09-20  635  	if (IS_ERR_OR_NULL(sch_ep))
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  636  		return -ENOMEM;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  637  
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  638  	setup_sch_info(udev, ep_ctx, sch_ep);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  639  
a99b1fe33b427dd Ikjoon Jang  2020-12-10  640  	list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new);
08e469de87a2534 Chunfeng Yun 2018-09-20  641  
a99b1fe33b427dd Ikjoon Jang  2020-12-10  642  	return 0;
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  643  }
a99b1fe33b427dd Ikjoon Jang  2020-12-10  644  EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
0cbd4b34cda9dfd Chunfeng Yun 2015-11-24  645  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Ikjoon Jang Dec. 11, 2020, 6:27 a.m. UTC | #3
On Thu, Dec 10, 2020 at 6:57 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Thu, Dec 10, 2020 at 06:47:47PM +0800, Ikjoon Jang wrote:
> > 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 bandwidth allocation fails at one endpoint, all earlier
> > allocation from the same interface could still remain at the table.
> >
> > This patch adds two more hooks from check_bandwidth() and
> > reset_bandwidth(), and make mtk-xhci to releases all failed endpoints
> > from reset_bandwidth().
> >
> > Fixes: 0cbd4b34cda9 ("xhci: mediatek: support MTK xHCI host controller")
> > Signed-off-by: Ikjoon Jang <ikjn@chromium.org>
>
> Shouldn't this be the first patch in the series?  You don't want a fix
> to be dependent on code style changes, otherwise it is really really
> hard to backport it to older kernels that might need this fix, right?

yes, you're right.

This patchset also requires
"4b0f7a77fb3c usb: xhci-mtk: supports bandwidth scheduling with multi-TT",
which doesn't have a Fixes tag.

I think I can change Fixes to point to that commit (4b0f7a77fb3c),
as this unreleased bandwidth data is much more impactful to
TT bandwidth.

Thanks!

>
> Can you re-order these patches please?
>
> thanks,
>
> greg k-h
diff mbox series

Patch

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 439391f1dc78..102d8e0a50f1 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -583,6 +583,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,16 +599,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;
 	unsigned int ep_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);
@@ -637,42 +637,37 @@  int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 
 	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 mu3h_sch_bw_info *sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
 
-	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)
+			    struct usb_host_endpoint *ep)
 {
 	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
-	struct xhci_hcd *xhci;
-	struct xhci_slot_ctx *slot_ctx;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 	struct xhci_virt_device *virt_dev;
+	struct xhci_slot_ctx *slot_ctx;
 	struct mu3h_sch_bw_info *sch_bw;
-	struct mu3h_sch_ep_info *sch_ep;
+	struct mu3h_sch_ep_info *sch_ep, *tmp;
 
-	xhci = hcd_to_xhci(hcd);
 	virt_dev = xhci->devs[udev->slot_id];
 	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
 
@@ -686,17 +681,72 @@  void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
 
 	sch_bw = get_bw_info(mtk, udev, ep);
 
-	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);
+			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 xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
+	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;
+		struct xhci_ep_ctx *ep_ctx;
+		struct usb_host_endpoint *ep = sch_ep->ep;
+		unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
+
+		sch_bw = get_bw_info(mtk, udev, ep);
+
+		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 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 8be8c5f7ff62..05ca989985fc 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;
@@ -165,6 +166,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,
@@ -178,6 +181,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 2bf6c526ac7a..5a9e01b33688 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2854,6 +2854,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;
@@ -2941,6 +2947,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 */