.. | .. |
---|
13 | 13 | #include "xhci.h" |
---|
14 | 14 | #include "xhci-mtk.h" |
---|
15 | 15 | |
---|
| 16 | +#define SSP_BW_BOUNDARY 130000 |
---|
16 | 17 | #define SS_BW_BOUNDARY 51000 |
---|
17 | 18 | /* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */ |
---|
18 | 19 | #define HS_BW_BOUNDARY 6144 |
---|
19 | 20 | /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ |
---|
20 | 21 | #define FS_PAYLOAD_MAX 188 |
---|
| 22 | +/* |
---|
| 23 | + * max number of microframes for split transfer, |
---|
| 24 | + * for fs isoc in : 1 ss + 1 idle + 7 cs |
---|
| 25 | + */ |
---|
| 26 | +#define TT_MICROFRAMES_MAX 9 |
---|
| 27 | + |
---|
| 28 | +#define DBG_BUF_EN 64 |
---|
| 29 | + |
---|
| 30 | +/* schedule error type */ |
---|
| 31 | +#define ESCH_SS_Y6 1001 |
---|
| 32 | +#define ESCH_SS_OVERLAP 1002 |
---|
| 33 | +#define ESCH_CS_OVERFLOW 1003 |
---|
| 34 | +#define ESCH_BW_OVERFLOW 1004 |
---|
| 35 | +#define ESCH_FIXME 1005 |
---|
21 | 36 | |
---|
22 | 37 | /* mtk scheduler bitmasks */ |
---|
23 | | -#define EP_BPKTS(p) ((p) & 0x3f) |
---|
| 38 | +#define EP_BPKTS(p) ((p) & 0x7f) |
---|
24 | 39 | #define EP_BCSCOUNT(p) (((p) & 0x7) << 8) |
---|
25 | 40 | #define EP_BBM(p) ((p) << 11) |
---|
26 | 41 | #define EP_BOFFSET(p) ((p) & 0x3fff) |
---|
27 | 42 | #define EP_BREPEAT(p) (((p) & 0x7fff) << 16) |
---|
| 43 | + |
---|
| 44 | +static char *sch_error_string(int err_num) |
---|
| 45 | +{ |
---|
| 46 | + switch (err_num) { |
---|
| 47 | + case ESCH_SS_Y6: |
---|
| 48 | + return "Can't schedule Start-Split in Y6"; |
---|
| 49 | + case ESCH_SS_OVERLAP: |
---|
| 50 | + return "Can't find a suitable Start-Split location"; |
---|
| 51 | + case ESCH_CS_OVERFLOW: |
---|
| 52 | + return "The last Complete-Split is greater than 7"; |
---|
| 53 | + case ESCH_BW_OVERFLOW: |
---|
| 54 | + return "Bandwidth exceeds the maximum limit"; |
---|
| 55 | + case ESCH_FIXME: |
---|
| 56 | + return "FIXME, to be resolved"; |
---|
| 57 | + default: |
---|
| 58 | + return "Unknown"; |
---|
| 59 | + } |
---|
| 60 | +} |
---|
28 | 61 | |
---|
29 | 62 | static int is_fs_or_ls(enum usb_device_speed speed) |
---|
30 | 63 | { |
---|
31 | 64 | return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW; |
---|
32 | 65 | } |
---|
33 | 66 | |
---|
| 67 | +static const char * |
---|
| 68 | +decode_ep(struct usb_host_endpoint *ep, enum usb_device_speed speed) |
---|
| 69 | +{ |
---|
| 70 | + static char buf[DBG_BUF_EN]; |
---|
| 71 | + struct usb_endpoint_descriptor *epd = &ep->desc; |
---|
| 72 | + unsigned int interval; |
---|
| 73 | + const char *unit; |
---|
| 74 | + |
---|
| 75 | + interval = usb_decode_interval(epd, speed); |
---|
| 76 | + if (interval % 1000) { |
---|
| 77 | + unit = "us"; |
---|
| 78 | + } else { |
---|
| 79 | + unit = "ms"; |
---|
| 80 | + interval /= 1000; |
---|
| 81 | + } |
---|
| 82 | + |
---|
| 83 | + snprintf(buf, DBG_BUF_EN, "%s ep%d%s %s, mpkt:%d, interval:%d/%d%s\n", |
---|
| 84 | + usb_speed_string(speed), usb_endpoint_num(epd), |
---|
| 85 | + usb_endpoint_dir_in(epd) ? "in" : "out", |
---|
| 86 | + usb_ep_type_string(usb_endpoint_type(epd)), |
---|
| 87 | + usb_endpoint_maxp(epd), epd->bInterval, interval, unit); |
---|
| 88 | + |
---|
| 89 | + return buf; |
---|
| 90 | +} |
---|
| 91 | + |
---|
| 92 | +static u32 get_bw_boundary(enum usb_device_speed speed) |
---|
| 93 | +{ |
---|
| 94 | + u32 boundary; |
---|
| 95 | + |
---|
| 96 | + switch (speed) { |
---|
| 97 | + case USB_SPEED_SUPER_PLUS: |
---|
| 98 | + boundary = SSP_BW_BOUNDARY; |
---|
| 99 | + break; |
---|
| 100 | + case USB_SPEED_SUPER: |
---|
| 101 | + boundary = SS_BW_BOUNDARY; |
---|
| 102 | + break; |
---|
| 103 | + default: |
---|
| 104 | + boundary = HS_BW_BOUNDARY; |
---|
| 105 | + break; |
---|
| 106 | + } |
---|
| 107 | + |
---|
| 108 | + return boundary; |
---|
| 109 | +} |
---|
| 110 | + |
---|
34 | 111 | /* |
---|
35 | | -* get the index of bandwidth domains array which @ep belongs to. |
---|
| 112 | +* get the bandwidth domain which @ep belongs to. |
---|
36 | 113 | * |
---|
37 | 114 | * the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk, |
---|
38 | 115 | * each HS root port is treated as a single bandwidth domain, |
---|
.. | .. |
---|
43 | 120 | * so the bandwidth domain array is organized as follow for simplification: |
---|
44 | 121 | * SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY |
---|
45 | 122 | */ |
---|
46 | | -static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev, |
---|
47 | | - struct usb_host_endpoint *ep) |
---|
| 123 | +static struct mu3h_sch_bw_info * |
---|
| 124 | +get_bw_info(struct xhci_hcd_mtk *mtk, struct usb_device *udev, |
---|
| 125 | + struct usb_host_endpoint *ep) |
---|
48 | 126 | { |
---|
| 127 | + struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); |
---|
49 | 128 | struct xhci_virt_device *virt_dev; |
---|
50 | 129 | int bw_index; |
---|
51 | 130 | |
---|
52 | 131 | virt_dev = xhci->devs[udev->slot_id]; |
---|
53 | 132 | |
---|
54 | | - if (udev->speed == USB_SPEED_SUPER) { |
---|
| 133 | + if (udev->speed >= USB_SPEED_SUPER) { |
---|
55 | 134 | if (usb_endpoint_dir_out(&ep->desc)) |
---|
56 | 135 | bw_index = (virt_dev->real_port - 1) * 2; |
---|
57 | 136 | else |
---|
.. | .. |
---|
61 | 140 | bw_index = virt_dev->real_port + xhci->usb3_rhub.num_ports - 1; |
---|
62 | 141 | } |
---|
63 | 142 | |
---|
64 | | - return bw_index; |
---|
| 143 | + return &mtk->sch_array[bw_index]; |
---|
65 | 144 | } |
---|
66 | 145 | |
---|
67 | | -static void setup_sch_info(struct usb_device *udev, |
---|
68 | | - struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep) |
---|
| 146 | +static u32 get_esit(struct xhci_ep_ctx *ep_ctx) |
---|
| 147 | +{ |
---|
| 148 | + u32 esit; |
---|
| 149 | + |
---|
| 150 | + esit = 1 << CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); |
---|
| 151 | + if (esit > XHCI_MTK_MAX_ESIT) |
---|
| 152 | + esit = XHCI_MTK_MAX_ESIT; |
---|
| 153 | + |
---|
| 154 | + return esit; |
---|
| 155 | +} |
---|
| 156 | + |
---|
| 157 | +static struct mu3h_sch_tt *find_tt(struct usb_device *udev) |
---|
| 158 | +{ |
---|
| 159 | + struct usb_tt *utt = udev->tt; |
---|
| 160 | + struct mu3h_sch_tt *tt, **tt_index, **ptt; |
---|
| 161 | + bool allocated_index = false; |
---|
| 162 | + |
---|
| 163 | + if (!utt) |
---|
| 164 | + return NULL; /* Not below a TT */ |
---|
| 165 | + |
---|
| 166 | + /* |
---|
| 167 | + * Find/create our data structure. |
---|
| 168 | + * For hubs with a single TT, we get it directly. |
---|
| 169 | + * For hubs with multiple TTs, there's an extra level of pointers. |
---|
| 170 | + */ |
---|
| 171 | + tt_index = NULL; |
---|
| 172 | + if (utt->multi) { |
---|
| 173 | + tt_index = utt->hcpriv; |
---|
| 174 | + if (!tt_index) { /* Create the index array */ |
---|
| 175 | + tt_index = kcalloc(utt->hub->maxchild, |
---|
| 176 | + sizeof(*tt_index), GFP_KERNEL); |
---|
| 177 | + if (!tt_index) |
---|
| 178 | + return ERR_PTR(-ENOMEM); |
---|
| 179 | + utt->hcpriv = tt_index; |
---|
| 180 | + allocated_index = true; |
---|
| 181 | + } |
---|
| 182 | + ptt = &tt_index[udev->ttport - 1]; |
---|
| 183 | + } else { |
---|
| 184 | + ptt = (struct mu3h_sch_tt **) &utt->hcpriv; |
---|
| 185 | + } |
---|
| 186 | + |
---|
| 187 | + tt = *ptt; |
---|
| 188 | + if (!tt) { /* Create the mu3h_sch_tt */ |
---|
| 189 | + tt = kzalloc(sizeof(*tt), GFP_KERNEL); |
---|
| 190 | + if (!tt) { |
---|
| 191 | + if (allocated_index) { |
---|
| 192 | + utt->hcpriv = NULL; |
---|
| 193 | + kfree(tt_index); |
---|
| 194 | + } |
---|
| 195 | + return ERR_PTR(-ENOMEM); |
---|
| 196 | + } |
---|
| 197 | + INIT_LIST_HEAD(&tt->ep_list); |
---|
| 198 | + *ptt = tt; |
---|
| 199 | + } |
---|
| 200 | + |
---|
| 201 | + return tt; |
---|
| 202 | +} |
---|
| 203 | + |
---|
| 204 | +/* Release the TT above udev, if it's not in use */ |
---|
| 205 | +static void drop_tt(struct usb_device *udev) |
---|
| 206 | +{ |
---|
| 207 | + struct usb_tt *utt = udev->tt; |
---|
| 208 | + struct mu3h_sch_tt *tt, **tt_index, **ptt; |
---|
| 209 | + int i, cnt; |
---|
| 210 | + |
---|
| 211 | + if (!utt || !utt->hcpriv) |
---|
| 212 | + return; /* Not below a TT, or never allocated */ |
---|
| 213 | + |
---|
| 214 | + cnt = 0; |
---|
| 215 | + if (utt->multi) { |
---|
| 216 | + tt_index = utt->hcpriv; |
---|
| 217 | + ptt = &tt_index[udev->ttport - 1]; |
---|
| 218 | + /* How many entries are left in tt_index? */ |
---|
| 219 | + for (i = 0; i < utt->hub->maxchild; ++i) |
---|
| 220 | + cnt += !!tt_index[i]; |
---|
| 221 | + } else { |
---|
| 222 | + tt_index = NULL; |
---|
| 223 | + ptt = (struct mu3h_sch_tt **)&utt->hcpriv; |
---|
| 224 | + } |
---|
| 225 | + |
---|
| 226 | + tt = *ptt; |
---|
| 227 | + if (!tt || !list_empty(&tt->ep_list)) |
---|
| 228 | + return; /* never allocated , or still in use*/ |
---|
| 229 | + |
---|
| 230 | + *ptt = NULL; |
---|
| 231 | + kfree(tt); |
---|
| 232 | + |
---|
| 233 | + if (cnt == 1) { |
---|
| 234 | + utt->hcpriv = NULL; |
---|
| 235 | + kfree(tt_index); |
---|
| 236 | + } |
---|
| 237 | +} |
---|
| 238 | + |
---|
| 239 | +static struct mu3h_sch_ep_info *create_sch_ep(struct usb_device *udev, |
---|
| 240 | + struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) |
---|
| 241 | +{ |
---|
| 242 | + struct mu3h_sch_ep_info *sch_ep; |
---|
| 243 | + struct mu3h_sch_tt *tt = NULL; |
---|
| 244 | + u32 len_bw_budget_table; |
---|
| 245 | + size_t mem_size; |
---|
| 246 | + |
---|
| 247 | + if (is_fs_or_ls(udev->speed)) |
---|
| 248 | + len_bw_budget_table = TT_MICROFRAMES_MAX; |
---|
| 249 | + else if ((udev->speed >= USB_SPEED_SUPER) |
---|
| 250 | + && usb_endpoint_xfer_isoc(&ep->desc)) |
---|
| 251 | + len_bw_budget_table = get_esit(ep_ctx); |
---|
| 252 | + else |
---|
| 253 | + len_bw_budget_table = 1; |
---|
| 254 | + |
---|
| 255 | + mem_size = sizeof(struct mu3h_sch_ep_info) + |
---|
| 256 | + len_bw_budget_table * sizeof(u32); |
---|
| 257 | + sch_ep = kzalloc(mem_size, GFP_KERNEL); |
---|
| 258 | + if (!sch_ep) |
---|
| 259 | + return ERR_PTR(-ENOMEM); |
---|
| 260 | + |
---|
| 261 | + if (is_fs_or_ls(udev->speed)) { |
---|
| 262 | + tt = find_tt(udev); |
---|
| 263 | + if (IS_ERR(tt)) { |
---|
| 264 | + kfree(sch_ep); |
---|
| 265 | + return ERR_PTR(-ENOMEM); |
---|
| 266 | + } |
---|
| 267 | + } |
---|
| 268 | + |
---|
| 269 | + sch_ep->sch_tt = tt; |
---|
| 270 | + sch_ep->ep = ep; |
---|
| 271 | + sch_ep->speed = udev->speed; |
---|
| 272 | + INIT_LIST_HEAD(&sch_ep->endpoint); |
---|
| 273 | + INIT_LIST_HEAD(&sch_ep->tt_endpoint); |
---|
| 274 | + |
---|
| 275 | + return sch_ep; |
---|
| 276 | +} |
---|
| 277 | + |
---|
| 278 | +static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, |
---|
| 279 | + struct mu3h_sch_ep_info *sch_ep) |
---|
69 | 280 | { |
---|
70 | 281 | u32 ep_type; |
---|
71 | | - u32 ep_interval; |
---|
72 | | - u32 max_packet_size; |
---|
| 282 | + u32 maxpkt; |
---|
73 | 283 | u32 max_burst; |
---|
74 | 284 | u32 mult; |
---|
75 | 285 | u32 esit_pkts; |
---|
| 286 | + u32 max_esit_payload; |
---|
| 287 | + u32 *bwb_table = sch_ep->bw_budget_table; |
---|
| 288 | + int i; |
---|
76 | 289 | |
---|
77 | 290 | ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); |
---|
78 | | - ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info)); |
---|
79 | | - max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); |
---|
| 291 | + maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); |
---|
80 | 292 | max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2)); |
---|
81 | 293 | mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info)); |
---|
| 294 | + max_esit_payload = |
---|
| 295 | + (CTX_TO_MAX_ESIT_PAYLOAD_HI( |
---|
| 296 | + le32_to_cpu(ep_ctx->ep_info)) << 16) | |
---|
| 297 | + CTX_TO_MAX_ESIT_PAYLOAD(le32_to_cpu(ep_ctx->tx_info)); |
---|
82 | 298 | |
---|
83 | | - sch_ep->esit = 1 << ep_interval; |
---|
| 299 | + sch_ep->esit = get_esit(ep_ctx); |
---|
| 300 | + sch_ep->ep_type = ep_type; |
---|
| 301 | + sch_ep->maxpkt = maxpkt; |
---|
84 | 302 | sch_ep->offset = 0; |
---|
85 | 303 | sch_ep->burst_mode = 0; |
---|
| 304 | + sch_ep->repeat = 0; |
---|
86 | 305 | |
---|
87 | | - if (udev->speed == USB_SPEED_HIGH) { |
---|
| 306 | + if (sch_ep->speed == USB_SPEED_HIGH) { |
---|
88 | 307 | sch_ep->cs_count = 0; |
---|
89 | 308 | |
---|
90 | 309 | /* |
---|
.. | .. |
---|
93 | 312 | * in a interval |
---|
94 | 313 | */ |
---|
95 | 314 | sch_ep->num_budget_microframes = 1; |
---|
96 | | - sch_ep->repeat = 0; |
---|
97 | 315 | |
---|
98 | 316 | /* |
---|
99 | 317 | * xHCI spec section6.2.3.4 |
---|
.. | .. |
---|
101 | 319 | * opportunities per microframe |
---|
102 | 320 | */ |
---|
103 | 321 | sch_ep->pkts = max_burst + 1; |
---|
104 | | - sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; |
---|
105 | | - } else if (udev->speed == USB_SPEED_SUPER) { |
---|
| 322 | + sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; |
---|
| 323 | + bwb_table[0] = sch_ep->bw_cost_per_microframe; |
---|
| 324 | + } else if (sch_ep->speed >= USB_SPEED_SUPER) { |
---|
106 | 325 | /* usb3_r1 spec section4.4.7 & 4.4.8 */ |
---|
107 | 326 | sch_ep->cs_count = 0; |
---|
108 | | - esit_pkts = (mult + 1) * (max_burst + 1); |
---|
| 327 | + sch_ep->burst_mode = 1; |
---|
| 328 | + /* |
---|
| 329 | + * some device's (d)wBytesPerInterval is set as 0, |
---|
| 330 | + * then max_esit_payload is 0, so evaluate esit_pkts from |
---|
| 331 | + * mult and burst |
---|
| 332 | + */ |
---|
| 333 | + esit_pkts = DIV_ROUND_UP(max_esit_payload, maxpkt); |
---|
| 334 | + if (esit_pkts == 0) |
---|
| 335 | + esit_pkts = (mult + 1) * (max_burst + 1); |
---|
| 336 | + |
---|
109 | 337 | if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { |
---|
110 | 338 | sch_ep->pkts = esit_pkts; |
---|
111 | 339 | sch_ep->num_budget_microframes = 1; |
---|
112 | | - sch_ep->repeat = 0; |
---|
| 340 | + bwb_table[0] = maxpkt * sch_ep->pkts; |
---|
113 | 341 | } |
---|
114 | 342 | |
---|
115 | 343 | if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { |
---|
| 344 | + |
---|
116 | 345 | if (sch_ep->esit == 1) |
---|
117 | 346 | sch_ep->pkts = esit_pkts; |
---|
118 | 347 | else if (esit_pkts <= sch_ep->esit) |
---|
.. | .. |
---|
124 | 353 | sch_ep->num_budget_microframes = |
---|
125 | 354 | DIV_ROUND_UP(esit_pkts, sch_ep->pkts); |
---|
126 | 355 | |
---|
127 | | - if (sch_ep->num_budget_microframes > 1) |
---|
128 | | - sch_ep->repeat = 1; |
---|
129 | | - else |
---|
130 | | - sch_ep->repeat = 0; |
---|
| 356 | + sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); |
---|
| 357 | + sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; |
---|
| 358 | + |
---|
| 359 | + for (i = 0; i < sch_ep->num_budget_microframes - 1; i++) |
---|
| 360 | + bwb_table[i] = sch_ep->bw_cost_per_microframe; |
---|
| 361 | + |
---|
| 362 | + /* last one <= bw_cost_per_microframe */ |
---|
| 363 | + bwb_table[i] = maxpkt * esit_pkts |
---|
| 364 | + - i * sch_ep->bw_cost_per_microframe; |
---|
131 | 365 | } |
---|
132 | | - sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts; |
---|
133 | | - } else if (is_fs_or_ls(udev->speed)) { |
---|
| 366 | + } else if (is_fs_or_ls(sch_ep->speed)) { |
---|
| 367 | + sch_ep->pkts = 1; /* at most one packet for each microframe */ |
---|
134 | 368 | |
---|
135 | 369 | /* |
---|
136 | | - * usb_20 spec section11.18.4 |
---|
137 | | - * assume worst cases |
---|
| 370 | + * num_budget_microframes and cs_count will be updated when |
---|
| 371 | + * check TT for INT_OUT_EP, ISOC/INT_IN_EP type |
---|
138 | 372 | */ |
---|
139 | | - sch_ep->repeat = 0; |
---|
140 | | - sch_ep->pkts = 1; /* at most one packet for each microframe */ |
---|
141 | | - if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { |
---|
142 | | - sch_ep->cs_count = 3; /* at most need 3 CS*/ |
---|
143 | | - /* one for SS and one for budgeted transaction */ |
---|
144 | | - sch_ep->num_budget_microframes = sch_ep->cs_count + 2; |
---|
145 | | - sch_ep->bw_cost_per_microframe = max_packet_size; |
---|
146 | | - } |
---|
147 | | - if (ep_type == ISOC_OUT_EP) { |
---|
| 373 | + sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); |
---|
| 374 | + sch_ep->num_budget_microframes = sch_ep->cs_count; |
---|
| 375 | + sch_ep->bw_cost_per_microframe = |
---|
| 376 | + (maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX; |
---|
148 | 377 | |
---|
| 378 | + /* init budget table */ |
---|
| 379 | + if (ep_type == ISOC_OUT_EP) { |
---|
| 380 | + for (i = 0; i < sch_ep->num_budget_microframes; i++) |
---|
| 381 | + bwb_table[i] = sch_ep->bw_cost_per_microframe; |
---|
| 382 | + } else if (ep_type == INT_OUT_EP) { |
---|
| 383 | + /* only first one consumes bandwidth, others as zero */ |
---|
| 384 | + bwb_table[0] = sch_ep->bw_cost_per_microframe; |
---|
| 385 | + } else { /* INT_IN_EP or ISOC_IN_EP */ |
---|
| 386 | + bwb_table[0] = 0; /* start split */ |
---|
| 387 | + bwb_table[1] = 0; /* idle */ |
---|
149 | 388 | /* |
---|
150 | | - * the best case FS budget assumes that 188 FS bytes |
---|
151 | | - * occur in each microframe |
---|
| 389 | + * due to cs_count will be updated according to cs |
---|
| 390 | + * position, assign all remainder budget array |
---|
| 391 | + * elements as @bw_cost_per_microframe, but only first |
---|
| 392 | + * @num_budget_microframes elements will be used later |
---|
152 | 393 | */ |
---|
153 | | - sch_ep->num_budget_microframes = DIV_ROUND_UP( |
---|
154 | | - max_packet_size, FS_PAYLOAD_MAX); |
---|
155 | | - sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; |
---|
156 | | - sch_ep->cs_count = sch_ep->num_budget_microframes; |
---|
157 | | - } |
---|
158 | | - if (ep_type == ISOC_IN_EP) { |
---|
159 | | - /* at most need additional two CS. */ |
---|
160 | | - sch_ep->cs_count = DIV_ROUND_UP( |
---|
161 | | - max_packet_size, FS_PAYLOAD_MAX) + 2; |
---|
162 | | - sch_ep->num_budget_microframes = sch_ep->cs_count + 2; |
---|
163 | | - sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX; |
---|
| 394 | + for (i = 2; i < TT_MICROFRAMES_MAX; i++) |
---|
| 395 | + bwb_table[i] = sch_ep->bw_cost_per_microframe; |
---|
164 | 396 | } |
---|
165 | 397 | } |
---|
166 | 398 | } |
---|
.. | .. |
---|
171 | 403 | { |
---|
172 | 404 | u32 num_esit; |
---|
173 | 405 | u32 max_bw = 0; |
---|
| 406 | + u32 bw; |
---|
174 | 407 | int i; |
---|
175 | 408 | int j; |
---|
176 | 409 | |
---|
.. | .. |
---|
179 | 412 | u32 base = offset + i * sch_ep->esit; |
---|
180 | 413 | |
---|
181 | 414 | for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
---|
182 | | - if (sch_bw->bus_bw[base + j] > max_bw) |
---|
183 | | - max_bw = sch_bw->bus_bw[base + j]; |
---|
| 415 | + bw = sch_bw->bus_bw[base + j] + |
---|
| 416 | + sch_ep->bw_budget_table[j]; |
---|
| 417 | + if (bw > max_bw) |
---|
| 418 | + max_bw = bw; |
---|
184 | 419 | } |
---|
185 | 420 | } |
---|
186 | 421 | return max_bw; |
---|
187 | 422 | } |
---|
188 | 423 | |
---|
189 | 424 | static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, |
---|
190 | | - struct mu3h_sch_ep_info *sch_ep, int bw_cost) |
---|
| 425 | + struct mu3h_sch_ep_info *sch_ep, bool used) |
---|
191 | 426 | { |
---|
192 | 427 | u32 num_esit; |
---|
193 | 428 | u32 base; |
---|
.. | .. |
---|
197 | 432 | num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; |
---|
198 | 433 | for (i = 0; i < num_esit; i++) { |
---|
199 | 434 | base = sch_ep->offset + i * sch_ep->esit; |
---|
200 | | - for (j = 0; j < sch_ep->num_budget_microframes; j++) |
---|
201 | | - sch_bw->bus_bw[base + j] += bw_cost; |
---|
| 435 | + for (j = 0; j < sch_ep->num_budget_microframes; j++) { |
---|
| 436 | + if (used) |
---|
| 437 | + sch_bw->bus_bw[base + j] += |
---|
| 438 | + sch_ep->bw_budget_table[j]; |
---|
| 439 | + else |
---|
| 440 | + sch_bw->bus_bw[base + j] -= |
---|
| 441 | + sch_ep->bw_budget_table[j]; |
---|
| 442 | + } |
---|
202 | 443 | } |
---|
203 | 444 | } |
---|
204 | 445 | |
---|
205 | | -static int check_sch_bw(struct usb_device *udev, |
---|
206 | | - struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) |
---|
| 446 | +static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) |
---|
| 447 | +{ |
---|
| 448 | + struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
---|
| 449 | + u32 num_esit, tmp; |
---|
| 450 | + int base; |
---|
| 451 | + int i, j; |
---|
| 452 | + u8 uframes = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); |
---|
| 453 | + |
---|
| 454 | + num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; |
---|
| 455 | + |
---|
| 456 | + if (sch_ep->ep_type == INT_IN_EP || sch_ep->ep_type == ISOC_IN_EP) |
---|
| 457 | + offset++; |
---|
| 458 | + |
---|
| 459 | + for (i = 0; i < num_esit; i++) { |
---|
| 460 | + base = offset + i * sch_ep->esit; |
---|
| 461 | + |
---|
| 462 | + for (j = 0; j < uframes; j++) { |
---|
| 463 | + tmp = tt->fs_bus_bw[base + j] + sch_ep->bw_cost_per_microframe; |
---|
| 464 | + if (tmp > FS_PAYLOAD_MAX) |
---|
| 465 | + return -ESCH_BW_OVERFLOW; |
---|
| 466 | + } |
---|
| 467 | + } |
---|
| 468 | + |
---|
| 469 | + return 0; |
---|
| 470 | +} |
---|
| 471 | + |
---|
| 472 | +static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) |
---|
| 473 | +{ |
---|
| 474 | + u32 extra_cs_count; |
---|
| 475 | + u32 start_ss, last_ss; |
---|
| 476 | + u32 start_cs, last_cs; |
---|
| 477 | + |
---|
| 478 | + start_ss = offset % 8; |
---|
| 479 | + |
---|
| 480 | + if (sch_ep->ep_type == ISOC_OUT_EP) { |
---|
| 481 | + last_ss = start_ss + sch_ep->cs_count - 1; |
---|
| 482 | + |
---|
| 483 | + /* |
---|
| 484 | + * usb_20 spec section11.18: |
---|
| 485 | + * must never schedule Start-Split in Y6 |
---|
| 486 | + */ |
---|
| 487 | + if (!(start_ss == 7 || last_ss < 6)) |
---|
| 488 | + return -ESCH_SS_Y6; |
---|
| 489 | + |
---|
| 490 | + } else { |
---|
| 491 | + u32 cs_count = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); |
---|
| 492 | + |
---|
| 493 | + /* |
---|
| 494 | + * usb_20 spec section11.18: |
---|
| 495 | + * must never schedule Start-Split in Y6 |
---|
| 496 | + */ |
---|
| 497 | + if (start_ss == 6) |
---|
| 498 | + return -ESCH_SS_Y6; |
---|
| 499 | + |
---|
| 500 | + /* one uframe for ss + one uframe for idle */ |
---|
| 501 | + start_cs = (start_ss + 2) % 8; |
---|
| 502 | + last_cs = start_cs + cs_count - 1; |
---|
| 503 | + |
---|
| 504 | + if (last_cs > 7) |
---|
| 505 | + return -ESCH_CS_OVERFLOW; |
---|
| 506 | + |
---|
| 507 | + if (sch_ep->ep_type == ISOC_IN_EP) |
---|
| 508 | + extra_cs_count = (last_cs == 7) ? 1 : 2; |
---|
| 509 | + else /* ep_type : INTR IN / INTR OUT */ |
---|
| 510 | + extra_cs_count = 1; |
---|
| 511 | + |
---|
| 512 | + cs_count += extra_cs_count; |
---|
| 513 | + if (cs_count > 7) |
---|
| 514 | + cs_count = 7; /* HW limit */ |
---|
| 515 | + |
---|
| 516 | + sch_ep->cs_count = cs_count; |
---|
| 517 | + /* one for ss, the other for idle */ |
---|
| 518 | + sch_ep->num_budget_microframes = cs_count + 2; |
---|
| 519 | + |
---|
| 520 | + /* |
---|
| 521 | + * if interval=1, maxp >752, num_budge_micoframe is larger |
---|
| 522 | + * than sch_ep->esit, will overstep boundary |
---|
| 523 | + */ |
---|
| 524 | + if (sch_ep->num_budget_microframes > sch_ep->esit) |
---|
| 525 | + sch_ep->num_budget_microframes = sch_ep->esit; |
---|
| 526 | + } |
---|
| 527 | + |
---|
| 528 | + return check_fs_bus_bw(sch_ep, offset); |
---|
| 529 | +} |
---|
| 530 | + |
---|
| 531 | +static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) |
---|
| 532 | +{ |
---|
| 533 | + struct mu3h_sch_tt *tt = sch_ep->sch_tt; |
---|
| 534 | + u32 base, num_esit; |
---|
| 535 | + int bw_updated; |
---|
| 536 | + int i, j; |
---|
| 537 | + int offset = sch_ep->offset; |
---|
| 538 | + u8 uframes = DIV_ROUND_UP(sch_ep->maxpkt, FS_PAYLOAD_MAX); |
---|
| 539 | + |
---|
| 540 | + num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit; |
---|
| 541 | + |
---|
| 542 | + if (used) |
---|
| 543 | + bw_updated = sch_ep->bw_cost_per_microframe; |
---|
| 544 | + else |
---|
| 545 | + bw_updated = -sch_ep->bw_cost_per_microframe; |
---|
| 546 | + |
---|
| 547 | + if (sch_ep->ep_type == INT_IN_EP || sch_ep->ep_type == ISOC_IN_EP) |
---|
| 548 | + offset++; |
---|
| 549 | + |
---|
| 550 | + for (i = 0; i < num_esit; i++) { |
---|
| 551 | + base = offset + i * sch_ep->esit; |
---|
| 552 | + |
---|
| 553 | + for (j = 0; j < uframes; j++) |
---|
| 554 | + tt->fs_bus_bw[base + j] += bw_updated; |
---|
| 555 | + } |
---|
| 556 | + |
---|
| 557 | + if (used) |
---|
| 558 | + list_add_tail(&sch_ep->tt_endpoint, &tt->ep_list); |
---|
| 559 | + else |
---|
| 560 | + list_del(&sch_ep->tt_endpoint); |
---|
| 561 | +} |
---|
| 562 | + |
---|
| 563 | +static int load_ep_bw(struct mu3h_sch_bw_info *sch_bw, |
---|
| 564 | + struct mu3h_sch_ep_info *sch_ep, bool loaded) |
---|
| 565 | +{ |
---|
| 566 | + if (sch_ep->sch_tt) |
---|
| 567 | + update_sch_tt(sch_ep, loaded); |
---|
| 568 | + |
---|
| 569 | + /* update bus bandwidth info */ |
---|
| 570 | + update_bus_bw(sch_bw, sch_ep, loaded); |
---|
| 571 | + sch_ep->allocated = loaded; |
---|
| 572 | + |
---|
| 573 | + return 0; |
---|
| 574 | +} |
---|
| 575 | + |
---|
| 576 | +static u32 get_esit_boundary(struct mu3h_sch_ep_info *sch_ep) |
---|
| 577 | +{ |
---|
| 578 | + u32 boundary = sch_ep->esit; |
---|
| 579 | + |
---|
| 580 | + if (sch_ep->sch_tt) { /* LS/FS with TT */ |
---|
| 581 | + /* |
---|
| 582 | + * tune for CS, normally esit >= 8 for FS/LS, |
---|
| 583 | + * not add one for other types to avoid access array |
---|
| 584 | + * out of boundary |
---|
| 585 | + */ |
---|
| 586 | + if (sch_ep->ep_type == ISOC_OUT_EP && boundary > 1) |
---|
| 587 | + boundary--; |
---|
| 588 | + } |
---|
| 589 | + |
---|
| 590 | + return boundary; |
---|
| 591 | +} |
---|
| 592 | + |
---|
| 593 | +static int check_sch_bw(struct mu3h_sch_bw_info *sch_bw, |
---|
| 594 | + struct mu3h_sch_ep_info *sch_ep) |
---|
207 | 595 | { |
---|
208 | 596 | u32 offset; |
---|
209 | | - u32 esit; |
---|
210 | | - u32 num_budget_microframes; |
---|
211 | 597 | u32 min_bw; |
---|
212 | 598 | u32 min_index; |
---|
213 | 599 | u32 worst_bw; |
---|
214 | 600 | u32 bw_boundary; |
---|
215 | | - |
---|
216 | | - if (sch_ep->esit > XHCI_MTK_MAX_ESIT) |
---|
217 | | - sch_ep->esit = XHCI_MTK_MAX_ESIT; |
---|
218 | | - |
---|
219 | | - esit = sch_ep->esit; |
---|
220 | | - num_budget_microframes = sch_ep->num_budget_microframes; |
---|
| 601 | + u32 esit_boundary; |
---|
| 602 | + u32 min_num_budget; |
---|
| 603 | + u32 min_cs_count; |
---|
| 604 | + int ret = 0; |
---|
221 | 605 | |
---|
222 | 606 | /* |
---|
223 | 607 | * Search through all possible schedule microframes. |
---|
.. | .. |
---|
225 | 609 | */ |
---|
226 | 610 | min_bw = ~0; |
---|
227 | 611 | min_index = 0; |
---|
228 | | - for (offset = 0; offset < esit; offset++) { |
---|
229 | | - if ((offset + num_budget_microframes) > sch_ep->esit) |
---|
230 | | - break; |
---|
| 612 | + min_cs_count = sch_ep->cs_count; |
---|
| 613 | + min_num_budget = sch_ep->num_budget_microframes; |
---|
| 614 | + esit_boundary = get_esit_boundary(sch_ep); |
---|
| 615 | + for (offset = 0; offset < sch_ep->esit; offset++) { |
---|
| 616 | + if (sch_ep->sch_tt) { |
---|
| 617 | + ret = check_sch_tt(sch_ep, offset); |
---|
| 618 | + if (ret) |
---|
| 619 | + continue; |
---|
| 620 | + } |
---|
231 | 621 | |
---|
232 | | - /* |
---|
233 | | - * usb_20 spec section11.18: |
---|
234 | | - * must never schedule Start-Split in Y6 |
---|
235 | | - */ |
---|
236 | | - if (is_fs_or_ls(udev->speed) && (offset % 8 == 6)) |
---|
237 | | - continue; |
---|
| 622 | + if ((offset + sch_ep->num_budget_microframes) > esit_boundary) |
---|
| 623 | + break; |
---|
238 | 624 | |
---|
239 | 625 | worst_bw = get_max_bw(sch_bw, sch_ep, offset); |
---|
240 | 626 | if (min_bw > worst_bw) { |
---|
241 | 627 | min_bw = worst_bw; |
---|
242 | 628 | min_index = offset; |
---|
| 629 | + min_cs_count = sch_ep->cs_count; |
---|
| 630 | + min_num_budget = sch_ep->num_budget_microframes; |
---|
243 | 631 | } |
---|
244 | 632 | if (min_bw == 0) |
---|
245 | 633 | break; |
---|
246 | 634 | } |
---|
247 | | - sch_ep->offset = min_index; |
---|
248 | 635 | |
---|
249 | | - bw_boundary = (udev->speed == USB_SPEED_SUPER) |
---|
250 | | - ? SS_BW_BOUNDARY : HS_BW_BOUNDARY; |
---|
251 | | - |
---|
| 636 | + bw_boundary = get_bw_boundary(sch_ep->speed); |
---|
252 | 637 | /* check bandwidth */ |
---|
253 | | - if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary) |
---|
254 | | - return -ERANGE; |
---|
| 638 | + if (min_bw > bw_boundary) |
---|
| 639 | + return ret ? ret : -ESCH_BW_OVERFLOW; |
---|
255 | 640 | |
---|
256 | | - /* update bus bandwidth info */ |
---|
257 | | - update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe); |
---|
| 641 | + sch_ep->offset = min_index; |
---|
| 642 | + sch_ep->cs_count = min_cs_count; |
---|
| 643 | + sch_ep->num_budget_microframes = min_num_budget; |
---|
258 | 644 | |
---|
259 | | - return 0; |
---|
| 645 | + return load_ep_bw(sch_bw, sch_ep, true); |
---|
| 646 | +} |
---|
| 647 | + |
---|
| 648 | +static void destroy_sch_ep(struct usb_device *udev, |
---|
| 649 | + struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) |
---|
| 650 | +{ |
---|
| 651 | + /* only release ep bw check passed by check_sch_bw() */ |
---|
| 652 | + if (sch_ep->allocated) |
---|
| 653 | + load_ep_bw(sch_bw, sch_ep, false); |
---|
| 654 | + |
---|
| 655 | + if (sch_ep->sch_tt) |
---|
| 656 | + drop_tt(udev); |
---|
| 657 | + |
---|
| 658 | + list_del(&sch_ep->endpoint); |
---|
| 659 | + kfree(sch_ep); |
---|
260 | 660 | } |
---|
261 | 661 | |
---|
262 | 662 | static bool need_bw_sch(struct usb_host_endpoint *ep, |
---|
.. | .. |
---|
301 | 701 | |
---|
302 | 702 | mtk->sch_array = sch_array; |
---|
303 | 703 | |
---|
| 704 | + INIT_LIST_HEAD(&mtk->bw_ep_chk_list); |
---|
| 705 | + |
---|
304 | 706 | return 0; |
---|
305 | 707 | } |
---|
306 | | -EXPORT_SYMBOL_GPL(xhci_mtk_sch_init); |
---|
307 | 708 | |
---|
308 | 709 | void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk) |
---|
309 | 710 | { |
---|
310 | 711 | kfree(mtk->sch_array); |
---|
311 | 712 | } |
---|
312 | | -EXPORT_SYMBOL_GPL(xhci_mtk_sch_exit); |
---|
313 | 713 | |
---|
314 | | -int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
---|
315 | | - struct usb_host_endpoint *ep) |
---|
| 714 | +static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
---|
| 715 | + struct usb_host_endpoint *ep) |
---|
316 | 716 | { |
---|
317 | 717 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
---|
318 | | - struct xhci_hcd *xhci; |
---|
| 718 | + struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
---|
319 | 719 | struct xhci_ep_ctx *ep_ctx; |
---|
320 | | - struct xhci_slot_ctx *slot_ctx; |
---|
321 | 720 | struct xhci_virt_device *virt_dev; |
---|
322 | | - struct mu3h_sch_bw_info *sch_bw; |
---|
323 | 721 | struct mu3h_sch_ep_info *sch_ep; |
---|
324 | | - struct mu3h_sch_bw_info *sch_array; |
---|
325 | 722 | unsigned int ep_index; |
---|
326 | | - int bw_index; |
---|
327 | | - int ret = 0; |
---|
328 | 723 | |
---|
329 | | - xhci = hcd_to_xhci(hcd); |
---|
330 | 724 | virt_dev = xhci->devs[udev->slot_id]; |
---|
331 | 725 | ep_index = xhci_get_endpoint_index(&ep->desc); |
---|
332 | | - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); |
---|
333 | 726 | ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); |
---|
334 | | - sch_array = mtk->sch_array; |
---|
335 | 727 | |
---|
336 | | - xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n", |
---|
337 | | - __func__, usb_endpoint_type(&ep->desc), udev->speed, |
---|
338 | | - usb_endpoint_maxp(&ep->desc), |
---|
339 | | - usb_endpoint_dir_in(&ep->desc), ep); |
---|
| 728 | + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); |
---|
340 | 729 | |
---|
341 | | - if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) { |
---|
| 730 | + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) { |
---|
342 | 731 | /* |
---|
343 | 732 | * set @bpkts to 1 if it is LS or FS periodic endpoint, and its |
---|
344 | 733 | * device does not connected through an external HS hub |
---|
345 | 734 | */ |
---|
346 | 735 | if (usb_endpoint_xfer_int(&ep->desc) |
---|
347 | 736 | || usb_endpoint_xfer_isoc(&ep->desc)) |
---|
348 | | - ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(1)); |
---|
| 737 | + ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(1)); |
---|
349 | 738 | |
---|
350 | 739 | return 0; |
---|
351 | 740 | } |
---|
352 | 741 | |
---|
353 | | - bw_index = get_bw_index(xhci, udev, ep); |
---|
354 | | - sch_bw = &sch_array[bw_index]; |
---|
355 | | - |
---|
356 | | - sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO); |
---|
357 | | - if (!sch_ep) |
---|
| 742 | + sch_ep = create_sch_ep(udev, ep, ep_ctx); |
---|
| 743 | + if (IS_ERR_OR_NULL(sch_ep)) |
---|
358 | 744 | return -ENOMEM; |
---|
359 | 745 | |
---|
360 | | - setup_sch_info(udev, ep_ctx, sch_ep); |
---|
| 746 | + setup_sch_info(ep_ctx, sch_ep); |
---|
361 | 747 | |
---|
362 | | - ret = check_sch_bw(udev, sch_bw, sch_ep); |
---|
363 | | - if (ret) { |
---|
364 | | - xhci_err(xhci, "Not enough bandwidth!\n"); |
---|
365 | | - kfree(sch_ep); |
---|
366 | | - return -ENOSPC; |
---|
367 | | - } |
---|
368 | | - |
---|
369 | | - list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); |
---|
370 | | - sch_ep->ep = ep; |
---|
371 | | - |
---|
372 | | - ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) |
---|
373 | | - | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); |
---|
374 | | - ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset) |
---|
375 | | - | EP_BREPEAT(sch_ep->repeat)); |
---|
376 | | - |
---|
377 | | - xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n", |
---|
378 | | - sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode, |
---|
379 | | - sch_ep->offset, sch_ep->repeat); |
---|
| 748 | + list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list); |
---|
380 | 749 | |
---|
381 | 750 | return 0; |
---|
382 | 751 | } |
---|
383 | | -EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk); |
---|
384 | 752 | |
---|
385 | | -void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
---|
386 | | - struct usb_host_endpoint *ep) |
---|
| 753 | +static void drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, |
---|
| 754 | + struct usb_host_endpoint *ep) |
---|
387 | 755 | { |
---|
388 | 756 | struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
---|
389 | | - struct xhci_hcd *xhci; |
---|
390 | | - struct xhci_slot_ctx *slot_ctx; |
---|
| 757 | + struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
---|
391 | 758 | struct xhci_virt_device *virt_dev; |
---|
392 | | - struct mu3h_sch_bw_info *sch_array; |
---|
393 | 759 | struct mu3h_sch_bw_info *sch_bw; |
---|
394 | | - struct mu3h_sch_ep_info *sch_ep; |
---|
395 | | - int bw_index; |
---|
| 760 | + struct mu3h_sch_ep_info *sch_ep, *tmp; |
---|
396 | 761 | |
---|
397 | | - xhci = hcd_to_xhci(hcd); |
---|
398 | 762 | virt_dev = xhci->devs[udev->slot_id]; |
---|
399 | | - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); |
---|
400 | | - sch_array = mtk->sch_array; |
---|
401 | 763 | |
---|
402 | | - xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n", |
---|
403 | | - __func__, usb_endpoint_type(&ep->desc), udev->speed, |
---|
404 | | - usb_endpoint_maxp(&ep->desc), |
---|
405 | | - usb_endpoint_dir_in(&ep->desc), ep); |
---|
| 764 | + xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); |
---|
406 | 765 | |
---|
407 | | - if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) |
---|
| 766 | + if (!need_bw_sch(ep, udev->speed, !!virt_dev->tt_info)) |
---|
408 | 767 | return; |
---|
409 | 768 | |
---|
410 | | - bw_index = get_bw_index(xhci, udev, ep); |
---|
411 | | - sch_bw = &sch_array[bw_index]; |
---|
| 769 | + sch_bw = get_bw_info(mtk, udev, ep); |
---|
412 | 770 | |
---|
413 | | - list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) { |
---|
| 771 | + list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { |
---|
414 | 772 | if (sch_ep->ep == ep) { |
---|
415 | | - update_bus_bw(sch_bw, sch_ep, |
---|
416 | | - -sch_ep->bw_cost_per_microframe); |
---|
417 | | - list_del(&sch_ep->endpoint); |
---|
418 | | - kfree(sch_ep); |
---|
| 773 | + destroy_sch_ep(udev, sch_bw, sch_ep); |
---|
419 | 774 | break; |
---|
420 | 775 | } |
---|
421 | 776 | } |
---|
422 | 777 | } |
---|
423 | | -EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk); |
---|
| 778 | + |
---|
| 779 | +int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) |
---|
| 780 | +{ |
---|
| 781 | + struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
---|
| 782 | + struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
---|
| 783 | + struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; |
---|
| 784 | + struct mu3h_sch_bw_info *sch_bw; |
---|
| 785 | + struct mu3h_sch_ep_info *sch_ep, *tmp; |
---|
| 786 | + int ret; |
---|
| 787 | + |
---|
| 788 | + xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); |
---|
| 789 | + |
---|
| 790 | + list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) { |
---|
| 791 | + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); |
---|
| 792 | + |
---|
| 793 | + ret = check_sch_bw(sch_bw, sch_ep); |
---|
| 794 | + if (ret) { |
---|
| 795 | + xhci_err(xhci, "Not enough bandwidth! (%s)\n", |
---|
| 796 | + sch_error_string(-ret)); |
---|
| 797 | + return -ENOSPC; |
---|
| 798 | + } |
---|
| 799 | + } |
---|
| 800 | + |
---|
| 801 | + list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { |
---|
| 802 | + struct xhci_ep_ctx *ep_ctx; |
---|
| 803 | + struct usb_host_endpoint *ep = sch_ep->ep; |
---|
| 804 | + unsigned int ep_index = xhci_get_endpoint_index(&ep->desc); |
---|
| 805 | + |
---|
| 806 | + sch_bw = get_bw_info(mtk, udev, ep); |
---|
| 807 | + list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); |
---|
| 808 | + |
---|
| 809 | + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); |
---|
| 810 | + ep_ctx->reserved[0] = cpu_to_le32(EP_BPKTS(sch_ep->pkts) |
---|
| 811 | + | EP_BCSCOUNT(sch_ep->cs_count) |
---|
| 812 | + | EP_BBM(sch_ep->burst_mode)); |
---|
| 813 | + ep_ctx->reserved[1] = cpu_to_le32(EP_BOFFSET(sch_ep->offset) |
---|
| 814 | + | EP_BREPEAT(sch_ep->repeat)); |
---|
| 815 | + |
---|
| 816 | + xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n", |
---|
| 817 | + sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode, |
---|
| 818 | + sch_ep->offset, sch_ep->repeat); |
---|
| 819 | + } |
---|
| 820 | + |
---|
| 821 | + return xhci_check_bandwidth(hcd, udev); |
---|
| 822 | +} |
---|
| 823 | + |
---|
| 824 | +void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) |
---|
| 825 | +{ |
---|
| 826 | + struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); |
---|
| 827 | + struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
---|
| 828 | + struct mu3h_sch_bw_info *sch_bw; |
---|
| 829 | + struct mu3h_sch_ep_info *sch_ep, *tmp; |
---|
| 830 | + |
---|
| 831 | + xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); |
---|
| 832 | + |
---|
| 833 | + list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { |
---|
| 834 | + sch_bw = get_bw_info(mtk, udev, sch_ep->ep); |
---|
| 835 | + destroy_sch_ep(udev, sch_bw, sch_ep); |
---|
| 836 | + } |
---|
| 837 | + |
---|
| 838 | + xhci_reset_bandwidth(hcd, udev); |
---|
| 839 | +} |
---|
| 840 | + |
---|
| 841 | +int xhci_mtk_add_ep(struct usb_hcd *hcd, struct usb_device *udev, |
---|
| 842 | + struct usb_host_endpoint *ep) |
---|
| 843 | +{ |
---|
| 844 | + int ret; |
---|
| 845 | + |
---|
| 846 | + ret = xhci_add_endpoint(hcd, udev, ep); |
---|
| 847 | + if (ret) |
---|
| 848 | + return ret; |
---|
| 849 | + |
---|
| 850 | + if (ep->hcpriv) |
---|
| 851 | + ret = add_ep_quirk(hcd, udev, ep); |
---|
| 852 | + |
---|
| 853 | + return ret; |
---|
| 854 | +} |
---|
| 855 | + |
---|
| 856 | +int xhci_mtk_drop_ep(struct usb_hcd *hcd, struct usb_device *udev, |
---|
| 857 | + struct usb_host_endpoint *ep) |
---|
| 858 | +{ |
---|
| 859 | + int ret; |
---|
| 860 | + |
---|
| 861 | + ret = xhci_drop_endpoint(hcd, udev, ep); |
---|
| 862 | + if (ret) |
---|
| 863 | + return ret; |
---|
| 864 | + |
---|
| 865 | + if (ep->hcpriv) |
---|
| 866 | + drop_ep_quirk(hcd, udev, ep); |
---|
| 867 | + |
---|
| 868 | + return 0; |
---|
| 869 | +} |
---|