Skip to content

Commit

Permalink
usb: xhci-mtk: improve bandwidth scheduling with TT
Browse files Browse the repository at this point in the history
When the USB headset is plug into an external hub, sometimes
can't set config due to not enough bandwidth, so need improve
LS/FS INT/ISOC bandwidth scheduling with TT.

Fixes: 54f6a8a ("usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints")
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Yaqii Wu <yaqii.wu@mediatek.com>
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/2f30e81400a59afef5f8231c98149169c7520519.1615170625.git.chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Chunfeng Yun authored and Greg Kroah-Hartman committed Mar 10, 2021
1 parent 5fa5827 commit e19ee44
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 16 deletions.
74 changes: 60 additions & 14 deletions drivers/usb/host/xhci-mtk-sch.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,31 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
sch_ep->allocated = used;
}

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;
int base;
int i, j;

num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
for (i = 0; i < num_esit; i++) {
base = offset + i * sch_ep->esit;

/*
* 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 -ERANGE;
}
}

return 0;
}

static int check_sch_tt(struct usb_device *udev,
struct mu3h_sch_ep_info *sch_ep, u32 offset)
{
Expand All @@ -402,7 +427,7 @@ static int check_sch_tt(struct usb_device *udev,
return -ERANGE;

for (i = 0; i < sch_ep->cs_count; i++)
if (test_bit(offset + i, tt->split_bit_map))
if (test_bit(offset + i, tt->ss_bit_map))
return -ERANGE;

} else {
Expand Down Expand Up @@ -432,7 +457,7 @@ static int check_sch_tt(struct usb_device *udev,
cs_count = 7; /* HW limit */

for (i = 0; i < cs_count + 2; i++) {
if (test_bit(offset + i, tt->split_bit_map))
if (test_bit(offset + i, tt->ss_bit_map))
return -ERANGE;
}

Expand All @@ -448,24 +473,44 @@ static int check_sch_tt(struct usb_device *udev,
sch_ep->num_budget_microframes = sch_ep->esit;
}

return 0;
return check_fs_bus_bw(sch_ep, offset);
}

static void update_sch_tt(struct usb_device *udev,
struct mu3h_sch_ep_info *sch_ep)
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 bits;
int i, j;

num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
bits = (sch_ep->ep_type == ISOC_OUT_EP) ? sch_ep->cs_count : 1;

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->num_budget_microframes; j++)
set_bit(base + j, tt->split_bit_map);

for (j = 0; j < bits; j++) {
if (used)
set_bit(base + j, tt->ss_bit_map);
else
clear_bit(base + j, tt->ss_bit_map);
}

for (j = 0; j < sch_ep->cs_count; j++)
tt->fs_bus_bw[base + j] += bw_updated;
}

list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list);
if (used)
list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list);
else
list_del(&sch_ep->tt_endpoint);
}

static int check_sch_bw(struct usb_device *udev,
Expand Down Expand Up @@ -535,7 +580,7 @@ static int check_sch_bw(struct usb_device *udev,
if (!tt_offset_ok)
return -ERANGE;

update_sch_tt(udev, sch_ep);
update_sch_tt(udev, sch_ep, 1);
}

/* update bus bandwidth info */
Expand All @@ -548,15 +593,16 @@ 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)
if (sch_ep->allocated) {
update_bus_bw(sch_bw, sch_ep, 0);
if (sch_ep->sch_tt)
update_sch_tt(udev, sch_ep, 0);
}

list_del(&sch_ep->endpoint);

if (sch_ep->sch_tt) {
list_del(&sch_ep->tt_endpoint);
if (sch_ep->sch_tt)
drop_tt(udev);
}

list_del(&sch_ep->endpoint);
kfree(sch_ep);
}

Expand Down
6 changes: 4 additions & 2 deletions drivers/usb/host/xhci-mtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
#define XHCI_MTK_MAX_ESIT 64

/**
* @split_bit_map: used to avoid split microframes overlay
* @ss_bit_map: used to avoid start split microframes overlay
* @fs_bus_bw: array to keep track of bandwidth already used for FS
* @ep_list: Endpoints using this TT
* @usb_tt: usb TT related
* @tt_port: TT port number
*/
struct mu3h_sch_tt {
DECLARE_BITMAP(split_bit_map, XHCI_MTK_MAX_ESIT);
DECLARE_BITMAP(ss_bit_map, XHCI_MTK_MAX_ESIT);
u32 fs_bus_bw[XHCI_MTK_MAX_ESIT];
struct list_head ep_list;
struct usb_tt *usb_tt;
int tt_port;
Expand Down

0 comments on commit e19ee44

Please sign in to comment.