From patchwork Thu Aug 26 02:51:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458879 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5C9CEC4320A for ; Thu, 26 Aug 2021 02:52:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3EC5760FD9 for ; Thu, 26 Aug 2021 02:52:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238028AbhHZCwv (ORCPT ); Wed, 25 Aug 2021 22:52:51 -0400 Received: from mailgw01.mediatek.com ([60.244.123.138]:42574 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S237025AbhHZCwu (ORCPT ); Wed, 25 Aug 2021 22:52:50 -0400 X-UUID: 063c3d8a60304aea82ebb55f98de02b1-20210826 X-UUID: 063c3d8a60304aea82ebb55f98de02b1-20210826 Received: from mtkcas10.mediatek.inc [(172.21.101.39)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1461335636; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:51:59 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 1/6] Revert "usb: xhci-mtk: relax TT periodic bandwidth allocation" Date: Thu, 26 Aug 2021 10:51:39 +0800 Message-ID: <20210826025144.51992-1-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org As discussed in following patch: https://patchwork.kernel.org/patch/12420339 No need calculate number of uframes again, but should use value form check_sch_tt(), if we plan to remove extra CS, also can do it in check_sch_tt(). So revert this patch, and prepare to send new patch for it. This reverts commit 548011957d1d72e0b662300c8b32b81d593b796e. Cc: Ikjoon Jang Signed-off-by: Chunfeng Yun --- v2: no changes --- drivers/usb/host/xhci-mtk-sch.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 46cbf5d54f4f..f9b4d27ce449 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -459,17 +459,16 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) u32 num_esit, tmp; int base; int i, j; - u8 uframes = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - - if (sch_ep->ep_type == INT_IN_EP || sch_ep->ep_type == ISOC_IN_EP) - offset++; - for (i = 0; i < num_esit; i++) { base = offset + i * sch_ep->esit; - for (j = 0; j < uframes; j++) { + /* + * Compared with hs bus, no matter what ep type, + * the hub will always delay one uframe to send data + */ + for (j = 0; j < sch_ep->cs_count; j++) { tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_cost_per_microframe; if (tmp > FS_PAYLOAD_MAX) return -ESCH_BW_OVERFLOW; @@ -547,8 +546,6 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) u32 base, num_esit; int bw_updated; int i, j; - int offset = sch_ep->offset; - u8 uframes = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; @@ -557,13 +554,10 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) else bw_updated = -sch_ep->bw_cost_per_microframe; - if (sch_ep->ep_type == INT_IN_EP || sch_ep->ep_type == ISOC_IN_EP) - offset++; - for (i = 0; i < num_esit; i++) { - base = offset + i * sch_ep->esit; + base = sch_ep->offset + i * sch_ep->esit; - for (j = 0; j < uframes; j++) + for (j = 0; j < sch_ep->cs_count; j++) tt->fs_bus_bw[base + j] += bw_updated; } From patchwork Thu Aug 26 02:51:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458881 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72F92C432BE for ; Thu, 26 Aug 2021 02:52:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4E11260FDA for ; Thu, 26 Aug 2021 02:52:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237894AbhHZCwu (ORCPT ); Wed, 25 Aug 2021 22:52:50 -0400 Received: from mailgw02.mediatek.com ([210.61.82.184]:32912 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S232441AbhHZCwt (ORCPT ); Wed, 25 Aug 2021 22:52:49 -0400 X-UUID: 40558634375a4e34ace55fa20c347fd6-20210826 X-UUID: 40558634375a4e34ace55fa20c347fd6-20210826 Received: from mtkcas10.mediatek.inc [(172.21.101.39)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1294242977; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:51:59 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 2/6] Revert "usb: xhci-mtk: Do not use xhci's virt_dev in drop_endpoint" Date: Thu, 26 Aug 2021 10:51:40 +0800 Message-ID: <20210826025144.51992-2-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20210826025144.51992-1-chunfeng.yun@mediatek.com> References: <20210826025144.51992-1-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org I find the patch introduce some issues, e.g. 1. oops happens when xhci_gen_setup() failed, and hash is not init but try to destroy it; 2. memory leakage happens when fail to insert ep, need free sch_ep, or insert ep after insert int list; 3. memory leakage happens when fail to allocate sch_array, need destroy rhashtable; 4. it's better to check ep->hcpriv when drop ep; so prefer to revert this patch, and resend it after the issues are fixed. This reverts commit b8731209958a1dffccc2888121f4c0280c990550. Cc: Ikjoon Jang Signed-off-by: Chunfeng Yun --- v2: append new version patch of this one [5/6] suggested by Ikjoon --- drivers/usb/host/xhci-mtk-sch.c | 140 ++++++++++++++------------------ drivers/usb/host/xhci-mtk.h | 15 ++-- 2 files changed, 69 insertions(+), 86 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index f9b4d27ce449..cffcaf4dfa9f 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -80,7 +80,7 @@ decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed) interval /= 1000; } - snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s", + snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s\n", usb_speed_string(speed), usb_endpoint_num(epd), usb_endpoint_dir_in(epd) ? "in" : "out", usb_ep_type_string(usb_endpoint_type(epd)), @@ -129,12 +129,6 @@ get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev, int bw_index; virt_dev = xhci->devs[udev->slot_id]; - if (WARN_ONCE(!virt_dev, "xhci-mtk: usb %s has no virt_dev\n", - dev_name(&udev->dev))) - return NULL; - if (WARN_ONCE(!virt_dev->real_port, "xhci-mtk: usb %s has invalid port number\n", - dev_name(&udev->dev))) - return NULL; if (udev->speed >= USB_SPEED_SUPER) { if (usb_endpoint_dir_out(&ep->desc)) @@ -200,6 +194,7 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev) } return ERR_PTR(-ENOMEM); } + INIT_LIST_HEAD(&tt->ep_list); *ptt = tt; } @@ -229,7 +224,7 @@ static void drop_tt(struct usb_device *udev) } tt = *ptt; - if (!tt || tt->nr_eps > 0) + if (!tt || !list_empty(&tt->ep_list)) return; /* never allocated , or still in use*/ *ptt = NULL; @@ -241,19 +236,13 @@ static void drop_tt(struct usb_device *udev) } } -static struct mu3h_sch_ep_info *create_sch_ep(struct xhci_hcd_mtk *mtk, - struct usb_device *udev, struct usb_host_endpoint *ep, - struct xhci_ep_ctx *ep_ctx) +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; - struct mu3h_sch_bw_info *bw_info; - - bw_info = get_bw_info(mtk, udev, ep); - if (!bw_info) - return ERR_PTR(-ENODEV); if (is_fs_or_ls(udev->speed)) len_bw_budget_table = TT_MICROFRAMES_MAX; @@ -277,10 +266,11 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct xhci_hcd_mtk *mtk, } } - sch_ep->bw_info = bw_info; sch_ep->sch_tt = tt; sch_ep->ep = ep; sch_ep->speed = udev->speed; + INIT_LIST_HEAD(&sch_ep->endpoint); + INIT_LIST_HEAD(&sch_ep->tt_endpoint); return sch_ep; } @@ -562,9 +552,9 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) } if (used) - tt->nr_eps++; - else if (!WARN_ONCE(tt->nr_eps < 1, "unbalanced sch_tt's ep count")) - tt->nr_eps--; + list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); + else + list_del(&sch_ep->tt_endpoint); } static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw, @@ -595,9 +585,9 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) return boundary; } -static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) +static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, + struct mu3h_sch_ep_info *sch_ep) { - struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info; const u32 esit_boundary = get_esit_boundary(sch_ep); const u32 bw_boundary = get_bw_boundary(sch_ep->speed); u32 offset; @@ -643,33 +633,23 @@ static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) return load_ep_bw(sch_bw, sch_ep, true); } -static const struct rhashtable_params sch_ep_table_param = { - .key_len = sizeof(struct usb_host_endpoint *), - .key_offset = offsetof(struct mu3h_sch_ep_info, ep), - .head_offset = offsetof(struct mu3h_sch_ep_info, ep_link), -}; - -static void destroy_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, - struct mu3h_sch_ep_info *sch_ep) +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) - load_ep_bw(sch_ep->bw_info, sch_ep, false); + load_ep_bw(sch_bw, sch_ep, false); if (sch_ep->sch_tt) drop_tt(udev); list_del(&sch_ep->endpoint); - rhashtable_remove_fast(&mtk->sch_ep_table, &sch_ep->ep_link, - sch_ep_table_param); kfree(sch_ep); } -static bool need_bw_sch(struct usb_device *udev, - struct usb_host_endpoint *ep) +static bool need_bw_sch(struct usb_host_endpoint *ep, + enum usb_device_speed speed, int has_tt) { - bool has_tt = udev->tt && udev->tt->hub->parent; - /* only for periodic endpoints */ if (usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_bulk(&ep->desc)) @@ -680,7 +660,7 @@ static bool need_bw_sch(struct usb_device *udev, * a TT are also ignored, root-hub will schedule them directly, * but need set @bpkts field of endpoint context to 1. */ - if (is_fs_or_ls(udev->speed) && !has_tt) + if (is_fs_or_ls(speed) && !has_tt) return false; /* skip endpoint with zero maxpkt */ @@ -695,12 +675,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); struct mu3h_sch_bw_info *sch_array; int num_usb_bus; - int ret; - - /* mu3h_sch_ep_info table, 'usb_host_endpoint*' as a key */ - ret = rhashtable_init(&mtk->sch_ep_table, &sch_ep_table_param); - if (ret) - return ret; + int i; /* ss IN and OUT are separated */ num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports; @@ -709,6 +684,9 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) if (sch_array == NULL) return -ENOMEM; + for (i = 0; i < num_usb_bus; i++) + INIT_LIST_HEAD(&sch_array[i].bw_ep_list); + mtk->sch_array = sch_array; INIT_LIST_HEAD(&mtk->bw_ep_chk_list); @@ -718,7 +696,6 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk) { - rhashtable_destroy(&mtk->sch_ep_table); kfree(mtk->sch_array); } @@ -736,7 +713,9 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - if (!need_bw_sch(udev, ep)) { + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); + + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) { /* * set @bpkts to 1 if it is LS or FS periodic endpoint, and its * device does not connected through an external HS hub @@ -748,22 +727,14 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, return 0; } - xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - - sch_ep = create_sch_ep(mtk, udev, ep, ep_ctx); + sch_ep = create_sch_ep(udev, ep, ep_ctx); if (IS_ERR_OR_NULL(sch_ep)) return -ENOMEM; - if (rhashtable_insert_fast(&mtk->sch_ep_table, &sch_ep->ep_link, - sch_ep_table_param)) - return -EEXIST; - setup_sch_info(ep_ctx, sch_ep); list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list); - xhci_dbg(xhci, "added sch_ep %p : %p\n", sch_ep, ep); - return 0; } @@ -772,20 +743,25 @@ static void drop_ep_quirk(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; - void *key = ep; + struct xhci_virt_device *virt_dev; + struct mu3h_sch_bw_info *sch_bw; + struct mu3h_sch_ep_info *sch_ep, *tmp; - if (!need_bw_sch(udev, ep)) - return; + virt_dev = xhci->devs[udev->slot_id]; xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - sch_ep = rhashtable_lookup_fast(&mtk->sch_ep_table, &key, - sch_ep_table_param); - if (sch_ep) - destroy_sch_ep(mtk, udev, sch_ep); - else - xhci_dbg(xhci, "ep %p is not on the bw table\n", ep); + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) + return; + + 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) { + destroy_sch_ep(udev, sch_bw, sch_ep); + break; + } + } } int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) @@ -793,22 +769,30 @@ 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; + struct mu3h_sch_bw_info *sch_bw; + struct mu3h_sch_ep_info *sch_ep, *tmp; int ret; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); list_for_each_entry(sch_ep, &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); + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); - ret = check_sch_bw(sch_ep); + ret = check_sch_bw(sch_bw, sch_ep); if (ret) { xhci_err(xhci, "Not enough bandwidth! (%s)\n", sch_error_string(-ret)); return -ENOSPC; } + } + + 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); + + 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) @@ -822,23 +806,22 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) sch_ep->offset, sch_ep->repeat); } - ret = xhci_check_bandwidth(hcd, udev); - if (!ret) - INIT_LIST_HEAD(&mtk->bw_ep_chk_list); - - return ret; + return xhci_check_bandwidth(hcd, udev); } 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; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); - list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) - destroy_sch_ep(mtk, udev, sch_ep); + list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); + destroy_sch_ep(udev, sch_bw, sch_ep); + } xhci_reset_bandwidth(hcd, udev); } @@ -867,7 +850,8 @@ int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, if (ret) return ret; - drop_ep_quirk(hcd, udev, ep); + if (ep->hcpriv) + drop_ep_quirk(hcd, udev, ep); return 0; } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index ddcf25524f67..ace432356c41 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -10,7 +10,6 @@ #define _XHCI_MTK_H_ #include -#include #include "xhci.h" @@ -26,34 +25,36 @@ /** * @fs_bus_bw: array to keep track of bandwidth already used for FS - * @nr_eps: number of endpoints using this TT + * @ep_list: Endpoints using this TT */ struct mu3h_sch_tt { u32 fs_bus_bw[XHCI_MTK_MAX_ESIT]; - int nr_eps; + struct list_head ep_list; }; /** * struct mu3h_sch_bw_info: schedule information for bandwidth domain * * @bus_bw: array to keep track of bandwidth already used at each uframes + * @bw_ep_list: eps in the bandwidth domain * * treat a HS root port as a bandwidth domain, but treat a SS root port as * two bandwidth domains, one for IN eps and another for OUT eps. */ struct mu3h_sch_bw_info { u32 bus_bw[XHCI_MTK_MAX_ESIT]; + struct list_head bw_ep_list; }; /** * struct mu3h_sch_ep_info: schedule information for endpoint * - * @bw_info: bandwidth domain which this endpoint belongs * @esit: unit is 125us, equal to 2 << Interval field in ep-context * @num_budget_microframes: number of continuous uframes * (@repeat==1) scheduled within the interval * @bw_cost_per_microframe: bandwidth cost per microframe - * @endpoint: linked into bw_ep_chk_list, used by check_bandwidth hook + * @endpoint: linked into bandwidth domain which it belongs to + * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to * @sch_tt: mu3h_sch_tt linked into * @ep_type: endpoint type * @maxpkt: max packet size of endpoint @@ -81,12 +82,11 @@ struct mu3h_sch_ep_info { u32 num_budget_microframes; u32 bw_cost_per_microframe; struct list_head endpoint; - struct mu3h_sch_bw_info *bw_info; + struct list_head tt_endpoint; struct mu3h_sch_tt *sch_tt; u32 ep_type; u32 maxpkt; struct usb_host_endpoint *ep; - struct rhash_head ep_link; enum usb_device_speed speed; bool allocated; /* @@ -134,7 +134,6 @@ struct xhci_hcd_mtk { struct device *dev; struct usb_hcd *hcd; struct mu3h_sch_bw_info *sch_array; - struct rhashtable sch_ep_table; struct list_head bw_ep_chk_list; struct mu3c_ippc_regs __iomem *ippc_regs; int num_u2_ports; From patchwork Thu Aug 26 02:51:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458885 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CCFA0C432BE for ; Thu, 26 Aug 2021 02:52:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AF14660FDA for ; Thu, 26 Aug 2021 02:52:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238082AbhHZCwx (ORCPT ); Wed, 25 Aug 2021 22:52:53 -0400 Received: from mailgw01.mediatek.com ([60.244.123.138]:42574 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S238000AbhHZCwv (ORCPT ); Wed, 25 Aug 2021 22:52:51 -0400 X-UUID: 5ae065803a324567bb8aa90284e744fd-20210826 X-UUID: 5ae065803a324567bb8aa90284e744fd-20210826 Received: from mtkexhb02.mediatek.inc [(172.21.101.103)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1818477389; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs06n1.mediatek.inc (172.21.101.129) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:51:59 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 3/6] usb: xhci-mtk: update fs bus bandwidth by bw_budget_table Date: Thu, 26 Aug 2021 10:51:41 +0800 Message-ID: <20210826025144.51992-3-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20210826025144.51992-1-chunfeng.yun@mediatek.com> References: <20210826025144.51992-1-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Use @bw_budget_table[] to update fs bus bandwidth due to not all microframes consume @bw_cost_per_microframe, see setup_sch_info(). Signed-off-by: Chunfeng Yun --- v2: new patch, move from another series --- drivers/usb/host/xhci-mtk-sch.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index cffcaf4dfa9f..83abd28269ca 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -458,8 +458,8 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) * Compared with hs bus, no matter what ep type, * the hub will always delay one uframe to send data */ - for (j = 0; j < sch_ep->cs_count; j++) { - tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_cost_per_microframe; + for (j = 0; j < sch_ep->num_budget_microframes; j++) { + tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_budget_table[j]; if (tmp > FS_PAYLOAD_MAX) return -ESCH_BW_OVERFLOW; } @@ -534,21 +534,18 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; u32 base, num_esit; - int bw_updated; int i, j; num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - if (used) - bw_updated = sch_ep->bw_cost_per_microframe; - else - bw_updated = -sch_ep->bw_cost_per_microframe; - for (i = 0; i < num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; - for (j = 0; j < sch_ep->cs_count; j++) - tt->fs_bus_bw[base + j] += bw_updated; + for (j = 0; j < sch_ep->num_budget_microframes; j++) + if (used) + tt->fs_bus_bw[base + j] += sch_ep->bw_budget_table[j]; + else + tt->fs_bus_bw[base + j] -= sch_ep->bw_budget_table[j]; } if (used) From patchwork Thu Aug 26 02:51:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458889 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46DB5C432BE for ; Thu, 26 Aug 2021 02:52:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3090760FE6 for ; Thu, 26 Aug 2021 02:52:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238428AbhHZCxS (ORCPT ); Wed, 25 Aug 2021 22:53:18 -0400 Received: from mailgw02.mediatek.com ([210.61.82.184]:33614 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S238044AbhHZCxQ (ORCPT ); Wed, 25 Aug 2021 22:53:16 -0400 X-UUID: 71d7077333214b0397bed79c36547107-20210826 X-UUID: 71d7077333214b0397bed79c36547107-20210826 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1557332125; Thu, 26 Aug 2021 10:52:21 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs05n2.mediatek.inc (172.21.101.140) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:52:00 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 4/6] usb: xhci-mtk: add a member of num_esit Date: Thu, 26 Aug 2021 10:51:42 +0800 Message-ID: <20210826025144.51992-4-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20210826025144.51992-1-chunfeng.yun@mediatek.com> References: <20210826025144.51992-1-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Add a member num_esit to save the number of esit, then no need caculate it in some functions. Signed-off-by: Chunfeng Yun --- v2: new patch, move from another series --- drivers/usb/host/xhci-mtk-sch.c | 20 +++++++------------- drivers/usb/host/xhci-mtk.h | 2 ++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 83abd28269ca..54c521524bfc 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -297,6 +297,7 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); sch_ep->esit = get_esit(ep_ctx); + sch_ep->num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; sch_ep->ep_type = ep_type; sch_ep->maxpkt = maxpkt; sch_ep->offset = 0; @@ -401,14 +402,12 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep, u32 offset) { - u32 num_esit; u32 max_bw = 0; u32 bw; int i; int j; - num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - for (i = 0; i < num_esit; i++) { + for (i = 0; i < sch_ep->num_esit; i++) { u32 base = offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) { @@ -424,13 +423,11 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep, bool used) { - u32 num_esit; u32 base; int i; int j; - num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - for (i = 0; i < num_esit; i++) { + for (i = 0; i < sch_ep->num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) { if (used) @@ -446,12 +443,11 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; - u32 num_esit, tmp; + u32 tmp; int base; int i, j; - num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - for (i = 0; i < num_esit; i++) { + for (i = 0; i < sch_ep->num_esit; i++) { base = offset + i * sch_ep->esit; /* @@ -533,12 +529,10 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; - u32 base, num_esit; + u32 base; int i, j; - num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; - - for (i = 0; i < num_esit; i++) { + for (i = 0; i < sch_ep->num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index ace432356c41..eb05aaf6edbe 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -50,6 +50,7 @@ struct mu3h_sch_bw_info { * struct mu3h_sch_ep_info: schedule information for endpoint * * @esit: unit is 125us, equal to 2 << Interval field in ep-context + * @num_esit: number of @esit in a period * @num_budget_microframes: number of continuous uframes * (@repeat==1) scheduled within the interval * @bw_cost_per_microframe: bandwidth cost per microframe @@ -79,6 +80,7 @@ struct mu3h_sch_bw_info { */ struct mu3h_sch_ep_info { u32 esit; + u32 num_esit; u32 num_budget_microframes; u32 bw_cost_per_microframe; struct list_head endpoint; From patchwork Thu Aug 26 02:51:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458887 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A455AC43214 for ; Thu, 26 Aug 2021 02:52:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7EE91610A1 for ; Thu, 26 Aug 2021 02:52:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238227AbhHZCw4 (ORCPT ); Wed, 25 Aug 2021 22:52:56 -0400 Received: from mailgw01.mediatek.com ([60.244.123.138]:42656 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S238044AbhHZCww (ORCPT ); Wed, 25 Aug 2021 22:52:52 -0400 X-UUID: 307c47eb0ae9493b8a5c07f830e59e49-20210826 X-UUID: 307c47eb0ae9493b8a5c07f830e59e49-20210826 Received: from mtkcas11.mediatek.inc [(172.21.101.40)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1200171935; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:52:00 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 5/6] usb: xhci-mtk: Do not use xhci's virt_dev in drop_endpoint Date: Thu, 26 Aug 2021 10:51:43 +0800 Message-ID: <20210826025144.51992-5-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20210826025144.51992-1-chunfeng.yun@mediatek.com> References: <20210826025144.51992-1-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org xhci-mtk depends on xhci's internal virt_dev when it retrieves its internal data from usb_host_endpoint both in add_endpoint and drop_endpoint callbacks. But when setup packet was retired by transaction errors in xhci_setup_device() path, a virt_dev for the slot is newly created with real_port 0. This leads to xhci-mtks's NULL pointer dereference from drop_endpoint callback as xhci-mtk assumes that virt_dev's real_port is always started from one. The similar problems were addressed by [1] but that can't cover the failure cases from setup_device. This patch drops the usages of xhci's virt_dev in xhci-mtk's drop_endpoint callback by adopting hashtable for searching mtk's schedule entity from a given usb_host_endpoint pointer instead of searching a linked list. So mtk's drop_endpoint callback doesn't have to rely on virt_dev at all. [1] f351f4b63dac ("usb: xhci-mtk: fix oops when unbind driver") Signed-off-by: Ikjoon Jang Signed-off-by: Chunfeng Yun --- v2: use fixed size hash table instead of rhashtable; fix some issues as described in this series [2/6] --- drivers/usb/host/xhci-mtk-sch.c | 100 ++++++++++++++++---------------- drivers/usb/host/xhci-mtk.h | 11 +++- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index 54c521524bfc..f3c6f078f82d 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -80,7 +80,7 @@ decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed) interval /= 1000; } - snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s\n", + snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s", usb_speed_string(speed), usb_endpoint_num(epd), usb_endpoint_dir_in(epd) ? "in" : "out", usb_ep_type_string(usb_endpoint_type(epd)), @@ -129,6 +129,10 @@ get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev, int bw_index; virt_dev = xhci->devs[udev->slot_id]; + if (!virt_dev->real_port) { + WARN_ONCE(1, "%s invalid real_port\n", dev_name(&udev->dev)); + return NULL; + } if (udev->speed >= USB_SPEED_SUPER) { if (usb_endpoint_dir_out(&ep->desc)) @@ -236,14 +240,20 @@ static void drop_tt(struct usb_device *udev) } } -static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, - struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) +static struct mu3h_sch_ep_info * +create_sch_ep(struct xhci_hcd_mtk *mtk, 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_bw_info *bw_info; struct mu3h_sch_tt *tt = NULL; u32 len_bw_budget_table; size_t mem_size; + bw_info = get_bw_info(mtk, udev, ep); + if (!bw_info) + return ERR_PTR(-ENODEV); + if (is_fs_or_ls(udev->speed)) len_bw_budget_table = TT_MICROFRAMES_MAX; else if ((udev->speed >= USB_SPEED_SUPER) @@ -266,11 +276,13 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, } } + sch_ep->bw_info = bw_info; sch_ep->sch_tt = tt; sch_ep->ep = ep; sch_ep->speed = udev->speed; INIT_LIST_HEAD(&sch_ep->endpoint); INIT_LIST_HEAD(&sch_ep->tt_endpoint); + INIT_HLIST_NODE(&sch_ep->hentry); return sch_ep; } @@ -576,9 +588,9 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) return boundary; } -static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, - struct mu3h_sch_ep_info *sch_ep) +static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) { + struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info; const u32 esit_boundary = get_esit_boundary(sch_ep); const u32 bw_boundary = get_bw_boundary(sch_ep->speed); u32 offset; @@ -624,23 +636,26 @@ static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, return load_ep_bw(sch_bw, sch_ep, true); } -static void destroy_sch_ep(struct usb_device *udev, - struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) +static void destroy_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, + struct mu3h_sch_ep_info *sch_ep) { /* only release ep bw check passed by check_sch_bw() */ if (sch_ep->allocated) - load_ep_bw(sch_bw, sch_ep, false); + load_ep_bw(sch_ep->bw_info, sch_ep, false); if (sch_ep->sch_tt) drop_tt(udev); list_del(&sch_ep->endpoint); + hlist_del(&sch_ep->hentry); kfree(sch_ep); } -static bool need_bw_sch(struct usb_host_endpoint *ep, - enum usb_device_speed speed, int has_tt) +static bool need_bw_sch(struct usb_device *udev, + struct usb_host_endpoint *ep) { + bool has_tt = udev->tt && udev->tt->hub->parent; + /* only for periodic endpoints */ if (usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_bulk(&ep->desc)) @@ -651,7 +666,7 @@ static bool need_bw_sch(struct usb_host_endpoint *ep, * a TT are also ignored, root-hub will schedule them directly, * but need set @bpkts field of endpoint context to 1. */ - if (is_fs_or_ls(speed) && !has_tt) + if (is_fs_or_ls(udev->speed) && !has_tt) return false; /* skip endpoint with zero maxpkt */ @@ -666,7 +681,6 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); struct mu3h_sch_bw_info *sch_array; int num_usb_bus; - int i; /* ss IN and OUT are separated */ num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports; @@ -675,12 +689,10 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) if (sch_array == NULL) return -ENOMEM; - for (i = 0; i < num_usb_bus; i++) - INIT_LIST_HEAD(&sch_array[i].bw_ep_list); - mtk->sch_array = sch_array; INIT_LIST_HEAD(&mtk->bw_ep_chk_list); + hash_init(mtk->sch_ep_hash); return 0; } @@ -704,9 +716,7 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - - if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) { + if (!need_bw_sch(udev, ep)) { /* * set @bpkts to 1 if it is LS or FS periodic endpoint, and its * device does not connected through an external HS hub @@ -718,13 +728,16 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, return 0; } - sch_ep = create_sch_ep(udev, ep, ep_ctx); + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); + + sch_ep = create_sch_ep(mtk, udev, ep, ep_ctx); if (IS_ERR_OR_NULL(sch_ep)) return -ENOMEM; setup_sch_info(ep_ctx, sch_ep); list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list); + hash_add(mtk->sch_ep_hash, &sch_ep->hentry, (unsigned long)ep); return 0; } @@ -734,22 +747,18 @@ static void drop_ep_quirk(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; - struct mu3h_sch_bw_info *sch_bw; - struct mu3h_sch_ep_info *sch_ep, *tmp; - - virt_dev = xhci->devs[udev->slot_id]; - - xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); + struct mu3h_sch_ep_info *sch_ep; + struct hlist_node *hn; - if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) + if (!need_bw_sch(udev, ep)) return; - sch_bw = get_bw_info(mtk, udev, ep); + xhci_err(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); - list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { + hash_for_each_possible_safe(mtk->sch_ep_hash, sch_ep, + hn, hentry, (unsigned long)ep) { if (sch_ep->ep == ep) { - destroy_sch_ep(udev, sch_bw, sch_ep); + destroy_sch_ep(mtk, udev, sch_ep); break; } } @@ -760,30 +769,22 @@ 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; + struct mu3h_sch_ep_info *sch_ep; int ret; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) { - sch_bw = get_bw_info(mtk, udev, sch_ep->ep); + struct xhci_ep_ctx *ep_ctx; + struct usb_host_endpoint *ep = sch_ep->ep; + unsigned int ep_index = xhci_get_endpoint_index(&ep->desc); - ret = check_sch_bw(sch_bw, sch_ep); + ret = check_sch_bw(sch_ep); if (ret) { xhci_err(xhci, "Not enough bandwidth! (%s)\n", sch_error_string(-ret)); return -ENOSPC; } - } - - 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); - - 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) @@ -797,22 +798,23 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) sch_ep->offset, sch_ep->repeat); } - return xhci_check_bandwidth(hcd, udev); + ret = xhci_check_bandwidth(hcd, udev); + if (!ret) + INIT_LIST_HEAD(&mtk->bw_ep_chk_list); + + return ret; } 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; xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); - list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { - sch_bw = get_bw_info(mtk, udev, sch_ep->ep); - destroy_sch_ep(udev, sch_bw, sch_ep); - } + list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) + destroy_sch_ep(mtk, udev, sch_ep); xhci_reset_bandwidth(hcd, udev); } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index eb05aaf6edbe..dc5e83f5c5cc 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -10,11 +10,15 @@ #define _XHCI_MTK_H_ #include +#include #include "xhci.h" #define BULK_CLKS_NUM 5 +/* support at most 64 ep, use 32 size hash table */ +#define SCH_EP_HASH_BITS 5 + /** * To simplify scheduler algorithm, set a upper limit for ESIT, * if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT, @@ -36,14 +40,12 @@ struct mu3h_sch_tt { * struct mu3h_sch_bw_info: schedule information for bandwidth domain * * @bus_bw: array to keep track of bandwidth already used at each uframes - * @bw_ep_list: eps in the bandwidth domain * * treat a HS root port as a bandwidth domain, but treat a SS root port as * two bandwidth domains, one for IN eps and another for OUT eps. */ struct mu3h_sch_bw_info { u32 bus_bw[XHCI_MTK_MAX_ESIT]; - struct list_head bw_ep_list; }; /** @@ -54,8 +56,10 @@ struct mu3h_sch_bw_info { * @num_budget_microframes: number of continuous uframes * (@repeat==1) scheduled within the interval * @bw_cost_per_microframe: bandwidth cost per microframe + * @hentry: hash table entry * @endpoint: linked into bandwidth domain which it belongs to * @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to + * @bw_info: bandwidth domain which this endpoint belongs * @sch_tt: mu3h_sch_tt linked into * @ep_type: endpoint type * @maxpkt: max packet size of endpoint @@ -84,7 +88,9 @@ struct mu3h_sch_ep_info { u32 num_budget_microframes; u32 bw_cost_per_microframe; struct list_head endpoint; + struct hlist_node hentry; struct list_head tt_endpoint; + struct mu3h_sch_bw_info *bw_info; struct mu3h_sch_tt *sch_tt; u32 ep_type; u32 maxpkt; @@ -137,6 +143,7 @@ struct xhci_hcd_mtk { struct usb_hcd *hcd; struct mu3h_sch_bw_info *sch_array; struct list_head bw_ep_chk_list; + DECLARE_HASHTABLE(sch_ep_hash, SCH_EP_HASH_BITS); struct mu3c_ippc_regs __iomem *ippc_regs; int num_u2_ports; int num_u3_ports; From patchwork Thu Aug 26 02:51:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 12458883 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNPARSEABLE_RELAY,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F866C43214 for ; Thu, 26 Aug 2021 02:52:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4DC40610CE for ; Thu, 26 Aug 2021 02:52:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232441AbhHZCww (ORCPT ); Wed, 25 Aug 2021 22:52:52 -0400 Received: from mailgw01.mediatek.com ([60.244.123.138]:42604 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S237996AbhHZCwv (ORCPT ); Wed, 25 Aug 2021 22:52:51 -0400 X-UUID: 1411f0387bf64cd59aaacbe44349d2d4-20210826 X-UUID: 1411f0387bf64cd59aaacbe44349d2d4-20210826 Received: from mtkexhb02.mediatek.inc [(172.21.101.103)] by mailgw01.mediatek.com (envelope-from ) (Generic MTA with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1407219757; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkmbs10n2.mediatek.inc (172.21.101.183) by mtkmbs06n1.mediatek.inc (172.21.101.129) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Thu, 26 Aug 2021 10:52:01 +0800 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Thu, 26 Aug 2021 10:52:00 +0800 Received: from mtkslt301.mediatek.inc (10.21.14.114) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Thu, 26 Aug 2021 10:52:00 +0800 From: Chunfeng Yun To: Mathias Nyman , Greg Kroah-Hartman CC: Chunfeng Yun , Matthias Brugger , , , , , Ikjoon Jang , Eddie Hung , Yaqii wu Subject: [PATCH next v2 6/6] usb: xhci-mtk: allow bandwidth table rollover Date: Thu, 26 Aug 2021 10:51:44 +0800 Message-ID: <20210826025144.51992-6-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20210826025144.51992-1-chunfeng.yun@mediatek.com> References: <20210826025144.51992-1-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org xhci-mtk has 64 slots for periodic bandwidth calculations and each slot represents byte budgets on a microframe. When an endpoint's allocation sits on the boundary of the table, byte budgets' slot can be rolled over but the current implementation doesn't. This patch allows the microframe index rollover and prevent out-of-bounds array access. Signed-off-by: Ikjoon Jang Signed-off-by: Chunfeng Yun --- v2: new patch --- drivers/usb/host/xhci-mtk-sch.c | 51 +++++++++++---------------------- drivers/usb/host/xhci-mtk.h | 3 +- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c index f3c6f078f82d..134f4789bd89 100644 --- a/drivers/usb/host/xhci-mtk-sch.c +++ b/drivers/usb/host/xhci-mtk-sch.c @@ -416,15 +416,14 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, { u32 max_bw = 0; u32 bw; - int i; - int j; + int i, j, k; for (i = 0; i < sch_ep->num_esit; i++) { u32 base = offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) { - bw = sch_bw->bus_bw[base + j] + - sch_ep->bw_budget_table[j]; + k = XHCI_MTK_BW_INDEX(base + j); + bw = sch_bw->bus_bw[k] + sch_ep->bw_budget_table[j]; if (bw > max_bw) max_bw = bw; } @@ -436,18 +435,16 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep, bool used) { u32 base; - int i; - int j; + int i, j, k; for (i = 0; i < sch_ep->num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; for (j = 0; j < sch_ep->num_budget_microframes; j++) { + k = XHCI_MTK_BW_INDEX(base + j); if (used) - sch_bw->bus_bw[base + j] += - sch_ep->bw_budget_table[j]; + sch_bw->bus_bw[k] += sch_ep->bw_budget_table[j]; else - sch_bw->bus_bw[base + j] -= - sch_ep->bw_budget_table[j]; + sch_bw->bus_bw[k] -= sch_ep->bw_budget_table[j]; } } } @@ -457,7 +454,7 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) struct mu3h_sch_tt *tt = sch_ep->sch_tt; u32 tmp; int base; - int i, j; + int i, j, k; for (i = 0; i < sch_ep->num_esit; i++) { base = offset + i * sch_ep->esit; @@ -467,7 +464,8 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) * the hub will always delay one uframe to send data */ for (j = 0; j < sch_ep->num_budget_microframes; j++) { - tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_budget_table[j]; + k = XHCI_MTK_BW_INDEX(base + j); + tmp = tt->fs_bus_bw[k] + sch_ep->bw_budget_table[j]; if (tmp > FS_PAYLOAD_MAX) return -ESCH_BW_OVERFLOW; } @@ -542,16 +540,18 @@ static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) { struct mu3h_sch_tt *tt = sch_ep->sch_tt; u32 base; - int i, j; + int i, j, k; for (i = 0; i < sch_ep->num_esit; i++) { base = sch_ep->offset + i * sch_ep->esit; - for (j = 0; j < sch_ep->num_budget_microframes; j++) + for (j = 0; j < sch_ep->num_budget_microframes; j++) { + k = XHCI_MTK_BW_INDEX(base + j); if (used) - tt->fs_bus_bw[base + j] += sch_ep->bw_budget_table[j]; + tt->fs_bus_bw[k] += sch_ep->bw_budget_table[j]; else - tt->fs_bus_bw[base + j] -= sch_ep->bw_budget_table[j]; + tt->fs_bus_bw[k] -= sch_ep->bw_budget_table[j]; + } } if (used) @@ -573,25 +573,9 @@ static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw, return 0; } -static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) -{ - u32 boundary = sch_ep->esit; - - if (sch_ep->sch_tt) { /* LS/FS with TT */ - /* tune for CS */ - if (sch_ep->ep_type != ISOC_OUT_EP) - boundary++; - else if (boundary > 1) /* normally esit >= 8 for FS/LS */ - boundary--; - } - - return boundary; -} - static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) { struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info; - const u32 esit_boundary = get_esit_boundary(sch_ep); const u32 bw_boundary = get_bw_boundary(sch_ep->speed); u32 offset; u32 worst_bw; @@ -608,9 +592,6 @@ static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) if (ret) continue; - if ((offset + sch_ep->num_budget_microframes) > esit_boundary) - break; - worst_bw = get_max_bw(sch_bw, sch_ep, offset); if (worst_bw > bw_boundary) continue; diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index dc5e83f5c5cc..7cc0123eada0 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -25,7 +25,8 @@ * round down to the limit value, that means allocating more * bandwidth to it. */ -#define XHCI_MTK_MAX_ESIT 64 +#define XHCI_MTK_MAX_ESIT (1 << 6) +#define XHCI_MTK_BW_INDEX(x) ((x) & (XHCI_MTK_MAX_ESIT - 1)) /** * @fs_bus_bw: array to keep track of bandwidth already used for FS