Changeset 889146e in mainline for uspace/drv/bus/usb/xhci/commands.c
- Timestamp:
- 2017-12-10T21:49:12Z (6 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 53db806
- Parents:
- 6ef407b
- git-author:
- Ondřej Hlavatý <aearsis@…> (2017-12-10 21:43:47)
- git-committer:
- Ondřej Hlavatý <aearsis@…> (2017-12-10 21:49:12)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/commands.c
r6ef407b r889146e 64 64 /* Control functions */ 65 65 66 static xhci_cmd_ring_t *get_cmd_ring(xhci_hc_t *hc) 67 { 68 assert(hc); 69 return &hc->cr; 70 } 71 66 72 int xhci_init_commands(xhci_hc_t *hc) 67 73 { 68 assert(hc); 69 70 list_initialize(&hc->commands); 71 72 fibril_mutex_initialize(&hc->commands_mtx); 74 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 75 int err; 76 77 if ((err = xhci_trb_ring_init(&cr->trb_ring))) 78 return err; 79 80 fibril_mutex_initialize(&cr->guard); 81 fibril_condvar_initialize(&cr->state_cv); 82 fibril_condvar_initialize(&cr->stopped_cv); 83 84 list_initialize(&cr->cmd_list); 85 86 cr->state = XHCI_CR_STATE_OPEN; 73 87 74 88 return EOK; … … 77 91 void xhci_fini_commands(xhci_hc_t *hc) 78 92 { 79 // Note: Untested.93 xhci_stop_command_ring(hc); 80 94 assert(hc); 81 95 } … … 91 105 92 106 cmd->_header.cmd = type; 93 cmd->_header.timeout = XHCI_DEFAULT_TIMEOUT;94 107 } 95 108 … … 106 119 } 107 120 108 static inline xhci_cmd_t *get_command(xhci_hc_t *hc, uint64_t phys) 109 { 110 fibril_mutex_lock(&hc->commands_mtx); 111 112 link_t *cmd_link = list_first(&hc->commands); 121 /** Call with guard locked. */ 122 static inline xhci_cmd_t *find_command(xhci_hc_t *hc, uint64_t phys) 123 { 124 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 125 assert(fibril_mutex_is_locked(&cr->guard)); 126 127 link_t *cmd_link = list_first(&cr->cmd_list); 113 128 114 129 while (cmd_link != NULL) { … … 118 133 break; 119 134 120 cmd_link = list_next(cmd_link, &hc->commands); 121 } 122 123 if (cmd_link != NULL) { 124 list_remove(cmd_link); 125 fibril_mutex_unlock(&hc->commands_mtx); 126 127 return list_get_instance(cmd_link, xhci_cmd_t, _header.link); 128 } 129 130 fibril_mutex_unlock(&hc->commands_mtx); 131 return NULL; 135 cmd_link = list_next(cmd_link, &cr->cmd_list); 136 } 137 138 return cmd_link ? list_get_instance(cmd_link, xhci_cmd_t, _header.link) 139 : NULL; 132 140 } 133 141 134 142 static inline int enqueue_command(xhci_hc_t *hc, xhci_cmd_t *cmd, unsigned doorbell, unsigned target) 135 143 { 136 assert(hc); 137 assert(cmd); 138 139 fibril_mutex_lock(&hc->commands_mtx); 140 list_append(&cmd->_header.link, &hc->commands); 141 fibril_mutex_unlock(&hc->commands_mtx); 142 143 xhci_trb_ring_enqueue(&hc->command_ring, &cmd->_header.trb, &cmd->_header.trb_phys); 144 hc_ring_doorbell(hc, doorbell, target); 145 146 usb_log_debug2("HC(%p): Sent command:", hc); 144 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 145 assert(cmd); 146 147 fibril_mutex_lock(&cr->guard); 148 149 while (cr->state == XHCI_CR_STATE_CHANGING) 150 fibril_condvar_wait(&cr->state_cv, &cr->guard); 151 152 if (cr->state != XHCI_CR_STATE_OPEN) { 153 fibril_mutex_unlock(&cr->guard); 154 return ENAK; 155 } 156 157 usb_log_debug2("HC(%p): Sending command:", hc); 147 158 xhci_dump_trb(&cmd->_header.trb); 148 159 160 list_append(&cmd->_header.link, &cr->cmd_list); 161 162 xhci_trb_ring_enqueue(&cr->trb_ring, &cmd->_header.trb, &cmd->_header.trb_phys); 163 hc_ring_doorbell(hc, 0, 0); 164 165 fibril_mutex_unlock(&cr->guard); 166 149 167 return EOK; 150 168 } … … 152 170 void xhci_stop_command_ring(xhci_hc_t *hc) 153 171 { 154 assert(hc); 172 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 173 174 fibril_mutex_lock(&cr->guard); 175 176 // Prevent others from starting CR again. 177 cr->state = XHCI_CR_STATE_CLOSED; 178 fibril_condvar_broadcast(&cr->state_cv); 155 179 156 180 XHCI_REG_SET(hc->op_regs, XHCI_OP_CS, 1); 157 158 /** 159 * Note: There is a bug in qemu that checks CS only when CRCR_HI 160 * is written, this (and the read/write in abort) ensures 161 * the command rings stops. 162 */ 163 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, XHCI_REG_RD(hc->op_regs, XHCI_OP_CRCR_HI)); 164 } 165 166 void xhci_abort_command_ring(xhci_hc_t *hc) 167 { 168 assert(hc); 169 181 XHCI_REG_SET(hc->op_regs, XHCI_OP_CRCR_HI, 0); // Some systems (incl. QEMU) require 64-bit write 182 183 while (XHCI_REG_RD(hc->op_regs, XHCI_OP_CRR)) 184 fibril_condvar_wait(&cr->stopped_cv, &cr->guard); 185 186 fibril_mutex_unlock(&cr->guard); 187 } 188 189 static void abort_command_ring(xhci_hc_t *hc) 190 { 170 191 XHCI_REG_WR(hc->op_regs, XHCI_OP_CA, 1); 171 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, XHCI_REG_RD(hc->op_regs, XHCI_OP_CRCR_HI)); 172 } 173 174 void xhci_start_command_ring(xhci_hc_t *hc) 175 { 176 assert(hc); 177 178 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRR, 1); 179 hc_ring_doorbell(hc, 0, 0); 192 XHCI_REG_SET(hc->op_regs, XHCI_OP_CRCR_HI, 0); // Some systems (incl. QEMU) require 64-bit write 180 193 } 181 194 … … 233 246 int xhci_handle_command_completion(xhci_hc_t *hc, xhci_trb_t *trb) 234 247 { 235 // TODO: Update dequeue ptrs. 236 assert(hc); 248 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 237 249 assert(trb); 238 250 239 251 usb_log_debug2("HC(%p) Command completed.", hc); 240 252 241 int code; 242 uint64_t phys; 243 xhci_cmd_t *command; 244 245 code = TRB_GET_CODE(*trb); 246 phys = TRB_GET_PHYS(*trb);; 247 command = get_command(hc, phys); 253 fibril_mutex_lock(&cr->guard); 254 255 int code = TRB_GET_CODE(*trb); 256 const uint64_t phys = TRB_GET_PHYS(*trb); 257 258 xhci_trb_ring_update_dequeue(&cr->trb_ring, phys); 259 260 if (code == XHCI_TRBC_COMMAND_RING_STOPPED) { 261 /* This can either mean that the ring is being stopped, or 262 * a command was aborted. In either way, wake threads waiting 263 * on stopped_cv. 264 * 265 * Note that we need to hold mutex, because we must be sure the 266 * requesting thread is waiting inside the CV. 267 */ 268 fibril_condvar_broadcast(&cr->stopped_cv); 269 fibril_mutex_unlock(&cr->guard); 270 return EOK; 271 } 272 273 xhci_cmd_t *command = find_command(hc, phys); 248 274 if (command == NULL) { 249 // TODO: STOP & ABORT may not have command structs in the list! 250 usb_log_warning("No command struct for this completion event found."); 275 usb_log_error("No command struct for this completion event found."); 251 276 252 277 if (code != XHCI_TRBC_SUCCESS) … … 255 280 return EOK; 256 281 } 282 283 list_remove(&command->_header.link); 257 284 258 285 /* Semantics of NO_OP_CMD is that success is marked as a TRB error. */ … … 272 299 switch (TRB_TYPE(command->_header.trb)) { 273 300 case XHCI_TRB_TYPE_NO_OP_CMD: 274 break;275 301 case XHCI_TRB_TYPE_ENABLE_SLOT_CMD: 276 break;277 302 case XHCI_TRB_TYPE_DISABLE_SLOT_CMD: 278 break;279 303 case XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD: 280 break;281 304 case XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD: 282 break;283 305 case XHCI_TRB_TYPE_EVALUATE_CONTEXT_CMD: 284 break;285 306 case XHCI_TRB_TYPE_RESET_ENDPOINT_CMD: 286 307 break; … … 294 315 default: 295 316 usb_log_debug2("Unsupported command trb: %s", xhci_trb_str_type(TRB_TYPE(command->_header.trb))); 296 297 command->_header.completed = true;298 317 return ENAK; 299 318 } 319 320 fibril_mutex_unlock(&cr->guard); 300 321 301 322 fibril_mutex_lock(&command->_header.completed_mtx); … … 533 554 }; 534 555 535 static int wait_for_cmd_completion(xhci_cmd_t *cmd) 556 static int try_abort_current_command(xhci_hc_t *hc) 557 { 558 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 559 560 fibril_mutex_lock(&cr->guard); 561 562 if (cr->state != XHCI_CR_STATE_OPEN) { 563 // The CR is either stopped, or different fibril is already 564 // restarting it. 565 fibril_mutex_unlock(&cr->guard); 566 return EOK; 567 } 568 569 usb_log_error("HC(%p): Timeout while waiting for command: aborting current command.", hc); 570 571 cr->state = XHCI_CR_STATE_CHANGING; 572 fibril_condvar_broadcast(&cr->state_cv); 573 574 abort_command_ring(hc); 575 576 fibril_condvar_wait_timeout(&cr->stopped_cv, &cr->guard, XHCI_CR_ABORT_TIMEOUT); 577 578 if (XHCI_REG_RD(hc->op_regs, XHCI_OP_CRR)) { 579 /* 4.6.1.2, implementation note 580 * Assume there are larger problems with HC and 581 * reset it. 582 */ 583 usb_log_error("HC(%p): Command didn't abort.", hc); 584 585 cr->state = XHCI_CR_STATE_CLOSED; 586 fibril_condvar_broadcast(&cr->state_cv); 587 588 // TODO: Reset HC completely. 589 // Don't forget to somehow complete all commands with error. 590 591 fibril_mutex_unlock(&cr->guard); 592 return ENAK; 593 } 594 595 usb_log_error("HC(%p): Command ring stopped. Starting again.", hc); 596 hc_ring_doorbell(hc, 0, 0); 597 598 cr->state = XHCI_CR_STATE_OPEN; 599 fibril_condvar_broadcast(&cr->state_cv); 600 601 fibril_mutex_unlock(&cr->guard); 602 return EOK; 603 } 604 605 static int wait_for_cmd_completion(xhci_hc_t *hc, xhci_cmd_t *cmd) 536 606 { 537 607 int rv = EOK; … … 539 609 fibril_mutex_lock(&cmd->_header.completed_mtx); 540 610 while (!cmd->_header.completed) { 541 usb_log_debug2("Waiting for event completion: going to sleep."); 542 rv = fibril_condvar_wait_timeout(&cmd->_header.completed_cv, &cmd->_header.completed_mtx, cmd->_header.timeout); 543 544 usb_log_debug2("Waiting for event completion: woken: %s", str_error(rv)); 545 if (rv == ETIMEOUT) { 546 break; 611 612 rv = fibril_condvar_wait_timeout(&cmd->_header.completed_cv, &cmd->_header.completed_mtx, XHCI_COMMAND_TIMEOUT); 613 614 /* The waiting timed out. Current command (not necessarily 615 * ours) is probably blocked. 616 */ 617 if (!cmd->_header.completed && rv == ETIMEOUT) { 618 fibril_mutex_unlock(&cmd->_header.completed_mtx); 619 620 rv = try_abort_current_command(hc); 621 if (rv) 622 return rv; 623 624 fibril_mutex_lock(&cmd->_header.completed_mtx); 547 625 } 548 626 } … … 572 650 } 573 651 574 if ((err = wait_for_cmd_completion( cmd))) {575 /* Timeout expired or command failed. */652 if ((err = wait_for_cmd_completion(hc, cmd))) { 653 /* Command failed. */ 576 654 return err; 577 655 }
Note:
See TracChangeset
for help on using the changeset viewer.