Changeset 4db49344 in mainline for uspace/drv/bus/usb/uhci
- Timestamp:
- 2018-01-23T21:52:28Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 3dd80f8
- Parents:
- a6afb4c
- git-author:
- Ondřej Hlavatý <aearsis@…> (2018-01-23 20:49:35)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2018-01-23 21:52:28)
- Location:
- uspace/drv/bus/usb/uhci
- Files:
-
- 4 edited
-
hc.c (modified) (11 diffs)
-
hc.h (modified) (1 diff)
-
transfer_list.c (modified) (4 diffs)
-
transfer_list.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
ra6afb4c r4db49344 97 97 98 98 static void hc_init_hw(const hc_t *instance); 99 static int hc_init_mem_structures(hc_t *instance , hc_device_t *);99 static int hc_init_mem_structures(hc_t *instance); 100 100 static int hc_init_transfer_lists(hc_t *instance); 101 101 … … 164 164 /* Lower 2 bits are transaction error and transaction complete */ 165 165 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 166 LIST_INITIALIZE(done); 167 transfer_list_remove_finished( 168 &instance->transfers_interrupt, &done); 169 transfer_list_remove_finished( 170 &instance->transfers_control_slow, &done); 171 transfer_list_remove_finished( 172 &instance->transfers_control_full, &done); 173 transfer_list_remove_finished( 174 &instance->transfers_bulk_full, &done); 175 176 list_foreach_safe(done, current, next) { 177 list_remove(current); 178 uhci_transfer_batch_t *batch = 179 uhci_transfer_batch_from_link(current); 180 usb_transfer_batch_finish(&batch->base); 181 } 182 } 166 transfer_list_check_finished(&instance->transfers_interrupt); 167 transfer_list_check_finished(&instance->transfers_control_slow); 168 transfer_list_check_finished(&instance->transfers_control_full); 169 transfer_list_check_finished(&instance->transfers_bulk_full); 170 } 171 183 172 /* Resume interrupts are not supported */ 184 173 if (status & UHCI_STATUS_RESUME) { … … 239 228 hw_res->io_ranges.ranges[0].size); 240 229 241 ret = hc_init_mem_structures(instance , hcd);230 ret = hc_init_mem_structures(instance); 242 231 if (ret != EOK) { 243 232 usb_log_error("Failed to init UHCI memory structures: %s.", … … 328 317 } 329 318 319 static int endpoint_register(endpoint_t *ep) 320 { 321 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 322 323 const int err = usb2_bus_ops.endpoint_register(ep); 324 if (err) 325 return err; 326 327 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 328 if (!list) 329 /* 330 * We don't support this combination (e.g. isochronous). Do not 331 * fail early, because that would block any device with these 332 * endpoints from connecting. Instead, make sure these transfers 333 * are denied soon enough with ENOTSUP not to fail on asserts. 334 */ 335 return EOK; 336 337 endpoint_set_online(ep, &list->guard); 338 return EOK; 339 } 340 330 341 static void endpoint_unregister(endpoint_t *ep) 331 342 { 332 343 hc_t * const hc = bus_to_hc(endpoint_get_bus(ep)); 333 344 usb2_bus_ops.endpoint_unregister(ep); 334 335 uhci_transfer_batch_t *batch = NULL;336 345 337 346 // Check for the roothub, as it does not schedule into lists … … 344 353 345 354 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 346 347 355 if (!list) 348 356 /* … … 352 360 return; 353 361 354 // To avoid ABBA deadlock, we need to take the list first355 362 fibril_mutex_lock(&list->guard); 356 fibril_mutex_lock(&ep->guard); 357 if (ep->active_batch) { 358 batch = uhci_transfer_batch_get(ep->active_batch); 359 endpoint_deactivate_locked(ep); 360 transfer_list_remove_batch(list, batch); 361 } 362 fibril_mutex_unlock(&ep->guard); 363 364 endpoint_set_offline_locked(ep); 365 /* From now on, no other transfer will be scheduled. */ 366 367 if (!ep->active_batch) { 368 fibril_mutex_unlock(&list->guard); 369 return; 370 } 371 372 /* First, offer the batch a short chance to be finished. */ 373 endpoint_wait_timeout_locked(ep, 10000); 374 375 if (!ep->active_batch) { 376 fibril_mutex_unlock(&list->guard); 377 return; 378 } 379 380 uhci_transfer_batch_t * const batch = 381 uhci_transfer_batch_get(ep->active_batch); 382 383 /* Remove the batch from the schedule to stop it from being finished. */ 384 endpoint_deactivate_locked(ep); 385 transfer_list_remove_batch(list, batch); 386 363 387 fibril_mutex_unlock(&list->guard); 364 388 365 if (batch) { 366 // The HW could have been looking at the batch. 367 // Better wait two frames before we release the buffers. 368 async_usleep(2000); 369 batch->base.error = EINTR; 370 batch->base.transferred_size = 0; 371 usb_transfer_batch_finish(&batch->base); 372 } 389 /* 390 * We removed the batch from software schedule only, it's still possible 391 * that HC has it in its caches. Better wait a while before we release 392 * the buffers. 393 */ 394 async_usleep(20000); 395 batch->base.error = EINTR; 396 batch->base.transferred_size = 0; 397 usb_transfer_batch_finish(&batch->base); 373 398 } 374 399 … … 382 407 .status = hc_status, 383 408 409 .endpoint_register = endpoint_register, 384 410 .endpoint_unregister = endpoint_unregister, 385 411 .endpoint_count_bw = bandwidth_count_usb11, … … 400 426 * - frame list page (needs to be one UHCI hw accessible 4K page) 401 427 */ 402 int hc_init_mem_structures(hc_t *instance , hc_device_t *hcd)428 int hc_init_mem_structures(hc_t *instance) 403 429 { 404 430 assert(instance); … … 425 451 return ENOMEM; 426 452 } 453 list_initialize(&instance->pending_endpoints); 427 454 usb_log_debug("Initialized transfer lists."); 428 455 … … 514 541 } 515 542 516 /** Schedule batch for execution. 543 /** 544 * Schedule batch for execution. 517 545 * 518 546 * @param[in] instance UHCI structure to use. 519 547 * @param[in] batch Transfer batch to schedule. 520 548 * @return Error code 521 *522 * Checks for bandwidth availability and appends the batch to the proper queue.523 549 */ 524 550 static int hc_schedule(usb_transfer_batch_t *batch) … … 531 557 return uhci_rh_schedule(&hc->rh, batch); 532 558 533 534 const int err = uhci_transfer_batch_prepare(uhci_batch); 535 if (err) 559 transfer_list_t * const list = 560 hc->transfers[ep->device->speed][ep->transfer_type]; 561 562 if (!list) 563 return ENOTSUP; 564 565 int err; 566 if ((err = uhci_transfer_batch_prepare(uhci_batch))) 536 567 return err; 537 568 538 transfer_list_t *list = hc->transfers[ep->device->speed][ep->transfer_type]; 539 assert(list); 540 transfer_list_add_batch(list, uhci_batch); 541 542 return EOK; 543 } 544 545 int hc_unschedule_batch(usb_transfer_batch_t *batch) 546 { 547 548 return EOK; 569 return transfer_list_add_batch(list, uhci_batch); 549 570 } 550 571 -
uspace/drv/bus/usb/uhci/hc.h
ra6afb4c r4db49344 123 123 transfer_list_t *transfers[2][4]; 124 124 125 /** 126 * Guard for the pending list. Can be locked under EP guard, but not 127 * vice versa. 128 */ 129 fibril_mutex_t guard; 130 /** List of endpoints with a transfer scheduled */ 131 list_t pending_endpoints; 132 125 133 /** Number of hw failures detected. */ 126 134 unsigned hw_failures; -
uspace/drv/bus/usb/uhci/transfer_list.c
ra6afb4c r4db49344 102 102 } 103 103 104 /** Add transfer batch to the list and queue. 105 * 106 * @param[in] instance List to use. 107 * @param[in] batch Transfer batch to submit. 104 /** 105 * Add transfer batch to the list and queue. 108 106 * 109 107 * The batch is added to the end of the list and queue. 110 */ 111 void transfer_list_add_batch( 108 * 109 * @param[in] instance List to use. 110 * @param[in] batch Transfer batch to submit. After return, the batch must 111 * not be used further. 112 */ 113 int transfer_list_add_batch( 112 114 transfer_list_t *instance, uhci_transfer_batch_t *uhci_batch) 113 115 { … … 117 119 endpoint_t *ep = uhci_batch->base.ep; 118 120 119 /* First, wait until the endpoint is free to use */ 120 fibril_mutex_lock(&ep->guard); 121 endpoint_activate_locked(ep, &uhci_batch->base); 122 fibril_mutex_unlock(&ep->guard); 121 fibril_mutex_lock(&instance->guard); 122 123 const int err = endpoint_activate_locked(ep, &uhci_batch->base); 124 if (err) { 125 fibril_mutex_unlock(&instance->guard); 126 return err; 127 } 123 128 124 129 usb_log_debug2("Batch %p adding to queue %s.", 125 130 uhci_batch, instance->name); 126 127 fibril_mutex_lock(&instance->guard);128 131 129 132 /* Assume there is nothing scheduled */ … … 155 158 USB_TRANSFER_BATCH_ARGS(uhci_batch->base), instance->name); 156 159 fibril_mutex_unlock(&instance->guard); 160 return EOK; 157 161 } 158 162 … … 171 175 * @param[in] done list to fill 172 176 */ 173 void transfer_list_remove_finished(transfer_list_t *instance, list_t *done) 174 { 175 assert(instance); 176 assert(done); 177 void transfer_list_check_finished(transfer_list_t *instance) 178 { 179 assert(instance); 177 180 178 181 fibril_mutex_lock(&instance->guard); 179 link_t *current = list_first(&instance->batch_list); 180 while (current && current != &instance->batch_list.head) { 181 link_t * const next = current->next; 182 uhci_transfer_batch_t *batch = 183 uhci_transfer_batch_from_link(current); 182 list_foreach_safe(instance->batch_list, current, next) { 183 uhci_transfer_batch_t *batch = uhci_transfer_batch_from_link(current); 184 184 185 185 if (uhci_transfer_batch_check_completed(batch)) { 186 /* Remove from schedule, save for processing */187 fibril_mutex_lock(&batch->base.ep->guard);188 186 assert(batch->base.ep->active_batch == &batch->base); 187 endpoint_deactivate_locked(batch->base.ep); 189 188 hc_reset_toggles(&batch->base, &uhci_reset_toggle); 190 endpoint_deactivate_locked(batch->base.ep);191 189 transfer_list_remove_batch(instance, batch); 192 fibril_mutex_unlock(&batch->base.ep->guard); 193 194 list_append(current, done); 190 usb_transfer_batch_finish(&batch->base); 195 191 } 196 current = next;197 192 } 198 193 fibril_mutex_unlock(&instance->guard); -
uspace/drv/bus/usb/uhci/transfer_list.h
ra6afb4c r4db49344 59 59 int transfer_list_init(transfer_list_t *, const char *); 60 60 void transfer_list_set_next(transfer_list_t *, transfer_list_t *); 61 voidtransfer_list_add_batch(transfer_list_t *, uhci_transfer_batch_t *);61 int transfer_list_add_batch(transfer_list_t *, uhci_transfer_batch_t *); 62 62 void transfer_list_remove_batch(transfer_list_t *, uhci_transfer_batch_t *); 63 void transfer_list_ remove_finished(transfer_list_t *,list_t *);63 void transfer_list_check_finished(transfer_list_t *); 64 64 void transfer_list_abort_all(transfer_list_t *); 65 65
Note:
See TracChangeset
for help on using the changeset viewer.
