2021-03-05 09:04:51

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 01/17] usb: xhci-mtk: remove or operator for setting schedule parameters

Side effect may happen if use or operator to set schedule parameters
when the parameters are already set before. Set them directly due to
other bits are reserved.

Fixes: 54f6a8af3722 ("usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints")
Cc: stable <[email protected]>
Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index b45e5bf08997..5891f56c64da 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -643,7 +643,7 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
*/
if (usb_endpoint_xfer_int(&ep->desc)
|| usb_endpoint_xfer_isoc(&ep->desc))
- ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(1));
+ ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(1));

return 0;
}
@@ -730,10 +730,10 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
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_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_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",
--
2.18.0


2021-03-05 09:04:51

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 02/17] usb: xhci-mtk: improve bandwidth scheduling with TT

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: 54f6a8af3722 ("usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints")
Cc: stable <[email protected]>
Signed-off-by: Yaqii Wu <[email protected]>
Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 74 ++++++++++++++++++++++++++-------
drivers/usb/host/xhci-mtk.h | 6 ++-
2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 5891f56c64da..8950d1f10a7f 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -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)
{
@@ -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 {
@@ -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;
}

@@ -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,
@@ -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 */
@@ -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);
}

diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index cbb09dfea62e..f42769c69249 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -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;
--
2.18.0

2021-03-05 09:04:53

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 04/17] usb: xhci-mtk: add only one extra CS for FS/LS INTR

In USB2 Spec:
"11.18.5 TT Response Generation
In general, there will be two (or more) complete-split
transactions scheduled for a periodic endpoint.
However, for interrupt endpoints, the maximum size of
the full-/low-speed transaction guarantees that it can
never require more than two complete-split transactions.
Two complete-split transactions are only required
when the transaction spans a microframe boundary."

Due to the maxp is 64, and less then 188 (at most in one
microframe), seems never span boundary, so use only one CS
for FS/LS interrupt transfer, this will save some bandwidth.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index e3b18dfca874..817ef2815e67 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -408,13 +408,11 @@ static int check_sch_tt(struct usb_device *udev,
{
struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
- u32 fs_budget_start;
u32 start_ss, last_ss;
u32 start_cs, last_cs;
int i;

start_ss = offset % 8;
- fs_budget_start = (start_ss + 1) % 8;

if (sch_ep->ep_type == ISOC_OUT_EP) {
last_ss = start_ss + sch_ep->cs_count - 1;
@@ -450,16 +448,14 @@ static int check_sch_tt(struct usb_device *udev,
if (sch_ep->ep_type == ISOC_IN_EP)
extra_cs_count = (last_cs == 7) ? 1 : 2;
else /* ep_type : INTR IN / INTR OUT */
- extra_cs_count = (fs_budget_start == 6) ? 1 : 2;
+ extra_cs_count = 1;

cs_count += extra_cs_count;
if (cs_count > 7)
cs_count = 7; /* HW limit */

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

sch_ep->cs_count = cs_count;
/* one for ss, the other for idle */
--
2.18.0

2021-03-05 09:04:53

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 03/17] usb: xhci-mtk: get the microframe boundary for ESIT

Tune the boundary for FS/LS ESIT due to CS:
For ISOC out-ep, the controller starts transfer data after
the first SS; for others, the data is already transfered
before the last CS.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 8950d1f10a7f..e3b18dfca874 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -513,22 +513,35 @@ static void update_sch_tt(struct usb_device *udev,
list_del(&sch_ep->tt_endpoint);
}

+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 += 1;
+ else if (boundary > 1) /* normally esit >= 8 for FS/LS */
+ boundary -= 1;
+ }
+
+ return boundary;
+}
+
static int check_sch_bw(struct usb_device *udev,
struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
{
u32 offset;
- u32 esit;
u32 min_bw;
u32 min_index;
u32 worst_bw;
u32 bw_boundary;
+ u32 esit_boundary;
u32 min_num_budget;
u32 min_cs_count;
bool tt_offset_ok = false;
int ret;

- esit = sch_ep->esit;
-
/*
* Search through all possible schedule microframes.
* and find a microframe where its worst bandwidth is minimum.
@@ -537,7 +550,8 @@ static int check_sch_bw(struct usb_device *udev,
min_index = 0;
min_cs_count = sch_ep->cs_count;
min_num_budget = sch_ep->num_budget_microframes;
- for (offset = 0; offset < esit; offset++) {
+ esit_boundary = get_esit_boundary(sch_ep);
+ for (offset = 0; offset < sch_ep->esit; offset++) {
if (is_fs_or_ls(udev->speed)) {
ret = check_sch_tt(udev, sch_ep, offset);
if (ret)
@@ -546,7 +560,7 @@ static int check_sch_bw(struct usb_device *udev,
tt_offset_ok = true;
}

- if ((offset + sch_ep->num_budget_microframes) > sch_ep->esit)
+ if ((offset + sch_ep->num_budget_microframes) > esit_boundary)
break;

worst_bw = get_max_bw(sch_bw, sch_ep, offset);
--
2.18.0

2021-03-05 09:05:01

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 09/17] usb: xhci-mtk: use clear type instead of void

Use struct usb_host_endpoint instead of void to declare
the member @ep of mu3h_sch_ep_info struct.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index f61e53b02706..076b9bbc89dd 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -84,7 +84,7 @@ struct mu3h_sch_ep_info {
struct mu3h_sch_tt *sch_tt;
u32 ep_type;
u32 maxpkt;
- void *ep;
+ struct usb_host_endpoint *ep;
bool allocated;
/*
* mtk xHCI scheduling information put into reserved DWs
--
2.18.0

2021-03-05 09:05:10

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 08/17] usb: xhci-mtk: remove unnecessary members of mu3h_sch_tt struct

The members @usb_tt and @tt_port in mu3h_sch_tt struct
are not used after initialization, so can be removed

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 7 +------
drivers/usb/host/xhci-mtk.h | 4 ----
2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index cb597357f134..1e8af5973a5e 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -104,7 +104,6 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
{
struct usb_tt *utt = udev->tt;
struct mu3h_sch_tt *tt, **tt_index, **ptt;
- unsigned int port;
bool allocated_index = false;

if (!utt)
@@ -126,10 +125,8 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
utt->hcpriv = tt_index;
allocated_index = true;
}
- port = udev->ttport - 1;
- ptt = &tt_index[port];
+ ptt = &tt_index[udev->ttport - 1];
} else {
- port = 0;
ptt = (struct mu3h_sch_tt **) &utt->hcpriv;
}

@@ -144,8 +141,6 @@ static struct mu3h_sch_tt *find_tt(struct usb_device *udev)
return ERR_PTR(-ENOMEM);
}
INIT_LIST_HEAD(&tt->ep_list);
- tt->usb_tt = utt;
- tt->tt_port = port;
*ptt = tt;
}

diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index f42769c69249..f61e53b02706 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -23,15 +23,11 @@
* @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(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;
};

/**
--
2.18.0

2021-03-05 09:05:10

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 11/17] usb: xhci-mtk: use @tt_info to check the FS/LS device is under a HS hub

If the LS/FS device is connected to an external HS hub, the member
@tt_info in xhci_virt_device struct in not NULL, use it to check
whether a LS/FS device is under an exernal HS hub, then no need get
the slot context of this device.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index e75628f82706..1562875c04ab 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -678,7 +678,6 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
struct xhci_hcd *xhci;
struct xhci_ep_ctx *ep_ctx;
- struct xhci_slot_ctx *slot_ctx;
struct xhci_virt_device *virt_dev;
struct mu3h_sch_ep_info *sch_ep;
unsigned int ep_index;
@@ -686,7 +685,6 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
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);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);

xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
@@ -694,7 +692,7 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
usb_endpoint_maxp(&ep->desc),
usb_endpoint_dir_in(&ep->desc), ep);

- if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) {
+ 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
@@ -723,7 +721,6 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
{
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
struct xhci_hcd *xhci;
- 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;
@@ -732,7 +729,6 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,

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",
@@ -740,7 +736,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
usb_endpoint_maxp(&ep->desc),
usb_endpoint_dir_in(&ep->desc), ep);

- if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
+ if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info))
return;

bw_index = get_bw_index(xhci, udev, ep);
--
2.18.0

2021-03-05 09:05:10

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 10/17] usb: xhci-mtk: add a member @speed in mu3h_sch_ep_info struct

This is used to drop parameter @udev for some functions,
meanwhile remove some unused @udev parameter.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 37 ++++++++++++++++-----------------
drivers/usb/host/xhci-mtk.h | 1 +
2 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 1e8af5973a5e..e75628f82706 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -214,14 +214,15 @@ static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev,

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;
}

-static void setup_sch_info(struct usb_device *udev,
- struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
+static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
+ struct mu3h_sch_ep_info *sch_ep)
{
u32 ep_type;
u32 maxpkt;
@@ -248,7 +249,7 @@ static void setup_sch_info(struct usb_device *udev,
sch_ep->burst_mode = 0;
sch_ep->repeat = 0;

- if (udev->speed == USB_SPEED_HIGH) {
+ if (sch_ep->speed == USB_SPEED_HIGH) {
sch_ep->cs_count = 0;

/*
@@ -266,7 +267,7 @@ static void setup_sch_info(struct usb_device *udev,
sch_ep->pkts = max_burst + 1;
sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
bwb_table[0] = sch_ep->bw_cost_per_microframe;
- } else if (udev->speed >= USB_SPEED_SUPER) {
+ } else if (sch_ep->speed >= USB_SPEED_SUPER) {
/* usb3_r1 spec section4.4.7 & 4.4.8 */
sch_ep->cs_count = 0;
sch_ep->burst_mode = 1;
@@ -311,7 +312,7 @@ static void setup_sch_info(struct usb_device *udev,
/* last one <= bw_cost_per_microframe */
bwb_table[i] = remainder;
}
- } else if (is_fs_or_ls(udev->speed)) {
+ } else if (is_fs_or_ls(sch_ep->speed)) {
sch_ep->pkts = 1; /* at most one packet for each microframe */

/*
@@ -416,8 +417,7 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
return 0;
}

-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_ep_info *sch_ep, u32 offset)
{
struct mu3h_sch_tt *tt = sch_ep->sch_tt;
u32 extra_cs_count;
@@ -485,8 +485,7 @@ static int check_sch_tt(struct usb_device *udev,
return check_fs_bus_bw(sch_ep, offset);
}

-static void update_sch_tt(struct usb_device *udev,
- struct mu3h_sch_ep_info *sch_ep, bool used)
+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;
@@ -522,11 +521,11 @@ static void update_sch_tt(struct usb_device *udev,
list_del(&sch_ep->tt_endpoint);
}

-static int load_ep_bw(struct usb_device *udev, struct mu3h_sch_bw_info *sch_bw,
+static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw,
struct mu3h_sch_ep_info *sch_ep, bool loaded)
{
if (sch_ep->sch_tt)
- update_sch_tt(udev, sch_ep, loaded);
+ update_sch_tt(sch_ep, loaded);

/* update bus bandwidth info */
update_bus_bw(sch_bw, sch_ep, loaded);
@@ -550,8 +549,8 @@ static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep)
return boundary;
}

-static int check_sch_bw(struct usb_device *udev,
- struct mu3h_sch_bw_info *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)
{
u32 offset;
u32 min_bw;
@@ -574,7 +573,7 @@ static int check_sch_bw(struct usb_device *udev,
esit_boundary = get_esit_boundary(sch_ep);
for (offset = 0; offset < sch_ep->esit; offset++) {
if (sch_ep->sch_tt) {
- ret = check_sch_tt(udev, sch_ep, offset);
+ ret = check_sch_tt(sch_ep, offset);
if (ret)
continue;
}
@@ -593,7 +592,7 @@ static int check_sch_bw(struct usb_device *udev,
break;
}

- bw_boundary = get_bw_boundary(udev->speed);
+ bw_boundary = get_bw_boundary(sch_ep->speed);
/* check bandwidth */
if (min_bw > bw_boundary)
return -ERANGE;
@@ -602,7 +601,7 @@ static int check_sch_bw(struct usb_device *udev,
sch_ep->cs_count = min_cs_count;
sch_ep->num_budget_microframes = min_num_budget;

- return load_ep_bw(udev, sch_bw, sch_ep, true);
+ return load_ep_bw(sch_bw, sch_ep, true);
}

static void destroy_sch_ep(struct usb_device *udev,
@@ -610,7 +609,7 @@ static void destroy_sch_ep(struct usb_device *udev,
{
/* only release ep bw check passed by check_sch_bw() */
if (sch_ep->allocated)
- load_ep_bw(udev, sch_bw, sch_ep, false);
+ load_ep_bw(sch_bw, sch_ep, false);

if (sch_ep->sch_tt)
drop_tt(udev);
@@ -711,7 +710,7 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM;

- setup_sch_info(udev, ep_ctx, sch_ep);
+ setup_sch_info(ep_ctx, sch_ep);

list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list);

@@ -771,7 +770,7 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
bw_index = get_bw_index(xhci, udev, sch_ep->ep);
sch_bw = &mtk->sch_array[bw_index];

- ret = check_sch_bw(udev, sch_bw, sch_ep);
+ ret = check_sch_bw(sch_bw, sch_ep);
if (ret) {
xhci_err(xhci, "Not enough bandwidth!\n");
return -ENOSPC;
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index 076b9bbc89dd..d25bf9e49136 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -85,6 +85,7 @@ struct mu3h_sch_ep_info {
u32 ep_type;
u32 maxpkt;
struct usb_host_endpoint *ep;
+ enum usb_device_speed speed;
bool allocated;
/*
* mtk xHCI scheduling information put into reserved DWs
--
2.18.0

2021-03-05 09:05:24

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 14/17] usb: xhci-mtk: remove declaration of xhci_mtk_setup()

Move xhci_driver_overrides struct variable after definition
of xhci_mtk_setup(), then we can remove it's declaration.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index fe010cc61f19..fb4e56f6a6c3 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -344,15 +344,6 @@ static void usb_wakeup_set(struct xhci_hcd_mtk *mtk, bool enable)
usb_wakeup_ip_sleep_set(mtk, enable);
}

-static int xhci_mtk_setup(struct usb_hcd *hcd);
-static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
- .reset = xhci_mtk_setup,
- .check_bandwidth = xhci_mtk_check_bandwidth,
- .reset_bandwidth = xhci_mtk_reset_bandwidth,
-};
-
-static struct hc_driver __read_mostly xhci_mtk_hc_driver;
-
static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
{
int ret;
@@ -424,6 +415,14 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
return ret;
}

+static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
+ .reset = xhci_mtk_setup,
+ .check_bandwidth = xhci_mtk_check_bandwidth,
+ .reset_bandwidth = xhci_mtk_reset_bandwidth,
+};
+
+static struct hc_driver __read_mostly xhci_mtk_hc_driver;
+
static int xhci_mtk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
--
2.18.0

2021-03-05 09:05:24

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 13/17] usb: xhci-mtk: add some schedule error number

This is used to provide more information about which case
causes bandwidth schedule failure.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 44 ++++++++++++++++++++++++++-------
1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index d39545ade9a1..deb918490b71 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -25,6 +25,13 @@
*/
#define TT_MICROFRAMES_MAX 9

+/* schedule error type */
+#define ESCH_SS_Y6 1001
+#define ESCH_SS_OVERLAP 1002
+#define ESCH_CS_OVERFLOW 1003
+#define ESCH_BW_OVERFLOW 1004
+#define ESCH_FIXME 1005
+
/* mtk scheduler bitmasks */
#define EP_BPKTS(p) ((p) & 0x7f)
#define EP_BCSCOUNT(p) (((p) & 0x7) << 8)
@@ -32,6 +39,24 @@
#define EP_BOFFSET(p) ((p) & 0x3fff)
#define EP_BREPEAT(p) (((p) & 0x7fff) << 16)

+static char *sch_error_string(int err_num)
+{
+ switch (err_num) {
+ case ESCH_SS_Y6:
+ return "Can't schedule Start-Split in Y6";
+ case ESCH_SS_OVERLAP:
+ return "Can't find a suitable Start-Split location";
+ case ESCH_CS_OVERFLOW:
+ return "The last Complete-Split is greater than 7";
+ case ESCH_BW_OVERFLOW:
+ return "Bandwidth exceeds the maximum limit";
+ case ESCH_FIXME:
+ return "FIXME, to be resolved";
+ default:
+ return "Unknown";
+ }
+}
+
static int is_fs_or_ls(enum usb_device_speed speed)
{
return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW;
@@ -412,7 +437,7 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
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 -ESCH_BW_OVERFLOW;
}
}

@@ -437,11 +462,11 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
* must never schedule Start-Split in Y6
*/
if (!(start_ss == 7 || last_ss < 6))
- return -ERANGE;
+ return -ESCH_SS_Y6;

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

} else {
u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX);
@@ -451,14 +476,14 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
* must never schedule Start-Split in Y6
*/
if (start_ss == 6)
- return -ERANGE;
+ return -ESCH_SS_Y6;

/* one uframe for ss + one uframe for idle */
start_cs = (start_ss + 2) % 8;
last_cs = start_cs + cs_count - 1;

if (last_cs > 7)
- return -ERANGE;
+ return -ESCH_CS_OVERFLOW;

if (sch_ep->ep_type == ISOC_IN_EP)
extra_cs_count = (last_cs == 7) ? 1 : 2;
@@ -470,7 +495,7 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
cs_count = 7; /* HW limit */

if (test_bit(offset, tt->ss_bit_map))
- return -ERANGE;
+ return -ESCH_SS_OVERLAP;

sch_ep->cs_count = cs_count;
/* one for ss, the other for idle */
@@ -562,7 +587,7 @@ static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
u32 esit_boundary;
u32 min_num_budget;
u32 min_cs_count;
- int ret;
+ int ret = 0;

/*
* Search through all possible schedule microframes.
@@ -597,7 +622,7 @@ static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw,
bw_boundary = get_bw_boundary(sch_ep->speed);
/* check bandwidth */
if (min_bw > bw_boundary)
- return -ERANGE;
+ return ret ? ret : -ESCH_BW_OVERFLOW;

sch_ep->offset = min_index;
sch_ep->cs_count = min_cs_count;
@@ -765,7 +790,8 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)

ret = check_sch_bw(sch_bw, sch_ep);
if (ret) {
- xhci_err(xhci, "Not enough bandwidth!\n");
+ xhci_err(xhci, "Not enough bandwidth! (%s)\n",
+ sch_error_string(-ret));
return -ENOSPC;
}
}
--
2.18.0

2021-03-05 09:05:34

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 06/17] usb: xhci-mtk: add a function to (un)load bandwidth info

Extract a function to load/unload bandwidth info, and remove
a dummy check of TT offset.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 37 ++++++++++++++-------------------
1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 9016188eee97..bef82c1f909d 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -375,7 +375,6 @@ static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
sch_ep->bw_budget_table[j];
}
}
- sch_ep->allocated = used;
}

static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
@@ -509,6 +508,19 @@ static void update_sch_tt(struct usb_device *udev,
list_del(&sch_ep->tt_endpoint);
}

+static int load_ep_bw(struct usb_device *udev, struct mu3h_sch_bw_info *sch_bw,
+ struct mu3h_sch_ep_info *sch_ep, bool loaded)
+{
+ if (sch_ep->sch_tt)
+ update_sch_tt(udev, sch_ep, loaded);
+
+ /* update bus bandwidth info */
+ update_bus_bw(sch_bw, sch_ep, loaded);
+ sch_ep->allocated = loaded;
+
+ return 0;
+}
+
static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep)
{
u32 boundary = sch_ep->esit;
@@ -535,7 +547,6 @@ static int check_sch_bw(struct usb_device *udev,
u32 esit_boundary;
u32 min_num_budget;
u32 min_cs_count;
- bool tt_offset_ok = false;
int ret;

/*
@@ -552,8 +563,6 @@ static int check_sch_bw(struct usb_device *udev,
ret = check_sch_tt(udev, sch_ep, offset);
if (ret)
continue;
- else
- tt_offset_ok = true;
}

if ((offset + sch_ep->num_budget_microframes) > esit_boundary)
@@ -585,29 +594,15 @@ static int check_sch_bw(struct usb_device *udev,
sch_ep->cs_count = min_cs_count;
sch_ep->num_budget_microframes = min_num_budget;

- if (sch_ep->sch_tt) {
- /* all offset for tt is not ok*/
- if (!tt_offset_ok)
- return -ERANGE;
-
- update_sch_tt(udev, sch_ep, 1);
- }
-
- /* update bus bandwidth info */
- update_bus_bw(sch_bw, sch_ep, 1);
-
- return 0;
+ return load_ep_bw(udev, 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)
{
/* only release ep bw check passed by check_sch_bw() */
- if (sch_ep->allocated) {
- update_bus_bw(sch_bw, sch_ep, 0);
- if (sch_ep->sch_tt)
- update_sch_tt(udev, sch_ep, 0);
- }
+ if (sch_ep->allocated)
+ load_ep_bw(udev, sch_bw, sch_ep, false);

if (sch_ep->sch_tt)
drop_tt(udev);
--
2.18.0

2021-03-05 09:05:53

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 17/17] usb: xhci-mtk: print debug info of endpoint interval

Print bInterval and convert it into the time expressed in
us or ms unit, this is the key info when allocate bandwidth
failed.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 37 ++++++++++++++++++++++++++-------
1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 4f6b86131820..03da55bc7f9b 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -25,6 +25,8 @@
*/
#define TT_MICROFRAMES_MAX 9

+#define DBG_BUF_EN 64
+
/* schedule error type */
#define ESCH_SS_Y6 1001
#define ESCH_SS_OVERLAP 1002
@@ -62,6 +64,31 @@ static int is_fs_or_ls(enum usb_device_speed speed)
return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW;
}

+static const char *
+decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed)
+{
+ static char buf[DBG_BUF_EN];
+ struct usb_endpoint_descriptor *epd = &ep->desc;
+ unsigned int interval;
+ const char *unit;
+
+ interval = usb_decode_interval(epd, speed);
+ if (interval % 1000) {
+ unit = "us";
+ } else {
+ unit = "ms";
+ interval /= 1000;
+ }
+
+ 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)),
+ usb_endpoint_maxp(epd), epd->bInterval, interval, unit);
+
+ return buf;
+}
+
static u32 get_bw_boundary(enum usb_device_speed speed)
{
u32 boundary;
@@ -711,10 +738,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() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
- __func__, usb_endpoint_type(&ep->desc), udev->speed,
- usb_endpoint_maxp(&ep->desc),
- usb_endpoint_dir_in(&ep->desc), ep);
+ xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));

if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) {
/*
@@ -750,10 +774,7 @@ static void drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,

virt_dev = xhci->devs[udev->slot_id];

- xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
- __func__, usb_endpoint_type(&ep->desc), udev->speed,
- usb_endpoint_maxp(&ep->desc),
- usb_endpoint_dir_in(&ep->desc), ep);
+ xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));

if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info))
return;
--
2.18.0

2021-03-05 09:06:00

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 15/17] usb: xhci-mtk: support to build xhci-mtk-hcd.ko

Currently xhci-hcd.ko building depends on USB_XHCI_MTK, this
is not flexible for some cases. For example:
USB_XHCI_HCD is y, and USB_XHCI_MTK is m, then we can't
implement extended functions if only update xhci-mtk.ko
This patch is used to remove the dependence.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/Makefile | 6 ++---
drivers/usb/host/xhci-mem.c | 2 +-
drivers/usb/host/xhci-mtk-sch.c | 48 +++++++++++++++++++++++----------
drivers/usb/host/xhci-mtk.c | 2 ++
drivers/usb/host/xhci-mtk.h | 33 +++--------------------
drivers/usb/host/xhci-ring.c | 1 -
drivers/usb/host/xhci.c | 30 +++++++++------------
drivers/usb/host/xhci.h | 8 ++++++
8 files changed, 64 insertions(+), 66 deletions(-)

diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 3e4d298d851f..171de4df50bd 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -19,9 +19,7 @@ ifneq ($(CONFIG_USB_XHCI_DBGCAP), )
xhci-hcd-y += xhci-dbgcap.o xhci-dbgtty.o
endif

-ifneq ($(CONFIG_USB_XHCI_MTK), )
- xhci-hcd-y += xhci-mtk-sch.o
-endif
+xhci-mtk-hcd-y := xhci-mtk.o xhci-mtk-sch.o

xhci-plat-hcd-y := xhci-plat.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
@@ -73,7 +71,7 @@ obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o
-obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o
+obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o
obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index f2c4ee7c4786..7eb8c07c8418 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -532,7 +532,7 @@ struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci,
return (struct xhci_ep_ctx *)
(ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params)));
}
-
+EXPORT_SYMBOL_GPL(xhci_get_ep_ctx);

/***************** Streams structures manipulation *************************/

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index deb918490b71..4f6b86131820 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -691,25 +691,22 @@ int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)

return 0;
}
-EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);

void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk)
{
kfree(mtk->sch_array);
}
-EXPORT_SYMBOL_GPL(xhci_mtk_sch_exit);

-int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
- struct usb_host_endpoint *ep)
+static int 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_virt_device *virt_dev;
struct mu3h_sch_ep_info *sch_ep;
unsigned int ep_index;

- xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
@@ -741,18 +738,16 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,

return 0;
}
-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 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 xhci_hcd *xhci;
+ 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;

- xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];

xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
@@ -772,7 +767,6 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
}
}
}
-EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);

int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
{
@@ -818,7 +812,6 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)

return xhci_check_bandwidth(hcd, udev);
}
-EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth);

void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
{
@@ -836,4 +829,31 @@ void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)

xhci_reset_bandwidth(hcd, udev);
}
-EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth);
+
+int xhci_mtk_add_ep(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ int ret;
+
+ ret = xhci_add_endpoint(hcd, udev, ep);
+ if (ret)
+ return ret;
+
+ if (ep->hcpriv)
+ ret = add_ep_quirk(hcd, udev, ep);
+
+ return ret;
+}
+
+int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ int ret;
+
+ ret = xhci_drop_endpoint(hcd, udev, ep);
+ if (ret)
+ return ret;
+
+ drop_ep_quirk(hcd, udev, ep);
+ return 0;
+}
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index fb4e56f6a6c3..57bcfdfa0465 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -417,6 +417,8 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)

static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
.reset = xhci_mtk_setup,
+ .add_endpoint = xhci_mtk_add_ep,
+ .drop_endpoint = xhci_mtk_drop_ep,
.check_bandwidth = xhci_mtk_check_bandwidth,
.reset_bandwidth = xhci_mtk_reset_bandwidth,
};
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index d25bf9e49136..621ec1a85009 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -161,38 +161,13 @@ static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
return dev_get_drvdata(hcd->self.controller);
}

-#if IS_ENABLED(CONFIG_USB_XHCI_MTK)
int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk);
void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk);
-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_add_ep(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+int xhci_mtk_drop_ep(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,
- struct usb_device *udev, struct usb_host_endpoint *ep)
-{
- return 0;
-}
-
-static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd,
- struct usb_device *udev, struct usb_host_endpoint *ep)
-{
-}
-
-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-ring.c b/drivers/usb/host/xhci-ring.c
index 5e548a1c93ab..c8a880111435 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -57,7 +57,6 @@
#include <linux/dma-mapping.h>
#include "xhci.h"
#include "xhci-trace.h"
-#include "xhci-mtk.h"

static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
u32 field1, u32 field2,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index bd27bd670104..13baeda927f0 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -20,7 +20,6 @@

#include "xhci.h"
#include "xhci-trace.h"
-#include "xhci-mtk.h"
#include "xhci-debugfs.h"
#include "xhci-dbgcap.h"

@@ -1420,6 +1419,7 @@ unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc)
(usb_endpoint_dir_in(desc) ? 1 : 0) - 1;
return index;
}
+EXPORT_SYMBOL_GPL(xhci_get_endpoint_index);

/* The reverse operation to xhci_get_endpoint_index. Calculate the USB endpoint
* address from the XHCI endpoint index.
@@ -1852,8 +1852,8 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
* disabled, so there's no need for mutual exclusion to protect
* the xhci->devs[slot_id] structure.
*/
-static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
- struct usb_host_endpoint *ep)
+int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
struct xhci_container_ctx *in_ctx, *out_ctx;
@@ -1913,9 +1913,6 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,

xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);

- if (xhci->quirks & XHCI_MTK_HOST)
- xhci_mtk_drop_ep_quirk(hcd, udev, ep);
-
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
@@ -1923,6 +1920,7 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
(unsigned int) new_add_flags);
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_drop_endpoint);

/* Add an endpoint to a new possible bandwidth configuration for this device.
* Only one call to this function is allowed per endpoint before
@@ -1937,8 +1935,8 @@ static int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* configuration or alt setting is installed in the device, so there's no need
* for mutual exclusion to protect the xhci->devs[slot_id] structure.
*/
-static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
- struct usb_host_endpoint *ep)
+int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
struct xhci_container_ctx *in_ctx;
@@ -2012,15 +2010,6 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
return -ENOMEM;
}

- if (xhci->quirks & XHCI_MTK_HOST) {
- ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
- if (ret < 0) {
- xhci_ring_free(xhci, virt_dev->eps[ep_index].new_ring);
- virt_dev->eps[ep_index].new_ring = NULL;
- return ret;
- }
- }
-
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);

@@ -2045,6 +2034,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
(unsigned int) new_add_flags);
return 0;
}
+EXPORT_SYMBOL_GPL(xhci_add_endpoint);

static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev)
{
@@ -3078,6 +3068,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)

return ret;
}
+EXPORT_SYMBOL_GPL(xhci_check_bandwidth);

void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
{
@@ -3102,6 +3093,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
}
xhci_zero_in_ctx(xhci, virt_dev);
}
+EXPORT_SYMBOL_GPL(xhci_reset_bandwidth);

static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
@@ -5428,6 +5420,10 @@ void xhci_init_driver(struct hc_driver *drv,
drv->reset = over->reset;
if (over->start)
drv->start = over->start;
+ if (over->add_endpoint)
+ drv->add_endpoint = over->add_endpoint;
+ if (over->drop_endpoint)
+ drv->drop_endpoint = over->drop_endpoint;
if (over->check_bandwidth)
drv->check_bandwidth = over->check_bandwidth;
if (over->reset_bandwidth)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index d41de5dc0452..5053c1adda1e 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1928,6 +1928,10 @@ struct xhci_driver_overrides {
size_t extra_priv_size;
int (*reset)(struct usb_hcd *hcd);
int (*start)(struct usb_hcd *hcd);
+ int (*add_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+ int (*drop_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
};
@@ -2080,6 +2084,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_shutdown(struct usb_hcd *hcd);
void xhci_init_driver(struct hc_driver *drv,
const struct xhci_driver_overrides *over);
+int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+ struct usb_host_endpoint *ep);
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
--
2.18.0

2021-03-05 09:06:06

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 12/17] usb: xhci-mtk: rebuild the way to get bandwidth domain

Rebuild the function get_bw_index(), get the bandwidth domain
directly instead its index of domain array.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 1562875c04ab..d39545ade9a1 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -57,7 +57,7 @@ static u32 get_bw_boundary(enum usb_device_speed speed)
}

/*
-* get the index of bandwidth domains array which @ep belongs to.
+* get the bandwidth domain which @ep belongs to.
*
* the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk,
* each HS root port is treated as a single bandwidth domain,
@@ -68,9 +68,11 @@ static u32 get_bw_boundary(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;

@@ -86,7 +88,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)
@@ -722,14 +724,11 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
struct xhci_hcd *xhci;
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, *tmp;
- int bw_index;

xhci = hcd_to_xhci(hcd);
virt_dev = xhci->devs[udev->slot_id];
- 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,
@@ -739,8 +738,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info))
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_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) {
if (sch_ep->ep == ep) {
@@ -758,13 +756,12 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
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;
- int bw_index, ret;
+ 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) {
- bw_index = get_bw_index(xhci, udev, sch_ep->ep);
- sch_bw = &mtk->sch_array[bw_index];
+ sch_bw = get_bw_info(mtk, udev, sch_ep->ep);

ret = check_sch_bw(sch_bw, sch_ep);
if (ret) {
@@ -778,9 +775,7 @@ int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
struct usb_host_endpoint *ep = sch_ep->ep;
unsigned int ep_index = xhci_get_endpoint_index(&ep->desc);

- bw_index = get_bw_index(xhci, udev, ep);
- sch_bw = &mtk->sch_array[bw_index];
-
+ 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);
@@ -805,13 +800,11 @@ void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct mu3h_sch_bw_info *sch_bw;
struct mu3h_sch_ep_info *sch_ep, *tmp;
- int bw_index;

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) {
- bw_index = get_bw_index(xhci, udev, sch_ep->ep);
- sch_bw = &mtk->sch_array[bw_index];
+ sch_bw = get_bw_info(mtk, udev, sch_ep->ep);
destroy_sch_ep(udev, sch_bw, sch_ep);
}

--
2.18.0

2021-03-05 09:06:33

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 16/17] usb: common: add function to get interval expressed in us unit

Add a new function to convert bInterval into the time expressed
in 1us unit.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/common/common.c | 33 +++++++++++++++++++++++++++++++++
drivers/usb/core/devices.c | 21 ++++-----------------
drivers/usb/core/endpoint.c | 35 ++++-------------------------------
include/linux/usb/ch9.h | 11 +++++++++++
4 files changed, 52 insertions(+), 48 deletions(-)

diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index fc21cf2d36f6..5dd7e657e369 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -165,6 +165,39 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev)
}
EXPORT_SYMBOL_GPL(usb_get_dr_mode);

+unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
+ enum usb_device_speed speed)
+{
+ unsigned int interval = 0;
+
+ switch (usb_endpoint_type(epd)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* uframes per NAK */
+ if (speed == USB_SPEED_HIGH)
+ interval = epd->bInterval;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ interval = 1 << (epd->bInterval - 1);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ /* uframes per NAK */
+ if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
+ interval = epd->bInterval;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (speed >= USB_SPEED_HIGH)
+ interval = 1 << (epd->bInterval - 1);
+ else
+ interval = epd->bInterval;
+ break;
+ }
+
+ interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
+
+ return interval;
+}
+EXPORT_SYMBOL_GPL(usb_decode_interval);
+
#ifdef CONFIG_OF
/**
* of_usb_get_dr_mode_by_phy - Get dual role mode for the controller device
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 1ef2de6e375a..d8b0041de612 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -157,38 +157,25 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
type = "Ctrl";
- if (speed == USB_SPEED_HIGH) /* uframes per NAK */
- interval = desc->bInterval;
- else
- interval = 0;
dir = 'B'; /* ctrl is bidirectional */
break;
case USB_ENDPOINT_XFER_ISOC:
type = "Isoc";
- interval = 1 << (desc->bInterval - 1);
break;
case USB_ENDPOINT_XFER_BULK:
type = "Bulk";
- if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */
- interval = desc->bInterval;
- else
- interval = 0;
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
- if (speed == USB_SPEED_HIGH || speed >= USB_SPEED_SUPER)
- interval = 1 << (desc->bInterval - 1);
- else
- interval = desc->bInterval;
break;
default: /* "can't happen" */
return start;
}
- interval *= (speed == USB_SPEED_HIGH ||
- speed >= USB_SPEED_SUPER) ? 125 : 1000;
- if (interval % 1000)
+
+ interval = usb_decode_interval(desc, speed);
+ if (interval % 1000) {
unit = 'u';
- else {
+ } else {
unit = 'm';
interval /= 1000;
}
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 903426b6d305..a2530811cf7d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -84,40 +84,13 @@ static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ep_device *ep = to_ep_device(dev);
+ unsigned int interval;
char unit;
- unsigned interval = 0;
- unsigned in;

- in = (ep->desc->bEndpointAddress & USB_DIR_IN);
-
- switch (usb_endpoint_type(ep->desc)) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (ep->udev->speed == USB_SPEED_HIGH)
- /* uframes per NAK */
- interval = ep->desc->bInterval;
- break;
-
- case USB_ENDPOINT_XFER_ISOC:
- interval = 1 << (ep->desc->bInterval - 1);
- break;
-
- case USB_ENDPOINT_XFER_BULK:
- if (ep->udev->speed == USB_SPEED_HIGH && !in)
- /* uframes per NAK */
- interval = ep->desc->bInterval;
- break;
-
- case USB_ENDPOINT_XFER_INT:
- if (ep->udev->speed == USB_SPEED_HIGH)
- interval = 1 << (ep->desc->bInterval - 1);
- else
- interval = ep->desc->bInterval;
- break;
- }
- interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
- if (interval % 1000)
+ interval = usb_decode_interval(ep->desc, ep->udev->speed);
+ if (interval % 1000) {
unit = 'u';
- else {
+ } else {
unit = 'm';
interval /= 1000;
}
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index abdd310c77f0..1a6d44ae707b 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -90,6 +90,17 @@ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev);
*/
extern const char *usb_state_string(enum usb_device_state state);

+/**
+ * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
+ * @epd: The descriptor of the endpoint
+ * @speed: The speed that the endpoint works as
+ *
+ * Function returns the interval expressed in 1us unit for servicing
+ * endpoint for data transfers.
+ */
+unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
+ enum usb_device_speed speed);
+
#ifdef CONFIG_TRACING
/**
* usb_decode_ctrl - Returns human readable representation of control request.
--
2.18.0

2021-03-05 09:06:56

by Chunfeng Yun

[permalink] [raw]
Subject: [PATCH 05/17] usb: xhci-mtk: use @sch_tt to check whether need do TT schedule

It's clearer to use @sch_tt to check whether need do TT schedule,
no function is changed.

Signed-off-by: Chunfeng Yun <[email protected]>
---
drivers/usb/host/xhci-mtk-sch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
index 817ef2815e67..9016188eee97 100644
--- a/drivers/usb/host/xhci-mtk-sch.c
+++ b/drivers/usb/host/xhci-mtk-sch.c
@@ -548,7 +548,7 @@ static int check_sch_bw(struct usb_device *udev,
min_num_budget = sch_ep->num_budget_microframes;
esit_boundary = get_esit_boundary(sch_ep);
for (offset = 0; offset < sch_ep->esit; offset++) {
- if (is_fs_or_ls(udev->speed)) {
+ if (sch_ep->sch_tt) {
ret = check_sch_tt(udev, sch_ep, offset);
if (ret)
continue;
@@ -585,7 +585,7 @@ static int check_sch_bw(struct usb_device *udev,
sch_ep->cs_count = min_cs_count;
sch_ep->num_budget_microframes = min_num_budget;

- if (is_fs_or_ls(udev->speed)) {
+ if (sch_ep->sch_tt) {
/* all offset for tt is not ok*/
if (!tt_offset_ok)
return -ERANGE;
--
2.18.0

2021-03-05 09:15:31

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 03/17] usb: xhci-mtk: get the microframe boundary for ESIT

Hello!

On 05.03.2021 12:02, Chunfeng Yun wrote:

> Tune the boundary for FS/LS ESIT due to CS:
> For ISOC out-ep, the controller starts transfer data after
> the first SS; for others, the data is already transfered

Transferred.

> before the last CS.
>
> Signed-off-by: Chunfeng Yun <[email protected]>
> ---
> drivers/usb/host/xhci-mtk-sch.c | 24 +++++++++++++++++++-----
> 1 file changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> index 8950d1f10a7f..e3b18dfca874 100644
> --- a/drivers/usb/host/xhci-mtk-sch.c
> +++ b/drivers/usb/host/xhci-mtk-sch.c
> @@ -513,22 +513,35 @@ static void update_sch_tt(struct usb_device *udev,
> list_del(&sch_ep->tt_endpoint);
> }
>
> +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 += 1;

Why not:

boundary++;

> + else if (boundary > 1) /* normally esit >= 8 for FS/LS */
> + boundary -= 1;

boundary--;

[...]

MBR, Sergei

2021-03-05 09:19:13

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 03/17] usb: xhci-mtk: get the microframe boundary for ESIT

On Fri, Mar 05, 2021 at 12:13:33PM +0300, Sergei Shtylyov wrote:
> Hello!
>
> On 05.03.2021 12:02, Chunfeng Yun wrote:
>
> > Tune the boundary for FS/LS ESIT due to CS:
> > For ISOC out-ep, the controller starts transfer data after
> > the first SS; for others, the data is already transfered
>
> Transferred.
>
> > before the last CS.
> >
> > Signed-off-by: Chunfeng Yun <[email protected]>
> > ---
> > drivers/usb/host/xhci-mtk-sch.c | 24 +++++++++++++++++++-----
> > 1 file changed, 19 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> > index 8950d1f10a7f..e3b18dfca874 100644
> > --- a/drivers/usb/host/xhci-mtk-sch.c
> > +++ b/drivers/usb/host/xhci-mtk-sch.c
> > @@ -513,22 +513,35 @@ static void update_sch_tt(struct usb_device *udev,
> > list_del(&sch_ep->tt_endpoint);
> > }
> > +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 += 1;
>
> Why not:
>
> boundary++;
>
> > + else if (boundary > 1) /* normally esit >= 8 for FS/LS */
> > + boundary -= 1;
>
> boundary--;

Doesn't matter either way, it's the author's choice.

greg k-h

2021-03-05 15:34:52

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH 16/17] usb: common: add function to get interval expressed in us unit

On Fri, Mar 05, 2021 at 05:02:54PM +0800, Chunfeng Yun wrote:
> Add a new function to convert bInterval into the time expressed
> in 1us unit.
>
> Signed-off-by: Chunfeng Yun <[email protected]>
> ---

> --- a/drivers/usb/common/common.c
> +++ b/drivers/usb/common/common.c
> @@ -165,6 +165,39 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev)
> }
> EXPORT_SYMBOL_GPL(usb_get_dr_mode);
>
> +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> + enum usb_device_speed speed)
> +{
> + unsigned int interval = 0;
> +
> + switch (usb_endpoint_type(epd)) {
> + case USB_ENDPOINT_XFER_CONTROL:
> + /* uframes per NAK */
> + if (speed == USB_SPEED_HIGH)
> + interval = epd->bInterval;
> + break;
> + case USB_ENDPOINT_XFER_ISOC:
> + interval = 1 << (epd->bInterval - 1);
> + break;
> + case USB_ENDPOINT_XFER_BULK:
> + /* uframes per NAK */
> + if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
> + interval = epd->bInterval;
> + break;
> + case USB_ENDPOINT_XFER_INT:
> + if (speed >= USB_SPEED_HIGH)
> + interval = 1 << (epd->bInterval - 1);
> + else
> + interval = epd->bInterval;
> + break;
> + }
> +
> + interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
> +
> + return interval;
> +}
> +EXPORT_SYMBOL_GPL(usb_decode_interval);

> --- a/include/linux/usb/ch9.h
> +++ b/include/linux/usb/ch9.h
> @@ -90,6 +90,17 @@ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev);
> */
> extern const char *usb_state_string(enum usb_device_state state);
>
> +/**
> + * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
> + * @epd: The descriptor of the endpoint
> + * @speed: The speed that the endpoint works as
> + *
> + * Function returns the interval expressed in 1us unit for servicing
> + * endpoint for data transfers.
> + */
> +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> + enum usb_device_speed speed);

As a general rule, I believe people expect to find the kerneldoc for a
function next to the function's definition, not next to the declaration
in a header file.

Alan Stern

2021-03-05 15:49:30

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 16/17] usb: common: add function to get interval expressed in us unit

On Fri, Mar 05, 2021 at 10:33:12AM -0500, Alan Stern wrote:
> On Fri, Mar 05, 2021 at 05:02:54PM +0800, Chunfeng Yun wrote:
> > Add a new function to convert bInterval into the time expressed
> > in 1us unit.
> >
> > Signed-off-by: Chunfeng Yun <[email protected]>
> > ---
>
> > --- a/drivers/usb/common/common.c
> > +++ b/drivers/usb/common/common.c
> > @@ -165,6 +165,39 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev)
> > }
> > EXPORT_SYMBOL_GPL(usb_get_dr_mode);
> >
> > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > + enum usb_device_speed speed)
> > +{
> > + unsigned int interval = 0;
> > +
> > + switch (usb_endpoint_type(epd)) {
> > + case USB_ENDPOINT_XFER_CONTROL:
> > + /* uframes per NAK */
> > + if (speed == USB_SPEED_HIGH)
> > + interval = epd->bInterval;
> > + break;
> > + case USB_ENDPOINT_XFER_ISOC:
> > + interval = 1 << (epd->bInterval - 1);
> > + break;
> > + case USB_ENDPOINT_XFER_BULK:
> > + /* uframes per NAK */
> > + if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
> > + interval = epd->bInterval;
> > + break;
> > + case USB_ENDPOINT_XFER_INT:
> > + if (speed >= USB_SPEED_HIGH)
> > + interval = 1 << (epd->bInterval - 1);
> > + else
> > + interval = epd->bInterval;
> > + break;
> > + }
> > +
> > + interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
> > +
> > + return interval;
> > +}
> > +EXPORT_SYMBOL_GPL(usb_decode_interval);
>
> > --- a/include/linux/usb/ch9.h
> > +++ b/include/linux/usb/ch9.h
> > @@ -90,6 +90,17 @@ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev);
> > */
> > extern const char *usb_state_string(enum usb_device_state state);
> >
> > +/**
> > + * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
> > + * @epd: The descriptor of the endpoint
> > + * @speed: The speed that the endpoint works as
> > + *
> > + * Function returns the interval expressed in 1us unit for servicing
> > + * endpoint for data transfers.
> > + */
> > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > + enum usb_device_speed speed);
>
> As a general rule, I believe people expect to find the kerneldoc for a
> function next to the function's definition, not next to the declaration
> in a header file.

I was going to make the same review comment, but if you look above this
in that file, there's other kernel doc information in the .h file, so
this does match with the style of the file :(

We can fix that all up later.

thanks,

greg k-h

2021-03-08 02:42:49

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 15/17] usb: xhci-mtk: support to build xhci-mtk-hcd.ko

On Fri, Mar 05, 2021 at 05:02:53PM +0800, Chunfeng Yun wrote:
> Currently xhci-hcd.ko building depends on USB_XHCI_MTK, this
> is not flexible for some cases. For example:
> USB_XHCI_HCD is y, and USB_XHCI_MTK is m, then we can't
> implement extended functions if only update xhci-mtk.ko
> This patch is used to remove the dependence.
>
> Signed-off-by: Chunfeng Yun <[email protected]>

Oh nice, I tried to unwind this once, but did not succeed.

Mathias, any objection to this? I think this is the only patch in this
series that touches the non-mtk code, want me to just queue it up in my
tree, or are you going to send it to me through your patches?

thanks,
g
reg k-h

2021-03-08 08:35:14

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 03/17] usb: xhci-mtk: get the microframe boundary for ESIT

On Fri, 2021-03-05 at 12:13 +0300, Sergei Shtylyov wrote:
> Hello!
>
> On 05.03.2021 12:02, Chunfeng Yun wrote:
>
> > Tune the boundary for FS/LS ESIT due to CS:
> > For ISOC out-ep, the controller starts transfer data after
> > the first SS; for others, the data is already transfered
>
> Transferred.
Ok
>
> > before the last CS.
> >
> > Signed-off-by: Chunfeng Yun <[email protected]>
> > ---
> > drivers/usb/host/xhci-mtk-sch.c | 24 +++++++++++++++++++-----
> > 1 file changed, 19 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/usb/host/xhci-mtk-sch.c b/drivers/usb/host/xhci-mtk-sch.c
> > index 8950d1f10a7f..e3b18dfca874 100644
> > --- a/drivers/usb/host/xhci-mtk-sch.c
> > +++ b/drivers/usb/host/xhci-mtk-sch.c
> > @@ -513,22 +513,35 @@ static void update_sch_tt(struct usb_device *udev,
> > list_del(&sch_ep->tt_endpoint);
> > }
> >
> > +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 += 1;
>
> Why not:
>
> boundary++;
Forgot it, it's modified from "boundary = sch_ep->esit + 1;"

Thanks
>
> > + else if (boundary > 1) /* normally esit >= 8 for FS/LS */
> > + boundary -= 1;
>
> boundary--;
>
> [...]
>
> MBR, Sergei

2021-03-08 08:35:28

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 16/17] usb: common: add function to get interval expressed in us unit

On Fri, 2021-03-05 at 16:47 +0100, Greg Kroah-Hartman wrote:
> On Fri, Mar 05, 2021 at 10:33:12AM -0500, Alan Stern wrote:
> > On Fri, Mar 05, 2021 at 05:02:54PM +0800, Chunfeng Yun wrote:
> > > Add a new function to convert bInterval into the time expressed
> > > in 1us unit.
> > >
> > > Signed-off-by: Chunfeng Yun <[email protected]>
> > > ---
> >
> > > --- a/drivers/usb/common/common.c
> > > +++ b/drivers/usb/common/common.c
> > > @@ -165,6 +165,39 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev)
> > > }
> > > EXPORT_SYMBOL_GPL(usb_get_dr_mode);
> > >
> > > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > > + enum usb_device_speed speed)
> > > +{
> > > + unsigned int interval = 0;
> > > +
> > > + switch (usb_endpoint_type(epd)) {
> > > + case USB_ENDPOINT_XFER_CONTROL:
> > > + /* uframes per NAK */
> > > + if (speed == USB_SPEED_HIGH)
> > > + interval = epd->bInterval;
> > > + break;
> > > + case USB_ENDPOINT_XFER_ISOC:
> > > + interval = 1 << (epd->bInterval - 1);
> > > + break;
> > > + case USB_ENDPOINT_XFER_BULK:
> > > + /* uframes per NAK */
> > > + if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
> > > + interval = epd->bInterval;
> > > + break;
> > > + case USB_ENDPOINT_XFER_INT:
> > > + if (speed >= USB_SPEED_HIGH)
> > > + interval = 1 << (epd->bInterval - 1);
> > > + else
> > > + interval = epd->bInterval;
> > > + break;
> > > + }
> > > +
> > > + interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
> > > +
> > > + return interval;
> > > +}
> > > +EXPORT_SYMBOL_GPL(usb_decode_interval);
> >
> > > --- a/include/linux/usb/ch9.h
> > > +++ b/include/linux/usb/ch9.h
> > > @@ -90,6 +90,17 @@ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev);
> > > */
> > > extern const char *usb_state_string(enum usb_device_state state);
> > >
> > > +/**
> > > + * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
> > > + * @epd: The descriptor of the endpoint
> > > + * @speed: The speed that the endpoint works as
> > > + *
> > > + * Function returns the interval expressed in 1us unit for servicing
> > > + * endpoint for data transfers.
> > > + */
> > > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > > + enum usb_device_speed speed);
> >
> > As a general rule, I believe people expect to find the kerneldoc for a
> > function next to the function's definition, not next to the declaration
> > in a header file.
>
> I was going to make the same review comment, but if you look above this
> in that file, there's other kernel doc information in the .h file, so
> this does match with the style of the file :(
>
> We can fix that all up later.
I'll prepare a patch

Thank you
>
> thanks,
>
> greg k-h

2021-03-08 08:37:11

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 16/17] usb: common: add function to get interval expressed in us unit

On Fri, 2021-03-05 at 10:33 -0500, Alan Stern wrote:
> On Fri, Mar 05, 2021 at 05:02:54PM +0800, Chunfeng Yun wrote:
> > Add a new function to convert bInterval into the time expressed
> > in 1us unit.
> >
> > Signed-off-by: Chunfeng Yun <[email protected]>
> > ---
>
> > --- a/drivers/usb/common/common.c
> > +++ b/drivers/usb/common/common.c
> > @@ -165,6 +165,39 @@ enum usb_dr_mode usb_get_dr_mode(struct device *dev)
> > }
> > EXPORT_SYMBOL_GPL(usb_get_dr_mode);
> >
> > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > + enum usb_device_speed speed)
> > +{
> > + unsigned int interval = 0;
> > +
> > + switch (usb_endpoint_type(epd)) {
> > + case USB_ENDPOINT_XFER_CONTROL:
> > + /* uframes per NAK */
> > + if (speed == USB_SPEED_HIGH)
> > + interval = epd->bInterval;
> > + break;
> > + case USB_ENDPOINT_XFER_ISOC:
> > + interval = 1 << (epd->bInterval - 1);
> > + break;
> > + case USB_ENDPOINT_XFER_BULK:
> > + /* uframes per NAK */
> > + if (speed == USB_SPEED_HIGH && usb_endpoint_dir_out(epd))
> > + interval = epd->bInterval;
> > + break;
> > + case USB_ENDPOINT_XFER_INT:
> > + if (speed >= USB_SPEED_HIGH)
> > + interval = 1 << (epd->bInterval - 1);
> > + else
> > + interval = epd->bInterval;
> > + break;
> > + }
> > +
> > + interval *= (speed >= USB_SPEED_HIGH) ? 125 : 1000;
> > +
> > + return interval;
> > +}
> > +EXPORT_SYMBOL_GPL(usb_decode_interval);
>
> > --- a/include/linux/usb/ch9.h
> > +++ b/include/linux/usb/ch9.h
> > @@ -90,6 +90,17 @@ extern enum usb_ssp_rate usb_get_maximum_ssp_rate(struct device *dev);
> > */
> > extern const char *usb_state_string(enum usb_device_state state);
> >
> > +/**
> > + * usb_decode_interval - Decode bInterval into the time expressed in 1us unit
> > + * @epd: The descriptor of the endpoint
> > + * @speed: The speed that the endpoint works as
> > + *
> > + * Function returns the interval expressed in 1us unit for servicing
> > + * endpoint for data transfers.
> > + */
> > +unsigned int usb_decode_interval(const struct usb_endpoint_descriptor *epd,
> > + enum usb_device_speed speed);
>
> As a general rule, I believe people expect to find the kerneldoc for a
> function next to the function's definition, not next to the declaration
> in a header file.
Got it, thanks

>
> Alan Stern

2021-03-08 11:23:14

by Mathias Nyman

[permalink] [raw]
Subject: Re: [PATCH 15/17] usb: xhci-mtk: support to build xhci-mtk-hcd.ko

On 7.3.2021 18.00, Greg Kroah-Hartman wrote:
> On Fri, Mar 05, 2021 at 05:02:53PM +0800, Chunfeng Yun wrote:
>> Currently xhci-hcd.ko building depends on USB_XHCI_MTK, this
>> is not flexible for some cases. For example:
>> USB_XHCI_HCD is y, and USB_XHCI_MTK is m, then we can't
>> implement extended functions if only update xhci-mtk.ko
>> This patch is used to remove the dependence.
>>
>> Signed-off-by: Chunfeng Yun <[email protected]>
>
> Oh nice, I tried to unwind this once, but did not succeed.
>
> Mathias, any objection to this? I think this is the only patch in this
> series that touches the non-mtk code, want me to just queue it up in my
> tree, or are you going to send it to me through your patches?
>

No objection, Chunfeng Yun sent v2 already, it looks good to me.
Easier (for me) if you queue up the whole series directly

Thanks
- Mathias