Skip to content

Commit 4ce1866

Browse files
Chunfeng Yungregkh
authored andcommitted
usb: xhci-mtk: Do not use xhci's virt_dev in drop_endpoint
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] f351f4b ("usb: xhci-mtk: fix oops when unbind driver") Signed-off-by: Ikjoon Jang <[email protected]> Signed-off-by: Chunfeng Yun <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 926d60a commit 4ce1866

File tree

2 files changed

+60
-51
lines changed

2 files changed

+60
-51
lines changed

drivers/usb/host/xhci-mtk-sch.c

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed)
8080
interval /= 1000;
8181
}
8282

83-
snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s\n",
83+
snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s",
8484
usb_speed_string(speed), usb_endpoint_num(epd),
8585
usb_endpoint_dir_in(epd) ? "in" : "out",
8686
usb_ep_type_string(usb_endpoint_type(epd)),
@@ -129,6 +129,10 @@ get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
129129
int bw_index;
130130

131131
virt_dev = xhci->devs[udev->slot_id];
132+
if (!virt_dev->real_port) {
133+
WARN_ONCE(1, "%s invalid real_port\n", dev_name(&udev->dev));
134+
return NULL;
135+
}
132136

133137
if (udev->speed >= USB_SPEED_SUPER) {
134138
if (usb_endpoint_dir_out(&ep->desc))
@@ -236,14 +240,20 @@ static void drop_tt(struct usb_device *udev)
236240
}
237241
}
238242

239-
static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
240-
struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
243+
static struct mu3h_sch_ep_info *
244+
create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
245+
struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx)
241246
{
242247
struct mu3h_sch_ep_info *sch_ep;
248+
struct mu3h_sch_bw_info *bw_info;
243249
struct mu3h_sch_tt *tt = NULL;
244250
u32 len_bw_budget_table;
245251
size_t mem_size;
246252

253+
bw_info = get_bw_info(mtk, udev, ep);
254+
if (!bw_info)
255+
return ERR_PTR(-ENODEV);
256+
247257
if (is_fs_or_ls(udev->speed))
248258
len_bw_budget_table = TT_MICROFRAMES_MAX;
249259
else if ((udev->speed >= USB_SPEED_SUPER)
@@ -266,11 +276,13 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,
266276
}
267277
}
268278

279+
sch_ep->bw_info = bw_info;
269280
sch_ep->sch_tt = tt;
270281
sch_ep->ep = ep;
271282
sch_ep->speed = udev->speed;
272283
INIT_LIST_HEAD(&sch_ep->endpoint);
273284
INIT_LIST_HEAD(&sch_ep->tt_endpoint);
285+
INIT_HLIST_NODE(&sch_ep->hentry);
274286

275287
return sch_ep;
276288
}
@@ -578,9 +590,9 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep)
578590
return boundary;
579591
}
580592

581-
static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
582-
struct mu3h_sch_ep_info *sch_ep)
593+
static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep)
583594
{
595+
struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info;
584596
const u32 esit_boundary = get_esit_boundary(sch_ep);
585597
const u32 bw_boundary = get_bw_boundary(sch_ep->speed);
586598
u32 offset;
@@ -627,23 +639,26 @@ static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
627639
return load_ep_bw(sch_bw, sch_ep, true);
628640
}
629641

630-
static void destroy_sch_ep(struct usb_device *udev,
631-
struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
642+
static void destroy_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
643+
struct mu3h_sch_ep_info *sch_ep)
632644
{
633645
/* only release ep bw check passed by check_sch_bw() */
634646
if (sch_ep->allocated)
635-
load_ep_bw(sch_bw, sch_ep, false);
647+
load_ep_bw(sch_ep->bw_info, sch_ep, false);
636648

637649
if (sch_ep->sch_tt)
638650
drop_tt(udev);
639651

640652
list_del(&sch_ep->endpoint);
653+
hlist_del(&sch_ep->hentry);
641654
kfree(sch_ep);
642655
}
643656

644-
static bool need_bw_sch(struct usb_host_endpoint *ep,
645-
enum usb_device_speed speed, int has_tt)
657+
static bool need_bw_sch(struct usb_device *udev,
658+
struct usb_host_endpoint *ep)
646659
{
660+
bool has_tt = udev->tt && udev->tt->hub->parent;
661+
647662
/* only for periodic endpoints */
648663
if (usb_endpoint_xfer_control(&ep->desc)
649664
|| usb_endpoint_xfer_bulk(&ep->desc))
@@ -654,7 +669,7 @@ static bool need_bw_sch(struct usb_host_endpoint *ep,
654669
* a TT are also ignored, root-hub will schedule them directly,
655670
* but need set @bpkts field of endpoint context to 1.
656671
*/
657-
if (is_fs_or_ls(speed) && !has_tt)
672+
if (is_fs_or_ls(udev->speed) && !has_tt)
658673
return false;
659674

660675
/* skip endpoint with zero maxpkt */
@@ -669,7 +684,6 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
669684
struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd);
670685
struct mu3h_sch_bw_info *sch_array;
671686
int num_usb_bus;
672-
int i;
673687

674688
/* ss IN and OUT are separated */
675689
num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports;
@@ -678,12 +692,10 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
678692
if (sch_array == NULL)
679693
return -ENOMEM;
680694

681-
for (i = 0; i < num_usb_bus; i++)
682-
INIT_LIST_HEAD(&sch_array[i].bw_ep_list);
683-
684695
mtk->sch_array = sch_array;
685696

686697
INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
698+
hash_init(mtk->sch_ep_hash);
687699

688700
return 0;
689701
}
@@ -707,9 +719,7 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
707719
ep_index = xhci_get_endpoint_index(&ep->desc);
708720
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
709721

710-
xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));
711-
712-
if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) {
722+
if (!need_bw_sch(udev, ep)) {
713723
/*
714724
* set @bpkts to 1 if it is LS or FS periodic endpoint, and its
715725
* device does not connected through an external HS hub
@@ -721,13 +731,16 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
721731
return 0;
722732
}
723733

724-
sch_ep = create_sch_ep(udev, ep, ep_ctx);
734+
xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));
735+
736+
sch_ep = create_sch_ep(mtk, udev, ep, ep_ctx);
725737
if (IS_ERR_OR_NULL(sch_ep))
726738
return -ENOMEM;
727739

728740
setup_sch_info(ep_ctx, sch_ep);
729741

730742
list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list);
743+
hash_add(mtk->sch_ep_hash, &sch_ep->hentry, (unsigned long)ep);
731744

732745
return 0;
733746
}
@@ -737,22 +750,18 @@ static void drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
737750
{
738751
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
739752
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
740-
struct xhci_virt_device *virt_dev;
741-
struct mu3h_sch_bw_info *sch_bw;
742-
struct mu3h_sch_ep_info *sch_ep, *tmp;
743-
744-
virt_dev = xhci->devs[udev->slot_id];
745-
746-
xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));
753+
struct mu3h_sch_ep_info *sch_ep;
754+
struct hlist_node *hn;
747755

748-
if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info))
756+
if (!need_bw_sch(udev, ep))
749757
return;
750758

751-
sch_bw = get_bw_info(mtk, udev, ep);
759+
xhci_err(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));
752760

753-
list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
761+
hash_for_each_possible_safe(mtk->sch_ep_hash, sch_ep,
762+
hn, hentry, (unsigned long)ep) {
754763
if (sch_ep->ep == ep) {
755-
destroy_sch_ep(udev, sch_bw, sch_ep);
764+
destroy_sch_ep(mtk, udev, sch_ep);
756765
break;
757766
}
758767
}
@@ -763,30 +772,22 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
763772
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
764773
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
765774
struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
766-
struct mu3h_sch_bw_info *sch_bw;
767-
struct mu3h_sch_ep_info *sch_ep, *tmp;
775+
struct mu3h_sch_ep_info *sch_ep;
768776
int ret;
769777

770778
xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
771779

772780
list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) {
773-
sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
781+
struct xhci_ep_ctx *ep_ctx;
782+
struct usb_host_endpoint *ep = sch_ep->ep;
783+
unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
774784

775-
ret = check_sch_bw(sch_bw, sch_ep);
785+
ret = check_sch_bw(sch_ep);
776786
if (ret) {
777787
xhci_err(xhci, "Not enough bandwidth! (%s)\n",
778788
sch_error_string(-ret));
779789
return -ENOSPC;
780790
}
781-
}
782-
783-
list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
784-
struct xhci_ep_ctx *ep_ctx;
785-
struct usb_host_endpoint *ep = sch_ep->ep;
786-
unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);
787-
788-
sch_bw = get_bw_info(mtk, udev, ep);
789-
list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
790791

791792
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
792793
ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(sch_ep->pkts)
@@ -800,22 +801,23 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
800801
sch_ep->offset, sch_ep->repeat);
801802
}
802803

803-
return xhci_check_bandwidth(hcd, udev);
804+
ret = xhci_check_bandwidth(hcd, udev);
805+
if (!ret)
806+
INIT_LIST_HEAD(&mtk->bw_ep_chk_list);
807+
808+
return ret;
804809
}
805810

806811
void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
807812
{
808813
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
809814
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
810-
struct mu3h_sch_bw_info *sch_bw;
811815
struct mu3h_sch_ep_info *sch_ep, *tmp;
812816

813817
xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev));
814818

815-
list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) {
816-
sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
817-
destroy_sch_ep(udev, sch_bw, sch_ep);
818-
}
819+
list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint)
820+
destroy_sch_ep(mtk, udev, sch_ep);
819821

820822
xhci_reset_bandwidth(hcd, udev);
821823
}

drivers/usb/host/xhci-mtk.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@
1010
#define _XHCI_MTK_H_
1111

1212
#include <linux/clk.h>
13+
#include <linux/hashtable.h>
1314

1415
#include "xhci.h"
1516

1617
#define BULK_CLKS_NUM 5
1718

19+
/* support at most 64 ep, use 32 size hash table */
20+
#define SCH_EP_HASH_BITS 5
21+
1822
/**
1923
* To simplify scheduler algorithm, set a upper limit for ESIT,
2024
* if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT,
@@ -36,14 +40,12 @@ struct mu3h_sch_tt {
3640
* struct mu3h_sch_bw_info: schedule information for bandwidth domain
3741
*
3842
* @bus_bw: array to keep track of bandwidth already used at each uframes
39-
* @bw_ep_list: eps in the bandwidth domain
4043
*
4144
* treat a HS root port as a bandwidth domain, but treat a SS root port as
4245
* two bandwidth domains, one for IN eps and another for OUT eps.
4346
*/
4447
struct mu3h_sch_bw_info {
4548
u32 bus_bw[XHCI_MTK_MAX_ESIT];
46-
struct list_head bw_ep_list;
4749
};
4850

4951
/**
@@ -54,8 +56,10 @@ struct mu3h_sch_bw_info {
5456
* @num_budget_microframes: number of continuous uframes
5557
* (@repeat==1) scheduled within the interval
5658
* @bw_cost_per_microframe: bandwidth cost per microframe
59+
* @hentry: hash table entry
5760
* @endpoint: linked into bandwidth domain which it belongs to
5861
* @tt_endpoint: linked into mu3h_sch_tt's list which it belongs to
62+
* @bw_info: bandwidth domain which this endpoint belongs
5963
* @sch_tt: mu3h_sch_tt linked into
6064
* @ep_type: endpoint type
6165
* @maxpkt: max packet size of endpoint
@@ -84,7 +88,9 @@ struct mu3h_sch_ep_info {
8488
u32 num_budget_microframes;
8589
u32 bw_cost_per_microframe;
8690
struct list_head endpoint;
91+
struct hlist_node hentry;
8792
struct list_head tt_endpoint;
93+
struct mu3h_sch_bw_info *bw_info;
8894
struct mu3h_sch_tt *sch_tt;
8995
u32 ep_type;
9096
u32 maxpkt;
@@ -137,6 +143,7 @@ struct xhci_hcd_mtk {
137143
struct usb_hcd *hcd;
138144
struct mu3h_sch_bw_info *sch_array;
139145
struct list_head bw_ep_chk_list;
146+
DECLARE_HASHTABLE(sch_ep_hash, SCH_EP_HASH_BITS);
140147
struct mu3c_ippc_regs __iomem *ippc_regs;
141148
int num_u2_ports;
142149
int num_u3_ports;

0 commit comments

Comments
 (0)