Changeset 889146e in mainline
- Timestamp:
- 2017-12-10T21:49:12Z (7 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)
- Location:
- uspace/drv/bus/usb/xhci
- Files:
-
- 5 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 } -
uspace/drv/bus/usb/xhci/commands.h
r6ef407b r889146e 42 42 #include <usb/host/dma_buffer.h> 43 43 #include "hw_struct/trb.h" 44 #include "trb_ring.h" 44 45 45 #define XHCI_ DEFAULT_TIMEOUT 100000046 #define XHCI_ BLOCK_INDEFINITELY046 #define XHCI_COMMAND_TIMEOUT 10000 47 #define XHCI_CR_ABORT_TIMEOUT 5000 47 48 48 49 typedef struct xhci_hc xhci_hc_t; … … 68 69 } xhci_cmd_type_t; 69 70 71 typedef enum { 72 XHCI_CR_STATE_CLOSED, /**< Commands are rejected with ENAK. */ 73 XHCI_CR_STATE_OPEN, /**< Commands are enqueued normally. */ 74 XHCI_CR_STATE_CHANGING, /**< Commands wait until state changes. */ 75 } xhci_cr_state; 76 77 typedef struct xhci_command_ring { 78 xhci_trb_ring_t trb_ring; 79 80 fibril_mutex_t guard; /**< Guard access to this structure. */ 81 list_t cmd_list; 82 83 xhci_cr_state state; /**< Whether commands are allowed to be 84 added. */ 85 fibril_condvar_t state_cv; /**< For waiting on CR state change. */ 86 87 fibril_condvar_t stopped_cv; /**< For waiting on CR stopped event. */ 88 } xhci_cmd_ring_t; 89 70 90 typedef struct xhci_command { 71 91 /** Internal fields used for bookkeeping. Need not worry about these. */ … … 74 94 75 95 xhci_cmd_type_t cmd; 76 suseconds_t timeout;77 96 78 97 xhci_trb_t trb; … … 130 149 fibril_condvar_initialize(&cmd._header.completed_cv); 131 150 132 if (!cmd._header.timeout) {133 cmd._header.timeout = XHCI_DEFAULT_TIMEOUT;134 }135 136 151 /* Issue the command */ 137 152 const int err = xhci_cmd_sync(hc, &cmd); -
uspace/drv/bus/usb/xhci/hc.c
r6ef407b r889146e 44 44 #include "hw_struct/context.h" 45 45 #include "endpoint.h" 46 #include "commands.h"47 46 #include "transfers.h" 48 47 #include "trb_ring.h" … … 204 203 hc->dcbaa = hc->dcbaa_dma.virt; 205 204 206 if ((err = xhci_ trb_ring_init(&hc->command_ring)))205 if ((err = xhci_event_ring_init(&hc->event_ring))) 207 206 goto err_dcbaa; 208 209 if ((err = xhci_event_ring_init(&hc->event_ring)))210 goto err_cmd_ring;211 207 212 208 if ((err = xhci_scratchpad_alloc(hc))) … … 233 229 err_event_ring: 234 230 xhci_event_ring_fini(&hc->event_ring); 235 err_cmd_ring:236 xhci_trb_ring_fini(&hc->command_ring);237 231 err_dcbaa: 238 232 hc->dcbaa = NULL; … … 399 393 return err; 400 394 395 // FIXME: Waiting forever. 401 396 while (XHCI_REG_RD(hc->op_regs, XHCI_OP_CNR)) 402 397 async_usleep(1000); … … 407 402 XHCI_REG_WR(hc->op_regs, XHCI_OP_MAX_SLOTS_EN, 0); 408 403 409 uint64_t crptr = xhci_trb_ring_get_dequeue_ptr(&hc->c ommand_ring);404 uint64_t crptr = xhci_trb_ring_get_dequeue_ptr(&hc->cr.trb_ring); 410 405 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_LO, LOWER32(crptr) >> 6); 411 406 XHCI_REG_WR(hc->op_regs, XHCI_OP_CRCR_HI, UPPER32(crptr)); … … 578 573 { 579 574 xhci_bus_fini(&hc->bus); 580 xhci_trb_ring_fini(&hc->command_ring);581 575 xhci_event_ring_fini(&hc->event_ring); 582 576 hc_dcbaa_fini(hc); -
uspace/drv/bus/usb/xhci/hc.h
r6ef407b r889146e 45 45 46 46 #include "rh.h" 47 #include "commands.h" 47 48 #include "bus.h" 49 50 typedef struct xhci_command xhci_cmd_t; 48 51 49 52 typedef struct xhci_hc { … … 61 64 62 65 /* Structures in allocated memory */ 63 xhci_trb_ring_t command_ring;64 66 xhci_event_ring_t event_ring; 65 67 uint64_t *dcbaa; … … 67 69 dma_buffer_t scratchpad_array; 68 70 dma_buffer_t *scratchpad_buffers; 71 72 /* Command ring management */ 73 xhci_cmd_ring_t cr; 69 74 70 75 /* Root hub emulation */ … … 81 86 xhci_port_speed_t speeds [16]; 82 87 uint8_t speed_to_psiv [USB_SPEED_MAX]; 83 84 /* Command list */85 list_t commands;86 fibril_mutex_t commands_mtx;87 88 88 89 /* TODO: Hack. Figure out a better way. */ -
uspace/drv/bus/usb/xhci/trb_ring.h
r6ef407b r889146e 91 91 * pointer inside the ring. Otherwise, the ring will soon show up as full. 92 92 */ 93 void xhci_trb_ring_update_dequeue(xhci_trb_ring_t *, uintptr_t); 93 static inline void xhci_trb_ring_update_dequeue(xhci_trb_ring_t *ring, uintptr_t phys) {} 94 94 uintptr_t xhci_trb_ring_get_dequeue_ptr(xhci_trb_ring_t *); 95 95
Note:
See TracChangeset
for help on using the changeset viewer.