Changeset 4ed803f1 in mainline
- Timestamp:
- 2018-01-11T17:35:02Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 69a93d02
- Parents:
- 929599a8
- git-author:
- Salmelu <salmelu@…> (2018-01-11 17:29:27)
- git-committer:
- Salmelu <salmelu@…> (2018-01-11 17:35:02)
- Location:
- uspace/drv/bus/usb/xhci
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/isoch.c
r929599a8 r4ed803f1 84 84 } 85 85 86 static void isoch_reset_no_timer(xhci_endpoint_t *ep) 87 { 88 xhci_isoch_t * const isoch = ep->isoch; 89 assert(fibril_mutex_is_locked(&isoch->guard)); 90 /* 91 * As we cannot clear timer when we are triggered by it, 92 * we have to avoid doing it in common method. 93 */ 94 fibril_timer_clear_locked(isoch->reset_timer); 95 isoch_reset(ep); 96 } 97 98 static void isoch_reset_timer(void *ep) { 99 xhci_isoch_t * const isoch = xhci_endpoint_get(ep)->isoch; 100 fibril_mutex_lock(&isoch->guard); 101 isoch_reset(ep); 102 fibril_mutex_unlock(&isoch->guard); 103 } 104 105 /* 106 * Fast transfers could trigger the reset timer before the data is processed, 107 * leading into false reset. 108 */ 109 #define RESET_TIMER_DELAY 100000 110 static void timer_schedule_reset(xhci_endpoint_t *ep) { 111 xhci_isoch_t * const isoch = ep->isoch; 112 const suseconds_t delay = isoch->buffer_count * ep->interval * 125 + RESET_TIMER_DELAY; 113 114 fibril_timer_clear_locked(isoch->reset_timer); 115 fibril_timer_set_locked(isoch->reset_timer, delay, 116 isoch_reset_timer, ep); 117 } 118 86 119 void isoch_fini(xhci_endpoint_t *ep) 87 120 { … … 92 125 fibril_timer_clear(isoch->feeding_timer); 93 126 fibril_timer_destroy(isoch->feeding_timer); 127 fibril_timer_clear(isoch->reset_timer); 128 fibril_timer_destroy(isoch->reset_timer); 94 129 } 95 130 … … 109 144 110 145 isoch->feeding_timer = fibril_timer_create(&isoch->guard); 146 isoch->reset_timer = fibril_timer_create(&isoch->guard); 111 147 if (!isoch->feeding_timer) 112 148 return ENOMEM; … … 115 151 if(!isoch->transfers) 116 152 goto err; 117 153 118 154 for (size_t i = 0; i < isoch->buffer_count; ++i) { 119 155 xhci_isoch_transfer_t *transfer = &isoch->transfers[i]; … … 124 160 125 161 fibril_mutex_lock(&isoch->guard); 126 isoch_reset (ep);162 isoch_reset_no_timer(ep); 127 163 fibril_mutex_unlock(&isoch->guard); 128 164 … … 226 262 * to ensure correct scheduling of transfers, that are 227 263 * buffer_count * interval away from now. 228 * Maximum interval is 8 seconds, which means we need a size of 264 * Maximum interval is 8 seconds, which means we need a size of 229 265 * 16 seconds. The size of MFIINDEX is 2 seconds only. 230 266 * … … 301 337 } 302 338 } 339 303 340 out: 304 305 341 if (fed) { 306 342 const uint8_t slot_id = xhci_device_get(ep->base.device)->slot_id; 307 343 const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */ 308 344 hc_ring_doorbell(hc, slot_id, target); 345 /* The ring may be dead. If no event happens until the delay, reset the endpoint. */ 346 timer_schedule_reset(ep); 309 347 } 310 348 … … 394 432 const uint8_t target = xhci_endpoint_index(ep) + 1; /* EP Doorbells start at 1 */ 395 433 hc_ring_doorbell(hc, slot_id, target); 434 /* The ring may be dead. If no event happens until the delay, reset the endpoint. */ 435 timer_schedule_reset(ep); 396 436 } 397 437 } … … 541 581 /* For IN, the buffer has overfilled, we empty the buffers and readd TRBs */ 542 582 usb_log_warning("Ring over/underrun."); 543 isoch_reset (ep);583 isoch_reset_no_timer(ep); 544 584 fibril_condvar_broadcast(&ep->isoch->avail); 545 585 fibril_mutex_unlock(&ep->isoch->guard); … … 555 595 } 556 596 557 bool found_mine = false;558 bool found_incomplete = false;559 560 597 /* 561 598 * The order of delivering events is not necessarily the one we would 562 * expect. It is safer to walk the list of our 4transfers and check599 * expect. It is safer to walk the list of our transfers and check 563 600 * which one it is. 601 * To minimize the amount of transfers checked, we start at dequeue pointer 602 * and exit the loop as soon as the transfer is found. 564 603 */ 565 for (size_t i = 0; i < isoch->buffer_count; ++i) { 566 xhci_isoch_transfer_t * const it = &isoch->transfers[i]; 567 568 switch (it->state) { 569 case ISOCH_FILLED: 570 found_incomplete = true; 571 break; 572 573 case ISOCH_FED: 574 if (it->interrupt_trb_phys != trb->parameter) { 575 found_incomplete = true; 576 break; 577 } 578 604 bool found_mine = false; 605 for (size_t i = 0, di = isoch->dequeue; i < isoch->buffer_count; ++i, ++di) { 606 /* Wrap it back to 0, don't use modulo every loop traversal */ 607 if (di == isoch->buffer_count) { 608 di = 0; 609 } 610 611 xhci_isoch_transfer_t * const it = &isoch->transfers[di]; 612 613 if (it->state == ISOCH_FED && it->interrupt_trb_phys == trb->parameter) { 579 614 usb_log_debug2("[isoch] buffer %zu completed", it - isoch->transfers); 580 615 it->state = ISOCH_COMPLETE; … … 583 618 found_mine = true; 584 619 break; 585 default:586 break;587 620 } 588 621 } … … 595 628 * It may happen that the driver already stopped reading (writing), 596 629 * and our buffers are filled (empty). As QEMU (and possibly others) 597 * does not send RING_UNDERRUN (OVERRUN) event, detect it here. 630 * does not send RING_UNDERRUN (OVERRUN) event, we set a timer to 631 * reset it after the buffers should have been consumed. If there 632 * is no issue, the timer will get restarted often enough. 598 633 */ 599 if (!found_incomplete) { 600 usb_log_warning("[isoch] Endpoint" XHCI_EP_FMT ": Detected " 601 "isochronous ring %s.", XHCI_EP_ARGS(*ep), 602 (ep->base.direction == USB_DIRECTION_IN) ? "underrun" : "overrun"); 603 isoch_reset(ep); 604 } 634 timer_schedule_reset(ep); 605 635 606 636 fibril_condvar_broadcast(&ep->isoch->avail); -
uspace/drv/bus/usb/xhci/isoch.h
r929599a8 r4ed803f1 81 81 fibril_timer_t *feeding_timer; 82 82 83 /** Resets endpoint if there is no traffic. */ 84 fibril_timer_t *reset_timer; 85 83 86 /** The maximum size of an isochronous transfer and therefore the size of buffers */ 84 87 size_t max_size;
Note:
See TracChangeset
for help on using the changeset viewer.