1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2015 MediaTek Inc. |
4 | * Author: |
5 | * Zhigang.Wei <zhigang.wei@mediatek.com> |
6 | * Chunfeng.Yun <chunfeng.yun@mediatek.com> |
7 | */ |
8 | |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> |
11 | #include <linux/slab.h> |
12 | |
13 | #include "xhci.h" |
14 | #include "xhci-mtk.h" |
15 | |
16 | #define SSP_BW_BOUNDARY 130000 |
17 | #define SS_BW_BOUNDARY 51000 |
18 | /* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */ |
19 | #define HS_BW_BOUNDARY 6144 |
20 | /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ |
21 | #define FS_PAYLOAD_MAX 188 |
22 | #define LS_PAYLOAD_MAX 18 |
23 | /* section 11.18.1, per fs frame */ |
24 | #define FS_BW_BOUNDARY 1157 |
25 | #define LS_BW_BOUNDARY 144 |
26 | |
27 | /* |
28 | * max number of microframes for split transfer, assume extra-cs budget is 0 |
29 | * for fs isoc in : 1 ss + 1 idle + 6 cs (roundup(1023/188)) |
30 | */ |
31 | #define TT_MICROFRAMES_MAX 8 |
32 | /* offset from SS for fs/ls isoc/intr ep (ss + idle) */ |
33 | #define CS_OFFSET 2 |
34 | |
35 | #define DBG_BUF_EN 64 |
36 | |
37 | /* schedule error type */ |
38 | #define ESCH_SS_Y6 1001 |
39 | #define ESCH_SS_OVERLAP 1002 |
40 | #define ESCH_CS_OVERFLOW 1003 |
41 | #define ESCH_BW_OVERFLOW 1004 |
42 | #define ESCH_FIXME 1005 |
43 | |
44 | /* mtk scheduler bitmasks */ |
45 | #define EP_BPKTS(p) ((p) & 0x7f) |
46 | #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) |
47 | #define EP_BBM(p) ((p) << 11) |
48 | #define EP_BOFFSET(p) ((p) & 0x3fff) |
49 | #define EP_BREPEAT(p) (((p) & 0x7fff) << 16) |
50 | |
51 | static char *sch_error_string(int err_num) |
52 | { |
53 | switch (err_num) { |
54 | case ESCH_SS_Y6: |
55 | return "Can't schedule Start-Split in Y6" ; |
56 | case ESCH_SS_OVERLAP: |
57 | return "Can't find a suitable Start-Split location" ; |
58 | case ESCH_CS_OVERFLOW: |
59 | return "The last Complete-Split is greater than 7" ; |
60 | case ESCH_BW_OVERFLOW: |
61 | return "Bandwidth exceeds the maximum limit" ; |
62 | case ESCH_FIXME: |
63 | return "FIXME, to be resolved" ; |
64 | default: |
65 | return "Unknown" ; |
66 | } |
67 | } |
68 | |
69 | static int is_fs_or_ls(enum usb_device_speed speed) |
70 | { |
71 | return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW; |
72 | } |
73 | |
74 | static const char * |
75 | decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed) |
76 | { |
77 | static char buf[DBG_BUF_EN]; |
78 | struct usb_endpoint_descriptor *epd = &ep->desc; |
79 | unsigned int interval; |
80 | const char *unit; |
81 | |
82 | interval = usb_decode_interval(epd, speed); |
83 | if (interval % 1000) { |
84 | unit = "us" ; |
85 | } else { |
86 | unit = "ms" ; |
87 | interval /= 1000; |
88 | } |
89 | |
90 | snprintf(buf, DBG_BUF_EN, fmt: "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s" , |
91 | usb_speed_string(speed), usb_endpoint_num(epd), |
92 | usb_endpoint_dir_in(epd) ? "in" : "out" , |
93 | usb_ep_type_string(ep_type: usb_endpoint_type(epd)), |
94 | usb_endpoint_maxp(epd), epd->bInterval, interval, unit); |
95 | |
96 | return buf; |
97 | } |
98 | |
99 | static u32 get_bw_boundary(enum usb_device_speed speed) |
100 | { |
101 | u32 boundary; |
102 | |
103 | switch (speed) { |
104 | case USB_SPEED_SUPER_PLUS: |
105 | boundary = SSP_BW_BOUNDARY; |
106 | break; |
107 | case USB_SPEED_SUPER: |
108 | boundary = SS_BW_BOUNDARY; |
109 | break; |
110 | default: |
111 | boundary = HS_BW_BOUNDARY; |
112 | break; |
113 | } |
114 | |
115 | return boundary; |
116 | } |
117 | |
118 | /* |
119 | * get the bandwidth domain which @ep belongs to. |
120 | * |
121 | * the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk, |
122 | * each HS root port is treated as a single bandwidth domain, |
123 | * but each SS root port is treated as two bandwidth domains, one for IN eps, |
124 | * one for OUT eps. |
125 | */ |
126 | static struct mu3h_sch_bw_info * |
127 | get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev, |
128 | struct usb_host_endpoint *ep) |
129 | { |
130 | struct xhci_hcd *xhci = hcd_to_xhci(hcd: mtk->hcd); |
131 | struct xhci_virt_device *virt_dev; |
132 | int bw_index; |
133 | |
134 | virt_dev = xhci->devs[udev->slot_id]; |
135 | if (!virt_dev->rhub_port) { |
136 | WARN_ONCE(1, "%s invalid rhub port\n" , dev_name(&udev->dev)); |
137 | return NULL; |
138 | } |
139 | |
140 | if (udev->speed >= USB_SPEED_SUPER) { |
141 | if (usb_endpoint_dir_out(epd: &ep->desc)) |
142 | bw_index = (virt_dev->rhub_port->hw_portnum) * 2; |
143 | else |
144 | bw_index = (virt_dev->rhub_port->hw_portnum) * 2 + 1; |
145 | } else { |
146 | /* add one more for each SS port */ |
147 | bw_index = virt_dev->rhub_port->hw_portnum + xhci->usb3_rhub.num_ports; |
148 | } |
149 | |
150 | return &mtk->sch_array[bw_index]; |
151 | } |
152 | |
153 | static u32 get_esit(struct xhci_ep_ctx *ep_ctx) |
154 | { |
155 | u32 esit; |
156 | |
157 | esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); |
158 | if (esit > XHCI_MTK_MAX_ESIT) |
159 | esit = XHCI_MTK_MAX_ESIT; |
160 | |
161 | return esit; |
162 | } |
163 | |
164 | static struct mu3h_sch_tt *find_tt(struct usb_device *udev) |
165 | { |
166 | struct usb_tt *utt = udev->tt; |
167 | struct mu3h_sch_tt *tt, **tt_index, **ptt; |
168 | bool allocated_index = false; |
169 | |
170 | if (!utt) |
171 | return NULL; /* Not below a TT */ |
172 | |
173 | /* |
174 | * Find/create our data structure. |
175 | * For hubs with a single TT, we get it directly. |
176 | * For hubs with multiple TTs, there's an extra level of pointers. |
177 | */ |
178 | tt_index = NULL; |
179 | if (utt->multi) { |
180 | tt_index = utt->hcpriv; |
181 | if (!tt_index) { /* Create the index array */ |
182 | tt_index = kcalloc(n: utt->hub->maxchild, |
183 | size: sizeof(*tt_index), GFP_KERNEL); |
184 | if (!tt_index) |
185 | return ERR_PTR(error: -ENOMEM); |
186 | utt->hcpriv = tt_index; |
187 | allocated_index = true; |
188 | } |
189 | ptt = &tt_index[udev->ttport - 1]; |
190 | } else { |
191 | ptt = (struct mu3h_sch_tt **) &utt->hcpriv; |
192 | } |
193 | |
194 | tt = *ptt; |
195 | if (!tt) { /* Create the mu3h_sch_tt */ |
196 | tt = kzalloc(size: sizeof(*tt), GFP_KERNEL); |
197 | if (!tt) { |
198 | if (allocated_index) { |
199 | utt->hcpriv = NULL; |
200 | kfree(objp: tt_index); |
201 | } |
202 | return ERR_PTR(error: -ENOMEM); |
203 | } |
204 | INIT_LIST_HEAD(list: &tt->ep_list); |
205 | *ptt = tt; |
206 | } |
207 | |
208 | return tt; |
209 | } |
210 | |
211 | /* Release the TT above udev, if it's not in use */ |
212 | static void drop_tt(struct usb_device *udev) |
213 | { |
214 | struct usb_tt *utt = udev->tt; |
215 | struct mu3h_sch_tt *tt, **tt_index, **ptt; |
216 | int i, cnt; |
217 | |
218 | if (!utt || !utt->hcpriv) |
219 | return; /* Not below a TT, or never allocated */ |
220 | |
221 | cnt = 0; |
222 | if (utt->multi) { |
223 | tt_index = utt->hcpriv; |
224 | ptt = &tt_index[udev->ttport - 1]; |
225 | /* How many entries are left in tt_index? */ |
226 | for (i = 0; i < utt->hub->maxchild; ++i) |
227 | cnt += !!tt_index[i]; |
228 | } else { |
229 | tt_index = NULL; |
230 | ptt = (struct mu3h_sch_tt **)&utt->hcpriv; |
231 | } |
232 | |
233 | tt = *ptt; |
234 | if (!tt || !list_empty(head: &tt->ep_list)) |
235 | return; /* never allocated , or still in use*/ |
236 | |
237 | *ptt = NULL; |
238 | kfree(objp: tt); |
239 | |
240 | if (cnt == 1) { |
241 | utt->hcpriv = NULL; |
242 | kfree(objp: tt_index); |
243 | } |
244 | } |
245 | |
246 | static struct mu3h_sch_ep_info * |
247 | create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, |
248 | struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) |
249 | { |
250 | struct mu3h_sch_ep_info *sch_ep; |
251 | struct mu3h_sch_bw_info *bw_info; |
252 | struct mu3h_sch_tt *tt = NULL; |
253 | u32 len; |
254 | |
255 | bw_info = get_bw_info(mtk, udev, ep); |
256 | if (!bw_info) |
257 | return ERR_PTR(error: -ENODEV); |
258 | |
259 | if (is_fs_or_ls(speed: udev->speed)) |
260 | len = TT_MICROFRAMES_MAX; |
261 | else if ((udev->speed >= USB_SPEED_SUPER) && |
262 | usb_endpoint_xfer_isoc(epd: &ep->desc)) |
263 | len = get_esit(ep_ctx); |
264 | else |
265 | len = 1; |
266 | |
267 | sch_ep = kzalloc(struct_size(sch_ep, bw_budget_table, len), GFP_KERNEL); |
268 | if (!sch_ep) |
269 | return ERR_PTR(error: -ENOMEM); |
270 | |
271 | if (is_fs_or_ls(speed: udev->speed)) { |
272 | tt = find_tt(udev); |
273 | if (IS_ERR(ptr: tt)) { |
274 | kfree(objp: sch_ep); |
275 | return ERR_PTR(error: -ENOMEM); |
276 | } |
277 | } |
278 | |
279 | sch_ep->bw_info = bw_info; |
280 | sch_ep->sch_tt = tt; |
281 | sch_ep->ep = ep; |
282 | sch_ep->speed = udev->speed; |
283 | INIT_LIST_HEAD(list: &sch_ep->endpoint); |
284 | INIT_LIST_HEAD(list: &sch_ep->tt_endpoint); |
285 | INIT_HLIST_NODE(h: &sch_ep->hentry); |
286 | |
287 | return sch_ep; |
288 | } |
289 | |
290 | static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, |
291 | struct mu3h_sch_ep_info *sch_ep) |
292 | { |
293 | u32 ep_type; |
294 | u32 maxpkt; |
295 | u32 max_burst; |
296 | u32 mult; |
297 | u32 esit_pkts; |
298 | u32 max_esit_payload; |
299 | u32 bw_per_microframe; |
300 | u32 *bwb_table; |
301 | int i; |
302 | |
303 | bwb_table = sch_ep->bw_budget_table; |
304 | ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); |
305 | maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); |
306 | max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); |
307 | mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); |
308 | max_esit_payload = |
309 | (CTX_TO_MAX_ESIT_PAYLOAD_HI( |
310 | le32_to_cpu(ep_ctx->ep_info)) << 16) | |
311 | CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); |
312 | |
313 | sch_ep->esit = get_esit(ep_ctx); |
314 | sch_ep->num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; |
315 | sch_ep->ep_type = ep_type; |
316 | sch_ep->maxpkt = maxpkt; |
317 | sch_ep->offset = 0; |
318 | sch_ep->burst_mode = 0; |
319 | sch_ep->repeat = 0; |
320 | |
321 | if (sch_ep->speed == USB_SPEED_HIGH) { |
322 | sch_ep->cs_count = 0; |
323 | |
324 | /* |
325 | * usb_20 spec section5.9 |
326 | * a single microframe is enough for HS synchromous endpoints |
327 | * in a interval |
328 | */ |
329 | sch_ep->num_budget_microframes = 1; |
330 | |
331 | /* |
332 | * xHCI spec section6.2.3.4 |
333 | * @max_burst is the number of additional transactions |
334 | * opportunities per microframe |
335 | */ |
336 | sch_ep->pkts = max_burst + 1; |
337 | bwb_table[0] = maxpkt * sch_ep->pkts; |
338 | } else if (sch_ep->speed >= USB_SPEED_SUPER) { |
339 | /* usb3_r1 spec section4.4.7 & 4.4.8 */ |
340 | sch_ep->cs_count = 0; |
341 | sch_ep->burst_mode = 1; |
342 | /* |
343 | * some device's (d)wBytesPerInterval is set as 0, |
344 | * then max_esit_payload is 0, so evaluate esit_pkts from |
345 | * mult and burst |
346 | */ |
347 | esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt); |
348 | if (esit_pkts == 0) |
349 | esit_pkts = (mult + 1) * (max_burst + 1); |
350 | |
351 | if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { |
352 | sch_ep->pkts = esit_pkts; |
353 | sch_ep->num_budget_microframes = 1; |
354 | bwb_table[0] = maxpkt * sch_ep->pkts; |
355 | } |
356 | |
357 | if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { |
358 | |
359 | if (sch_ep->esit == 1) |
360 | sch_ep->pkts = esit_pkts; |
361 | else if (esit_pkts <= sch_ep->esit) |
362 | sch_ep->pkts = 1; |
363 | else |
364 | sch_ep->pkts = roundup_pow_of_two(esit_pkts) |
365 | / sch_ep->esit; |
366 | |
367 | sch_ep->num_budget_microframes = |
368 | DIV_ROUND_UP(esit_pkts, sch_ep->pkts); |
369 | |
370 | sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); |
371 | bw_per_microframe = maxpkt * sch_ep->pkts; |
372 | |
373 | for (i = 0; i < sch_ep->num_budget_microframes - 1; i++) |
374 | bwb_table[i] = bw_per_microframe; |
375 | |
376 | /* last one <= bw_per_microframe */ |
377 | bwb_table[i] = maxpkt * esit_pkts - i * bw_per_microframe; |
378 | } |
379 | } else if (is_fs_or_ls(speed: sch_ep->speed)) { |
380 | sch_ep->pkts = 1; /* at most one packet for each microframe */ |
381 | |
382 | /* |
383 | * @cs_count will be updated to add extra-cs when |
384 | * check TT for INT_OUT_EP, ISOC/INT_IN_EP type |
385 | * @maxpkt <= 1023; |
386 | */ |
387 | sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); |
388 | sch_ep->num_budget_microframes = sch_ep->cs_count; |
389 | |
390 | /* init budget table */ |
391 | if (ep_type == ISOC_OUT_EP) { |
392 | for (i = 0; i < sch_ep->cs_count - 1; i++) |
393 | bwb_table[i] = FS_PAYLOAD_MAX; |
394 | |
395 | bwb_table[i] = maxpkt - i * FS_PAYLOAD_MAX; |
396 | } else if (ep_type == INT_OUT_EP) { |
397 | /* only first one used (maxpkt <= 64), others zero */ |
398 | bwb_table[0] = maxpkt; |
399 | } else { /* INT_IN_EP or ISOC_IN_EP */ |
400 | bwb_table[0] = 0; /* start split */ |
401 | bwb_table[1] = 0; /* idle */ |
402 | /* |
403 | * @cs_count will be updated according to cs position |
404 | * (add 1 or 2 extra-cs), but assume only first |
405 | * @num_budget_microframes elements will be used later, |
406 | * although in fact it does not (extra-cs budget many receive |
407 | * some data for IN ep); |
408 | * @cs_count is 1 for INT_IN_EP (maxpkt <= 64); |
409 | */ |
410 | for (i = 0; i < sch_ep->cs_count - 1; i++) |
411 | bwb_table[i + CS_OFFSET] = FS_PAYLOAD_MAX; |
412 | |
413 | bwb_table[i + CS_OFFSET] = maxpkt - i * FS_PAYLOAD_MAX; |
414 | /* ss + idle */ |
415 | sch_ep->num_budget_microframes += CS_OFFSET; |
416 | } |
417 | } |
418 | } |
419 | |
420 | /* Get maximum bandwidth when we schedule at offset slot. */ |
421 | static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, |
422 | struct mu3h_sch_ep_info *sch_ep, u32 offset) |
423 | { |
424 | u32 max_bw = 0; |
425 | u32 bw; |
426 | int i, j, k; |
427 | |
428 | for (i = 0; i < sch_ep->num_esit; i++) { |
429 | u32 base = offset + i * sch_ep->esit; |
430 | |
431 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
432 | k = XHCI_MTK_BW_INDEX(base + j); |
433 | bw = sch_bw->bus_bw[k] + sch_ep->bw_budget_table[j]; |
434 | if (bw > max_bw) |
435 | max_bw = bw; |
436 | } |
437 | } |
438 | return max_bw; |
439 | } |
440 | |
441 | /* |
442 | * for OUT: get first SS consumed bw; |
443 | * for IN: get first CS consumed bw; |
444 | */ |
445 | static u16 get_fs_bw(struct mu3h_sch_ep_info *sch_ep, int offset) |
446 | { |
447 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
448 | u16 fs_bw; |
449 | |
450 | if (sch_ep->ep_type == ISOC_OUT_EP || sch_ep->ep_type == INT_OUT_EP) |
451 | fs_bw = tt->fs_bus_bw_out[XHCI_MTK_BW_INDEX(offset)]; |
452 | else /* skip ss + idle */ |
453 | fs_bw = tt->fs_bus_bw_in[XHCI_MTK_BW_INDEX(offset + CS_OFFSET)]; |
454 | |
455 | return fs_bw; |
456 | } |
457 | |
458 | static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, |
459 | struct mu3h_sch_ep_info *sch_ep, bool used) |
460 | { |
461 | u32 base; |
462 | int i, j, k; |
463 | |
464 | for (i = 0; i < sch_ep->num_esit; i++) { |
465 | base = sch_ep->offset + i * sch_ep->esit; |
466 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
467 | k = XHCI_MTK_BW_INDEX(base + j); |
468 | if (used) |
469 | sch_bw->bus_bw[k] += sch_ep->bw_budget_table[j]; |
470 | else |
471 | sch_bw->bus_bw[k] -= sch_ep->bw_budget_table[j]; |
472 | } |
473 | } |
474 | } |
475 | |
476 | static int check_ls_budget_microframes(struct mu3h_sch_ep_info *sch_ep, int offset) |
477 | { |
478 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
479 | int i; |
480 | |
481 | if (sch_ep->speed != USB_SPEED_LOW) |
482 | return 0; |
483 | |
484 | if (sch_ep->ep_type == INT_OUT_EP) |
485 | i = XHCI_MTK_BW_INDEX(offset); |
486 | else if (sch_ep->ep_type == INT_IN_EP) |
487 | i = XHCI_MTK_BW_INDEX(offset + CS_OFFSET); /* skip ss + idle */ |
488 | else |
489 | return -EINVAL; |
490 | |
491 | if (tt->ls_bus_bw[i] + sch_ep->maxpkt > LS_PAYLOAD_MAX) |
492 | return -ESCH_BW_OVERFLOW; |
493 | |
494 | return 0; |
495 | } |
496 | |
497 | static int check_fs_budget_microframes(struct mu3h_sch_ep_info *sch_ep, int offset) |
498 | { |
499 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
500 | u32 tmp; |
501 | int i, k; |
502 | |
503 | /* |
504 | * for OUT eps, will transfer exactly assigned length of data, |
505 | * so can't allocate more than 188 bytes; |
506 | * but it's not for IN eps, usually it can't receive full |
507 | * 188 bytes in a uframe, if it not assign full 188 bytes, |
508 | * can add another one; |
509 | */ |
510 | for (i = 0; i < sch_ep->num_budget_microframes; i++) { |
511 | k = XHCI_MTK_BW_INDEX(offset + i); |
512 | if (sch_ep->ep_type == ISOC_OUT_EP || sch_ep->ep_type == INT_OUT_EP) |
513 | tmp = tt->fs_bus_bw_out[k] + sch_ep->bw_budget_table[i]; |
514 | else /* ep_type : ISOC IN / INTR IN */ |
515 | tmp = tt->fs_bus_bw_in[k]; |
516 | |
517 | if (tmp > FS_PAYLOAD_MAX) |
518 | return -ESCH_BW_OVERFLOW; |
519 | } |
520 | |
521 | return 0; |
522 | } |
523 | |
524 | static int check_fs_budget_frames(struct mu3h_sch_ep_info *sch_ep, int offset) |
525 | { |
526 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
527 | u32 head, tail; |
528 | int i, j, k; |
529 | |
530 | /* bugdet scheduled may cross at most two fs frames */ |
531 | j = XHCI_MTK_BW_INDEX(offset) / UFRAMES_PER_FRAME; |
532 | k = XHCI_MTK_BW_INDEX(offset + sch_ep->num_budget_microframes - 1) / UFRAMES_PER_FRAME; |
533 | |
534 | if (j != k) { |
535 | head = tt->fs_frame_bw[j]; |
536 | tail = tt->fs_frame_bw[k]; |
537 | } else { |
538 | head = tt->fs_frame_bw[j]; |
539 | tail = 0; |
540 | } |
541 | |
542 | j = roundup(offset, UFRAMES_PER_FRAME); |
543 | for (i = 0; i < sch_ep->num_budget_microframes; i++) { |
544 | if ((offset + i) < j) |
545 | head += sch_ep->bw_budget_table[i]; |
546 | else |
547 | tail += sch_ep->bw_budget_table[i]; |
548 | } |
549 | |
550 | if (head > FS_BW_BOUNDARY || tail > FS_BW_BOUNDARY) |
551 | return -ESCH_BW_OVERFLOW; |
552 | |
553 | return 0; |
554 | } |
555 | |
556 | static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) |
557 | { |
558 | int i, base; |
559 | int ret = 0; |
560 | |
561 | for (i = 0; i < sch_ep->num_esit; i++) { |
562 | base = offset + i * sch_ep->esit; |
563 | |
564 | ret = check_ls_budget_microframes(sch_ep, offset: base); |
565 | if (ret) |
566 | goto err; |
567 | |
568 | ret = check_fs_budget_microframes(sch_ep, offset: base); |
569 | if (ret) |
570 | goto err; |
571 | |
572 | ret = check_fs_budget_frames(sch_ep, offset: base); |
573 | if (ret) |
574 | goto err; |
575 | } |
576 | |
577 | err: |
578 | return ret; |
579 | } |
580 | |
581 | static int check_ss_and_cs(struct mu3h_sch_ep_info *sch_ep, u32 offset) |
582 | { |
583 | u32 start_ss, last_ss; |
584 | u32 start_cs, last_cs; |
585 | |
586 | start_ss = offset % UFRAMES_PER_FRAME; |
587 | |
588 | if (sch_ep->ep_type == ISOC_OUT_EP) { |
589 | last_ss = start_ss + sch_ep->cs_count - 1; |
590 | |
591 | /* |
592 | * usb_20 spec section11.18: |
593 | * must never schedule Start-Split in Y6 |
594 | */ |
595 | if (!(start_ss == 7 || last_ss < 6)) |
596 | return -ESCH_SS_Y6; |
597 | |
598 | } else { |
599 | /* maxpkt <= 1023, cs <= 6 */ |
600 | u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); |
601 | |
602 | /* |
603 | * usb_20 spec section11.18: |
604 | * must never schedule Start-Split in Y6 |
605 | */ |
606 | if (start_ss == 6) |
607 | return -ESCH_SS_Y6; |
608 | |
609 | /* one uframe for ss + one uframe for idle */ |
610 | start_cs = (start_ss + CS_OFFSET) % UFRAMES_PER_FRAME; |
611 | last_cs = start_cs + cs_count - 1; |
612 | if (last_cs > 7) |
613 | return -ESCH_CS_OVERFLOW; |
614 | |
615 | /* add extra-cs */ |
616 | cs_count += (last_cs == 7) ? 1 : 2; |
617 | if (cs_count > 7) |
618 | cs_count = 7; /* HW limit */ |
619 | |
620 | sch_ep->cs_count = cs_count; |
621 | |
622 | } |
623 | |
624 | return 0; |
625 | } |
626 | |
627 | /* |
628 | * when isoc-out transfers 188 bytes in a uframe, and send isoc/intr's |
629 | * ss token in the uframe, may cause 'bit stuff error' in downstream |
630 | * port; |
631 | * when isoc-out transfer less than 188 bytes in a uframe, shall send |
632 | * isoc-in's ss after isoc-out's ss (but hw can't ensure the sequence, |
633 | * so just avoid overlap). |
634 | */ |
635 | static int check_isoc_ss_overlap(struct mu3h_sch_ep_info *sch_ep, u32 offset) |
636 | { |
637 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
638 | int base; |
639 | int i, j, k; |
640 | |
641 | if (!tt) |
642 | return 0; |
643 | |
644 | for (i = 0; i < sch_ep->num_esit; i++) { |
645 | base = offset + i * sch_ep->esit; |
646 | |
647 | if (sch_ep->ep_type == ISOC_OUT_EP) { |
648 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
649 | k = XHCI_MTK_BW_INDEX(base + j); |
650 | if (tt->in_ss_cnt[k]) |
651 | return -ESCH_SS_OVERLAP; |
652 | } |
653 | } else if (sch_ep->ep_type == ISOC_IN_EP || sch_ep->ep_type == INT_IN_EP) { |
654 | k = XHCI_MTK_BW_INDEX(base); |
655 | /* only check IN's ss */ |
656 | if (tt->fs_bus_bw_out[k]) |
657 | return -ESCH_SS_OVERLAP; |
658 | } |
659 | } |
660 | |
661 | return 0; |
662 | } |
663 | |
664 | static int check_sch_tt_budget(struct mu3h_sch_ep_info *sch_ep, u32 offset) |
665 | { |
666 | int ret; |
667 | |
668 | ret = check_ss_and_cs(sch_ep, offset); |
669 | if (ret) |
670 | return ret; |
671 | |
672 | ret = check_isoc_ss_overlap(sch_ep, offset); |
673 | if (ret) |
674 | return ret; |
675 | |
676 | return check_fs_bus_bw(sch_ep, offset); |
677 | } |
678 | |
679 | /* allocate microframes in the ls/fs frame */ |
680 | static int alloc_sch_portion_of_frame(struct mu3h_sch_ep_info *sch_ep) |
681 | { |
682 | struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info; |
683 | const u32 bw_boundary = get_bw_boundary(speed: sch_ep->speed); |
684 | u32 bw_max, fs_bw_min; |
685 | u32 offset, offset_min; |
686 | u16 fs_bw; |
687 | int frames; |
688 | int i, j; |
689 | int ret; |
690 | |
691 | frames = sch_ep->esit / UFRAMES_PER_FRAME; |
692 | |
693 | for (i = 0; i < UFRAMES_PER_FRAME; i++) { |
694 | fs_bw_min = FS_PAYLOAD_MAX; |
695 | offset_min = XHCI_MTK_MAX_ESIT; |
696 | |
697 | for (j = 0; j < frames; j++) { |
698 | offset = (i + j * UFRAMES_PER_FRAME) % sch_ep->esit; |
699 | |
700 | ret = check_sch_tt_budget(sch_ep, offset); |
701 | if (ret) |
702 | continue; |
703 | |
704 | /* check hs bw domain */ |
705 | bw_max = get_max_bw(sch_bw, sch_ep, offset); |
706 | if (bw_max > bw_boundary) { |
707 | ret = -ESCH_BW_OVERFLOW; |
708 | continue; |
709 | } |
710 | |
711 | /* use best-fit between frames */ |
712 | fs_bw = get_fs_bw(sch_ep, offset); |
713 | if (fs_bw < fs_bw_min) { |
714 | fs_bw_min = fs_bw; |
715 | offset_min = offset; |
716 | } |
717 | |
718 | if (!fs_bw_min) |
719 | break; |
720 | } |
721 | |
722 | /* use first-fit between microframes in a frame */ |
723 | if (offset_min < XHCI_MTK_MAX_ESIT) |
724 | break; |
725 | } |
726 | |
727 | if (offset_min == XHCI_MTK_MAX_ESIT) |
728 | return -ESCH_BW_OVERFLOW; |
729 | |
730 | sch_ep->offset = offset_min; |
731 | |
732 | return 0; |
733 | } |
734 | |
735 | static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) |
736 | { |
737 | struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
738 | u16 *fs_bus_bw; |
739 | u32 base; |
740 | int i, j, k, f; |
741 | |
742 | if (sch_ep->ep_type == ISOC_OUT_EP || sch_ep->ep_type == INT_OUT_EP) |
743 | fs_bus_bw = tt->fs_bus_bw_out; |
744 | else |
745 | fs_bus_bw = tt->fs_bus_bw_in; |
746 | |
747 | for (i = 0; i < sch_ep->num_esit; i++) { |
748 | base = sch_ep->offset + i * sch_ep->esit; |
749 | |
750 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
751 | k = XHCI_MTK_BW_INDEX(base + j); |
752 | f = k / UFRAMES_PER_FRAME; |
753 | if (used) { |
754 | if (sch_ep->speed == USB_SPEED_LOW) |
755 | tt->ls_bus_bw[k] += (u8)sch_ep->bw_budget_table[j]; |
756 | |
757 | fs_bus_bw[k] += (u16)sch_ep->bw_budget_table[j]; |
758 | tt->fs_frame_bw[f] += (u16)sch_ep->bw_budget_table[j]; |
759 | } else { |
760 | if (sch_ep->speed == USB_SPEED_LOW) |
761 | tt->ls_bus_bw[k] -= (u8)sch_ep->bw_budget_table[j]; |
762 | |
763 | fs_bus_bw[k] -= (u16)sch_ep->bw_budget_table[j]; |
764 | tt->fs_frame_bw[f] -= (u16)sch_ep->bw_budget_table[j]; |
765 | } |
766 | } |
767 | |
768 | if (sch_ep->ep_type == ISOC_IN_EP || sch_ep->ep_type == INT_IN_EP) { |
769 | k = XHCI_MTK_BW_INDEX(base); |
770 | if (used) |
771 | tt->in_ss_cnt[k]++; |
772 | else |
773 | tt->in_ss_cnt[k]--; |
774 | } |
775 | } |
776 | |
777 | if (used) |
778 | list_add_tail(new: &sch_ep->tt_endpoint, head: &tt->ep_list); |
779 | else |
780 | list_del(entry: &sch_ep->tt_endpoint); |
781 | } |
782 | |
783 | static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw, |
784 | struct mu3h_sch_ep_info *sch_ep, bool loaded) |
785 | { |
786 | if (sch_ep->sch_tt) |
787 | update_sch_tt(sch_ep, used: loaded); |
788 | |
789 | /* update bus bandwidth info */ |
790 | update_bus_bw(sch_bw, sch_ep, used: loaded); |
791 | sch_ep->allocated = loaded; |
792 | |
793 | return 0; |
794 | } |
795 | |
796 | /* allocate microframes for hs/ss/ssp */ |
797 | static int alloc_sch_microframes(struct mu3h_sch_ep_info *sch_ep) |
798 | { |
799 | struct mu3h_sch_bw_info *sch_bw = sch_ep->bw_info; |
800 | const u32 bw_boundary = get_bw_boundary(speed: sch_ep->speed); |
801 | u32 offset; |
802 | u32 worst_bw; |
803 | u32 min_bw = ~0; |
804 | int min_index = -1; |
805 | |
806 | /* |
807 | * Search through all possible schedule microframes. |
808 | * and find a microframe where its worst bandwidth is minimum. |
809 | */ |
810 | for (offset = 0; offset < sch_ep->esit; offset++) { |
811 | |
812 | worst_bw = get_max_bw(sch_bw, sch_ep, offset); |
813 | if (worst_bw > bw_boundary) |
814 | continue; |
815 | |
816 | if (min_bw > worst_bw) { |
817 | min_bw = worst_bw; |
818 | min_index = offset; |
819 | } |
820 | } |
821 | |
822 | if (min_index < 0) |
823 | return -ESCH_BW_OVERFLOW; |
824 | |
825 | sch_ep->offset = min_index; |
826 | |
827 | return 0; |
828 | } |
829 | |
830 | static int check_sch_bw(struct mu3h_sch_ep_info *sch_ep) |
831 | { |
832 | int ret; |
833 | |
834 | if (sch_ep->sch_tt) |
835 | ret = alloc_sch_portion_of_frame(sch_ep); |
836 | else |
837 | ret = alloc_sch_microframes(sch_ep); |
838 | |
839 | if (ret) |
840 | return ret; |
841 | |
842 | return load_ep_bw(sch_bw: sch_ep->bw_info, sch_ep, loaded: true); |
843 | } |
844 | |
845 | static void destroy_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, |
846 | struct mu3h_sch_ep_info *sch_ep) |
847 | { |
848 | /* only release ep bw check passed by check_sch_bw() */ |
849 | if (sch_ep->allocated) |
850 | load_ep_bw(sch_bw: sch_ep->bw_info, sch_ep, loaded: false); |
851 | |
852 | if (sch_ep->sch_tt) |
853 | drop_tt(udev); |
854 | |
855 | list_del(entry: &sch_ep->endpoint); |
856 | hlist_del(n: &sch_ep->hentry); |
857 | kfree(objp: sch_ep); |
858 | } |
859 | |
860 | static bool need_bw_sch(struct usb_device *udev, |
861 | struct usb_host_endpoint *ep) |
862 | { |
863 | bool has_tt = udev->tt && udev->tt->hub->parent; |
864 | |
865 | /* only for periodic endpoints */ |
866 | if (usb_endpoint_xfer_control(epd: &ep->desc) |
867 | || usb_endpoint_xfer_bulk(epd: &ep->desc)) |
868 | return false; |
869 | |
870 | /* |
871 | * for LS & FS periodic endpoints which its device is not behind |
872 | * a TT are also ignored, root-hub will schedule them directly, |
873 | * but need set @bpkts field of endpoint context to 1. |
874 | */ |
875 | if (is_fs_or_ls(speed: udev->speed) && !has_tt) |
876 | return false; |
877 | |
878 | /* skip endpoint with zero maxpkt */ |
879 | if (usb_endpoint_maxp(epd: &ep->desc) == 0) |
880 | return false; |
881 | |
882 | return true; |
883 | } |
884 | |
885 | int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk) |
886 | { |
887 | struct xhci_hcd *xhci = hcd_to_xhci(hcd: mtk->hcd); |
888 | struct mu3h_sch_bw_info *sch_array; |
889 | int num_usb_bus; |
890 | |
891 | /* ss IN and OUT are separated */ |
892 | num_usb_bus = xhci->usb3_rhub.num_ports * 2 + xhci->usb2_rhub.num_ports; |
893 | |
894 | sch_array = kcalloc(n: num_usb_bus, size: sizeof(*sch_array), GFP_KERNEL); |
895 | if (sch_array == NULL) |
896 | return -ENOMEM; |
897 | |
898 | mtk->sch_array = sch_array; |
899 | |
900 | INIT_LIST_HEAD(list: &mtk->bw_ep_chk_list); |
901 | hash_init(mtk->sch_ep_hash); |
902 | |
903 | return 0; |
904 | } |
905 | |
906 | void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk) |
907 | { |
908 | kfree(objp: mtk->sch_array); |
909 | } |
910 | |
911 | static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
912 | struct usb_host_endpoint *ep) |
913 | { |
914 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
915 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
916 | struct xhci_ep_ctx *ep_ctx; |
917 | struct xhci_virt_device *virt_dev; |
918 | struct mu3h_sch_ep_info *sch_ep; |
919 | unsigned int ep_index; |
920 | |
921 | virt_dev = xhci->devs[udev->slot_id]; |
922 | ep_index = xhci_get_endpoint_index(desc: &ep->desc); |
923 | ep_ctx = xhci_get_ep_ctx(xhci, ctx: virt_dev->in_ctx, ep_index); |
924 | |
925 | if (!need_bw_sch(udev, ep)) { |
926 | /* |
927 | * set @bpkts to 1 if it is LS or FS periodic endpoint, and its |
928 | * device does not connected through an external HS hub |
929 | */ |
930 | if (usb_endpoint_xfer_int(epd: &ep->desc) |
931 | || usb_endpoint_xfer_isoc(epd: &ep->desc)) |
932 | ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(1)); |
933 | |
934 | return 0; |
935 | } |
936 | |
937 | xhci_dbg(xhci, "%s %s\n" , __func__, decode_ep(ep, udev->speed)); |
938 | |
939 | sch_ep = create_sch_ep(mtk, udev, ep, ep_ctx); |
940 | if (IS_ERR_OR_NULL(ptr: sch_ep)) |
941 | return -ENOMEM; |
942 | |
943 | setup_sch_info(ep_ctx, sch_ep); |
944 | |
945 | list_add_tail(new: &sch_ep->endpoint, head: &mtk->bw_ep_chk_list); |
946 | hash_add(mtk->sch_ep_hash, &sch_ep->hentry, (unsigned long)ep); |
947 | |
948 | return 0; |
949 | } |
950 | |
951 | static void drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
952 | struct usb_host_endpoint *ep) |
953 | { |
954 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
955 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
956 | struct mu3h_sch_ep_info *sch_ep; |
957 | struct hlist_node *hn; |
958 | |
959 | if (!need_bw_sch(udev, ep)) |
960 | return; |
961 | |
962 | xhci_dbg(xhci, "%s %s\n" , __func__, decode_ep(ep, udev->speed)); |
963 | |
964 | hash_for_each_possible_safe(mtk->sch_ep_hash, sch_ep, |
965 | hn, hentry, (unsigned long)ep) { |
966 | if (sch_ep->ep == ep) { |
967 | destroy_sch_ep(mtk, udev, sch_ep); |
968 | break; |
969 | } |
970 | } |
971 | } |
972 | |
973 | int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) |
974 | { |
975 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
976 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
977 | struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; |
978 | struct mu3h_sch_ep_info *sch_ep; |
979 | int ret; |
980 | |
981 | xhci_dbg(xhci, "%s() udev %s\n" , __func__, dev_name(&udev->dev)); |
982 | |
983 | list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) { |
984 | struct xhci_ep_ctx *ep_ctx; |
985 | struct usb_host_endpoint *ep = sch_ep->ep; |
986 | unsigned int ep_index = xhci_get_endpoint_index(desc: &ep->desc); |
987 | |
988 | ret = check_sch_bw(sch_ep); |
989 | if (ret) { |
990 | xhci_err(xhci, "Not enough bandwidth! (%s)\n" , |
991 | sch_error_string(-ret)); |
992 | return -ENOSPC; |
993 | } |
994 | |
995 | ep_ctx = xhci_get_ep_ctx(xhci, ctx: virt_dev->in_ctx, ep_index); |
996 | ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(sch_ep->pkts) |
997 | | EP_BCSCOUNT(sch_ep->cs_count) |
998 | | EP_BBM(sch_ep->burst_mode)); |
999 | ep_ctx->reserved[1] = cpu_to_le32(EP_BOFFSET(sch_ep->offset) |
1000 | | EP_BREPEAT(sch_ep->repeat)); |
1001 | |
1002 | xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n" , |
1003 | sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode, |
1004 | sch_ep->offset, sch_ep->repeat); |
1005 | } |
1006 | |
1007 | ret = xhci_check_bandwidth(hcd, udev); |
1008 | if (!ret) |
1009 | list_del_init(entry: &mtk->bw_ep_chk_list); |
1010 | |
1011 | return ret; |
1012 | } |
1013 | |
1014 | void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) |
1015 | { |
1016 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
1017 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
1018 | struct mu3h_sch_ep_info *sch_ep, *tmp; |
1019 | |
1020 | xhci_dbg(xhci, "%s() udev %s\n" , __func__, dev_name(&udev->dev)); |
1021 | |
1022 | list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) |
1023 | destroy_sch_ep(mtk, udev, sch_ep); |
1024 | |
1025 | xhci_reset_bandwidth(hcd, udev); |
1026 | } |
1027 | |
1028 | int xhci_mtk_add_ep(struct usb_hcd *hcd, struct usb_device *udev, |
1029 | struct usb_host_endpoint *ep) |
1030 | { |
1031 | int ret; |
1032 | |
1033 | ret = xhci_add_endpoint(hcd, udev, ep); |
1034 | if (ret) |
1035 | return ret; |
1036 | |
1037 | if (ep->hcpriv) |
1038 | ret = add_ep_quirk(hcd, udev, ep); |
1039 | |
1040 | return ret; |
1041 | } |
1042 | |
1043 | int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, |
1044 | struct usb_host_endpoint *ep) |
1045 | { |
1046 | int ret; |
1047 | |
1048 | ret = xhci_drop_endpoint(hcd, udev, ep); |
1049 | if (ret) |
1050 | return ret; |
1051 | |
1052 | /* needn't check @ep->hcpriv, xhci_endpoint_disable set it NULL */ |
1053 | drop_ep_quirk(hcd, udev, ep); |
1054 | |
1055 | return 0; |
1056 | } |
1057 | |