| .. | .. |
|---|
| 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 | +} |
|---|