Changeset 19f0048 in mainline
- Timestamp:
- 2018-02-01T02:13:34Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 17d34a8
- Parents:
- 53fdf8c
- Location:
- uspace
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/commands.c
r53fdf8c r19f0048 86 86 list_initialize(&cr->cmd_list); 87 87 88 cr->state = XHCI_CR_STATE_OPEN;89 90 88 return EOK; 91 89 } … … 251 249 fibril_condvar_wait(&cr->stopped_cv, &cr->guard); 252 250 251 fibril_mutex_unlock(&cr->guard); 252 } 253 254 /** 255 * Mark the command ring as stopped. NAK new commands, abort running, do not 256 * touch the HC as it's probably broken. 257 */ 258 void xhci_nuke_command_ring(xhci_hc_t *hc) 259 { 260 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 261 fibril_mutex_lock(&cr->guard); 262 // Prevent others from starting CR again. 263 cr_set_state(cr, XHCI_CR_STATE_CLOSED); 264 fibril_mutex_unlock(&cr->guard); 265 } 266 267 /** 268 * Mark the command ring as working again. 269 */ 270 void xhci_start_command_ring(xhci_hc_t *hc) 271 { 272 xhci_cmd_ring_t *cr = get_cmd_ring(hc); 273 fibril_mutex_lock(&cr->guard); 274 // Prevent others from starting CR again. 275 cr_set_state(cr, XHCI_CR_STATE_OPEN); 253 276 fibril_mutex_unlock(&cr->guard); 254 277 } -
uspace/drv/bus/usb/xhci/commands.h
r53fdf8c r19f0048 128 128 extern void xhci_fini_commands(xhci_hc_t *); 129 129 130 extern void xhci_nuke_command_ring(xhci_hc_t *); 130 131 extern void xhci_stop_command_ring(xhci_hc_t *); 131 132 extern void xhci_abort_command_ring(xhci_hc_t *); -
uspace/drv/bus/usb/xhci/hc.c
r53fdf8c r19f0048 259 259 int hc_init_memory(xhci_hc_t *hc, ddf_dev_t *device) 260 260 { 261 int err ;261 int err = ENOMEM; 262 262 263 263 if (dma_buffer_alloc(&hc->dcbaa_dma, (1 + hc->max_slots) * sizeof(uint64_t))) … … 265 265 hc->dcbaa = hc->dcbaa_dma.virt; 266 266 267 hc->event_worker = joinable_fibril_create(&event_worker, hc); 268 if (!hc->event_worker) 269 goto err_dcbaa; 270 267 271 if ((err = xhci_event_ring_init(&hc->event_ring, 1))) 268 goto err_ dcbaa;272 goto err_worker; 269 273 270 274 if ((err = xhci_scratchpad_alloc(hc))) … … 277 281 goto err_cmd; 278 282 279 hc->event_worker = joinable_fibril_create(&event_worker, hc);280 if (!hc->event_worker)281 goto err_bus;282 283 283 xhci_sw_ring_init(&hc->sw_ring, PAGE_SIZE / sizeof(xhci_trb_t)); 284 284 285 joinable_fibril_start(hc->event_worker);286 287 285 return EOK; 288 286 289 err_bus:290 xhci_bus_fini(&hc->bus);291 287 err_cmd: 292 288 xhci_fini_commands(hc); … … 295 291 err_event_ring: 296 292 xhci_event_ring_fini(&hc->event_ring); 293 err_worker: 294 joinable_fibril_destroy(hc->event_worker); 297 295 err_dcbaa: 298 296 hc->dcbaa = NULL; … … 468 466 * Initialize the HC: section 4.2 469 467 */ 470 int hc_start(xhci_hc_t *hc , bool irq)468 int hc_start(xhci_hc_t *hc) 471 469 { 472 470 int err; … … 489 487 490 488 XHCI_REG_SET(hc->op_regs, XHCI_OP_EWE, 1); 489 490 xhci_event_ring_reset(&hc->event_ring); 491 491 492 492 xhci_interrupter_regs_t *intr0 = &hc->rt_regs->ir[0]; … … 499 499 XHCI_REG_WR(intr0, XHCI_INTR_ERSTBA_HI, UPPER32(erstptr)); 500 500 501 if ( irq) {501 if (hc->base.irq_cap > 0) { 502 502 XHCI_REG_SET(intr0, XHCI_INTR_IE, 1); 503 503 XHCI_REG_SET(hc->op_regs, XHCI_OP_INTE, 1); … … 506 506 XHCI_REG_SET(hc->op_regs, XHCI_OP_HSEE, 1); 507 507 508 xhci_sw_ring_restart(&hc->sw_ring); 509 joinable_fibril_start(hc->event_worker); 510 511 xhci_start_command_ring(hc); 512 508 513 XHCI_REG_SET(hc->op_regs, XHCI_OP_RS, 1); 509 514 510 xhci_rh_startup(&hc->rh); 515 /* RH needs to access port states on startup */ 516 xhci_rh_start(&hc->rh); 511 517 512 518 return EOK; 519 } 520 521 static void hc_stop(xhci_hc_t *hc) 522 { 523 /* Stop the HC in hardware. */ 524 XHCI_REG_CLR(hc->op_regs, XHCI_OP_RS, 1); 525 526 /* 527 * Wait until the HC is halted - it shall take at most 16 ms. 528 * Note that we ignore the return value here. 529 */ 530 xhci_reg_wait(&hc->op_regs->usbsts, XHCI_REG_MASK(XHCI_OP_HCH), 531 XHCI_REG_MASK(XHCI_OP_HCH)); 532 533 /* Make sure commands will not block other fibrils. */ 534 xhci_nuke_command_ring(hc); 535 536 /* Stop the event worker fibril to restart it */ 537 xhci_sw_ring_stop(&hc->sw_ring); 538 joinable_fibril_join(hc->event_worker); 539 540 /* Then, disconnect all roothub devices, which shall trigger 541 * disconnection of everything */ 542 xhci_rh_stop(&hc->rh); 543 } 544 545 static void hc_reinitialize(xhci_hc_t *hc) 546 { 547 /* Stop everything. */ 548 hc_stop(hc); 549 550 usb_log_info("HC stopped. Starting again..."); 551 552 /* The worker fibrils need to be started again */ 553 joinable_fibril_recreate(hc->event_worker); 554 joinable_fibril_recreate(hc->rh.event_worker); 555 556 /* Now, the HC shall be stopped and software shall be clean. */ 557 hc_start(hc); 558 } 559 560 static bool hc_is_broken(xhci_hc_t *hc) 561 { 562 const uint32_t usbcmd = XHCI_REG_RD_FIELD(&hc->op_regs->usbcmd, 32); 563 const uint32_t usbsts = XHCI_REG_RD_FIELD(&hc->op_regs->usbsts, 32); 564 565 return !(usbcmd & XHCI_REG_MASK(XHCI_OP_RS)) 566 || (usbsts & XHCI_REG_MASK(XHCI_OP_HCE)) 567 || (usbsts & XHCI_REG_MASK(XHCI_OP_HSE)); 513 568 } 514 569 … … 622 677 hc->event_handler = 0; 623 678 624 /* Update the ERDP to make room in the ring. */625 679 uint64_t erdp = hc->event_ring.dequeue_ptr; 626 680 erdp |= XHCI_REG_MASK(XHCI_INTR_ERDP_EHB); … … 646 700 647 701 if (status & XHCI_REG_MASK(XHCI_OP_HSE)) { 648 usb_log_error("Host controller error occured. Bad things gonna happen..."); 649 status &= ~XHCI_REG_MASK(XHCI_OP_HSE); 702 usb_log_error("Host system error occured. Aren't we supposed to be dead already?"); 703 return; 704 } 705 706 if (status & XHCI_REG_MASK(XHCI_OP_HCE)) { 707 usb_log_error("Host controller error occured. Reinitializing..."); 708 hc_reinitialize(hc); 709 return; 650 710 } 651 711 … … 676 736 void hc_fini(xhci_hc_t *hc) 677 737 { 678 xhci_sw_ring_stop(&hc->sw_ring);679 joinable_fibril_join(hc->event_worker); 738 hc_stop(hc); 739 680 740 xhci_sw_ring_fini(&hc->sw_ring); 681 741 joinable_fibril_destroy(hc->event_worker); 682 742 xhci_bus_fini(&hc->bus); 683 743 xhci_event_ring_fini(&hc->event_ring); … … 882 942 xhci_hc_t * const hc = bus_to_hc(dev->base.bus); 883 943 944 if (hc_is_broken(hc)) 945 return EOK; 946 884 947 /* Issue configure endpoint command (sec 4.3.5) with the DC flag. */ 885 948 return xhci_cmd_sync_inline(hc, CONFIGURE_ENDPOINT, … … 930 993 { 931 994 xhci_device_t * const dev = xhci_ep_to_dev(ep); 995 xhci_hc_t * const hc = bus_to_hc(dev->base.bus); 932 996 const unsigned dci = endpoint_dci(ep); 997 998 if (hc_is_broken(hc)) 999 return EOK; 933 1000 934 1001 /* Issue configure endpoint command (sec 4.3.5). */ … … 938 1005 return err; 939 1006 940 xhci_hc_t * const hc = bus_to_hc(dev->base.bus);941 1007 xhci_input_ctx_t *ictx = ictx_dma_buf.virt; 942 1008 XHCI_INPUT_CTRL_CTX_DROP_SET(*XHCI_GET_CTRL_CTX(ictx, hc), dci); … … 992 1058 const unsigned dci = endpoint_dci(ep); 993 1059 xhci_hc_t * const hc = bus_to_hc(dev->base.bus); 1060 1061 if (hc_is_broken(hc)) 1062 return EOK; 1063 994 1064 return xhci_cmd_sync_inline(hc, STOP_ENDPOINT, 995 1065 .slot_id = dev->slot_id, -
uspace/drv/bus/usb/xhci/hc.h
r53fdf8c r19f0048 116 116 extern int hc_claim(xhci_hc_t *, ddf_dev_t *); 117 117 extern int hc_irq_code_gen(irq_code_t *, xhci_hc_t *, const hw_res_list_parsed_t *, int *); 118 extern int hc_start(xhci_hc_t * , bool);118 extern int hc_start(xhci_hc_t *); 119 119 extern void hc_fini(xhci_hc_t *); 120 120 -
uspace/drv/bus/usb/xhci/main.c
r53fdf8c r19f0048 83 83 { 84 84 xhci_hc_t *hc = hcd_to_hc(hcd); 85 return hc_start(hc , hcd->irq_cap >= 0);85 return hc_start(hc); 86 86 } 87 87 -
uspace/drv/bus/usb/xhci/rh.c
r53fdf8c r19f0048 113 113 xhci_sw_ring_init(&rh->event_ring, rh->max_ports); 114 114 115 joinable_fibril_start(rh->event_worker);116 117 115 return EOK; 118 116 } … … 290 288 } 291 289 292 void xhci_rh_startup(xhci_rh_t *rh) 293 { 290 void xhci_rh_start(xhci_rh_t *rh) 291 { 292 xhci_sw_ring_restart(&rh->event_ring); 293 joinable_fibril_start(rh->event_worker); 294 294 295 /* The reset changed status of all ports, and SW originated reason does 295 296 * not cause an interrupt. … … 311 312 } 312 313 314 /** 315 * Disconnect all devices on all ports. On contrary to ordinary disconnect, this 316 * function waits until the disconnection routine is over. 317 */ 318 void xhci_rh_stop(xhci_rh_t *rh) 319 { 320 xhci_sw_ring_stop(&rh->event_ring); 321 joinable_fibril_join(rh->event_worker); 322 323 for (uint8_t i = 0; i < rh->max_ports; ++i) { 324 rh_port_t * const port = &rh->ports[i]; 325 usb_port_disabled(&port->base, &rh_remove_device); 326 usb_port_fini(&port->base); 327 } 328 } 329 313 330 static int rh_worker(void *arg) 314 331 { -
uspace/drv/bus/usb/xhci/rh.h
r53fdf8c r19f0048 85 85 86 86 extern void xhci_rh_set_ports_protocol(xhci_rh_t *, unsigned, unsigned, unsigned); 87 extern void xhci_rh_startup(xhci_rh_t *); 87 extern void xhci_rh_start(xhci_rh_t *); 88 extern void xhci_rh_stop(xhci_rh_t *rh); 88 89 89 90 #endif -
uspace/drv/bus/usb/xhci/trb_ring.c
r53fdf8c r19f0048 188 188 static uintptr_t trb_ring_enqueue_phys(xhci_trb_ring_t *ring) 189 189 { 190 uintptr_t trb_id = ring->enqueue_trb - segment_begin(ring->enqueue_segment);190 size_t trb_id = ring->enqueue_trb - segment_begin(ring->enqueue_segment); 191 191 return ring->enqueue_segment->phys + trb_id * sizeof(xhci_trb_t); 192 192 } … … 346 346 } 347 347 348 fibril_mutex_initialize(&ring->guard); 349 350 usb_log_debug("Initialized event ring."); 351 return EOK; 352 } 353 354 void xhci_event_ring_reset(xhci_event_ring_t *ring) 355 { 356 list_foreach(ring->segments, segments_link, trb_segment_t, segment) 357 memset(segment->trb_storage, 0, sizeof(segment->trb_storage)); 358 348 359 trb_segment_t * const segment = get_first_segment(&ring->segments); 349 360 ring->dequeue_segment = segment; … … 351 362 ring->dequeue_ptr = segment->phys; 352 363 ring->ccs = 1; 353 354 fibril_mutex_initialize(&ring->guard);355 356 usb_log_debug("Initialized event ring.");357 return EOK;358 364 } 359 365 … … 432 438 ring->end = ring->begin + size; 433 439 434 ring->enqueue = ring->dequeue = ring->begin;435 436 440 fibril_mutex_initialize(&ring->guard); 437 441 fibril_condvar_initialize(&ring->enqueued_cv); 438 442 fibril_condvar_initialize(&ring->dequeued_cv); 439 443 440 ring->running = true;444 xhci_sw_ring_restart(ring); 441 445 } 442 446 … … 486 490 } 487 491 492 void xhci_sw_ring_restart(xhci_sw_ring_t *ring) 493 { 494 ring->enqueue = ring->dequeue = ring->begin; 495 memset(ring->begin, 0, sizeof(xhci_trb_t) * (ring->end - ring->begin)); 496 ring->running = true; 497 } 498 488 499 void xhci_sw_ring_fini(xhci_sw_ring_t *ring) 489 500 { -
uspace/drv/bus/usb/xhci/trb_ring.h
r53fdf8c r19f0048 109 109 extern int xhci_event_ring_init(xhci_event_ring_t *, size_t); 110 110 extern void xhci_event_ring_fini(xhci_event_ring_t *); 111 extern void xhci_event_ring_reset(xhci_event_ring_t *); 111 112 extern int xhci_event_ring_dequeue(xhci_event_ring_t *, xhci_trb_t *); 112 113 … … 130 131 extern int xhci_sw_ring_dequeue(xhci_sw_ring_t *, xhci_trb_t *); 131 132 133 extern void xhci_sw_ring_restart(xhci_sw_ring_t *); 132 134 extern void xhci_sw_ring_stop(xhci_sw_ring_t *); 133 135 extern void xhci_sw_ring_fini(xhci_sw_ring_t *); -
uspace/lib/usbhost/include/usb/host/utility.h
r53fdf8c r19f0048 63 63 void joinable_fibril_join(joinable_fibril_t *); 64 64 void joinable_fibril_destroy(joinable_fibril_t *); 65 errno_t joinable_fibril_recreate(joinable_fibril_t *); 65 66 66 67 -
uspace/lib/usbhost/src/utility.c
r53fdf8c r19f0048 297 297 { 298 298 joinable_fibril_t *jf = arg; 299 299 300 jf->worker(jf->arg); 300 301 … … 315 316 return NULL; 316 317 317 jf->fid = fibril_create(joinable_fibril_worker, jf);318 if (!jf->fid) {319 free(jf);320 return NULL;321 }322 323 318 jf->worker = worker; 324 319 jf->arg = arg; … … 326 321 fibril_condvar_initialize(&jf->dead_cv); 327 322 323 if (joinable_fibril_recreate(jf)) { 324 free(jf); 325 return NULL; 326 } 327 328 328 return jf; 329 329 } 330 331 330 332 331 /** … … 353 352 fibril_condvar_wait(&jf->dead_cv, &jf->guard); 354 353 fibril_mutex_unlock(&jf->guard); 354 355 jf->fid = 0; 356 } 357 358 /** 359 * Reinitialize a joinable fibril. 360 */ 361 errno_t joinable_fibril_recreate(joinable_fibril_t *jf) 362 { 363 assert(!jf->fid); 364 365 jf->fid = fibril_create(joinable_fibril_worker, jf); 366 return jf->fid ? EOK : ENOMEM; 355 367 } 356 368
Note:
See TracChangeset
for help on using the changeset viewer.