1 /* 2 * Copyright 2006-2011, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Some code borrowed from the Haiku EHCI driver 6 * 7 * Authors: 8 * Michael Lotz <mmlr@mlotz.ch> 9 * Jian Chiang <j.jian.chiang@gmail.com> 10 */ 11 12 13 #include <module.h> 14 #include <PCI.h> 15 #include <USB3.h> 16 #include <KernelExport.h> 17 18 #define TRACE_USB 19 #include "xhci.h" 20 21 #define USB_MODULE_NAME "xhci" 22 23 pci_module_info *XHCI::sPCIModule = NULL; 24 25 26 static int32 27 xhci_std_ops(int32 op, ...) 28 { 29 switch (op) { 30 case B_MODULE_INIT: 31 TRACE_MODULE("xhci init module\n"); 32 return B_OK; 33 case B_MODULE_UNINIT: 34 TRACE_MODULE("xhci uninit module\n"); 35 return B_OK; 36 } 37 38 return EINVAL; 39 } 40 41 42 usb_host_controller_info xhci_module = { 43 { 44 "busses/usb/xhci", 45 0, 46 xhci_std_ops 47 }, 48 NULL, 49 XHCI::AddTo 50 }; 51 52 53 module_info *modules[] = { 54 (module_info *)&xhci_module, 55 NULL 56 }; 57 58 59 XHCI::XHCI(pci_info *info, Stack *stack) 60 : BusManager(stack), 61 fCapabilityRegisters(NULL), 62 fOperationalRegisters(NULL), 63 fRegisterArea(-1), 64 fPCIInfo(info), 65 fStack(stack), 66 fErstArea(-1), 67 fDcbaArea(-1), 68 fSpinlock(B_SPINLOCK_INITIALIZER), 69 fCmdCompSem(-1), 70 fCmdCompThread(-1), 71 fFinishTransfersSem(-1), 72 fFinishThread(-1), 73 fStopThreads(false), 74 fRootHub(NULL), 75 fRootHubAddress(0), 76 fPortCount(0), 77 fSlotCount(0), 78 fEventIdx(0), 79 fCmdIdx(0), 80 fEventCcs(1), 81 fCmdCcs(1) 82 { 83 if (BusManager::InitCheck() < B_OK) { 84 TRACE_ERROR("bus manager failed to init\n"); 85 return; 86 } 87 88 TRACE("constructing new XHCI host controller driver\n"); 89 fInitOK = false; 90 91 // enable busmaster and memory mapped access 92 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, 93 fPCIInfo->device, fPCIInfo->function, PCI_command, 2); 94 command &= ~(PCI_command_io | PCI_command_int_disable); 95 command |= PCI_command_master | PCI_command_memory; 96 97 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 98 fPCIInfo->function, PCI_command, 2, command); 99 100 // map the registers 101 uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1); 102 addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset; 103 size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset 104 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 105 106 TRACE("map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n", 107 fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, 108 fPCIInfo->u.h0.base_register_sizes[0]); 109 110 fRegisterArea = map_physical_memory("XHCI memory mapped registers", 111 physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS, 112 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, 113 (void **)&fCapabilityRegisters); 114 if (fRegisterArea < B_OK) { 115 TRACE("failed to map register memory\n"); 116 return; 117 } 118 119 fCapabilityRegisters += offset; 120 fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(XHCI_CAPLENGTH); 121 fRuntimeRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_RTSOFF); 122 fDoorbellRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_DBOFF); 123 TRACE("mapped capability registers: 0x%08lx\n", (uint32)fCapabilityRegisters); 124 TRACE("mapped operational registers: 0x%08lx\n", (uint32)fOperationalRegisters); 125 TRACE("mapped rumtime registers: 0x%08lx\n", (uint32)fRuntimeRegisters); 126 TRACE("mapped doorbell registers: 0x%08lx\n", (uint32)fDoorbellRegisters); 127 128 TRACE("structural parameters1: 0x%08lx\n", ReadCapReg32(XHCI_HCSPARAMS1)); 129 TRACE("structural parameters2: 0x%08lx\n", ReadCapReg32(XHCI_HCSPARAMS2)); 130 TRACE("structural parameters3: 0x%08lx\n", ReadCapReg32(XHCI_HCSPARAMS3)); 131 TRACE("capability parameters: 0x%08lx\n", ReadCapReg32(XHCI_HCCPARAMS)); 132 133 uint32 cparams = ReadCapReg32(XHCI_HCCPARAMS); 134 uint32 eec = 0xffffffff; 135 uint32 eecp = HCS0_XECP(cparams) << 2; 136 for (; eecp != 0 && XECP_NEXT(eec); eecp += XECP_NEXT(eec) << 2) { 137 eec = ReadCapReg32(eecp); 138 if (XECP_ID(eec) != XHCI_LEGSUP_CAPID) 139 continue; 140 } 141 if (eec & XHCI_LEGSUP_BIOSOWNED) { 142 TRACE_ALWAYS("the host controller is bios owned, claiming" 143 " ownership\n"); 144 WriteCapReg32(eecp, eec | XHCI_LEGSUP_OSOWNED); 145 146 for (int32 i = 0; i < 20; i++) { 147 eec = ReadCapReg32(eecp); 148 149 if ((eec & XHCI_LEGSUP_BIOSOWNED) == 0) 150 break; 151 152 TRACE_ALWAYS("controller is still bios owned, waiting\n"); 153 snooze(50000); 154 } 155 156 if (eec & XHCI_LEGSUP_BIOSOWNED) { 157 TRACE_ERROR("bios won't give up control over the host " 158 "controller (ignoring)\n"); 159 } else if (eec & XHCI_LEGSUP_OSOWNED) { 160 TRACE_ALWAYS("successfully took ownership of the host " 161 "controller\n"); 162 } 163 164 // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes 165 // do indicate a successful handover but do not remove their SMIs 166 // and then freeze the system when interrupts are generated. 167 WriteCapReg32(eecp, eec & ~XHCI_LEGSUP_BIOSOWNED); 168 } 169 WriteCapReg32(eecp + XHCI_LEGCTLSTS, XHCI_LEGCTLSTS_DISABLE_SMI); 170 171 // halt the host controller 172 if (ControllerHalt() < B_OK) { 173 return; 174 } 175 176 // reset the host controller 177 if (ControllerReset() < B_OK) { 178 TRACE_ERROR("host controller failed to reset\n"); 179 return; 180 } 181 182 fCmdCompSem = create_sem(0, "XHCI Command Complete"); 183 fFinishTransfersSem = create_sem(0, "XHCI Finish Transfers"); 184 if (fFinishTransfersSem < B_OK || fCmdCompSem < B_OK) { 185 TRACE_ERROR("failed to create semaphores\n"); 186 return; 187 } 188 189 // create finisher service thread 190 fFinishThread = spawn_kernel_thread(FinishThread, "xhci finish thread", 191 B_NORMAL_PRIORITY, (void *)this); 192 resume_thread(fFinishThread); 193 194 // create command complete service thread 195 fCmdCompThread = spawn_kernel_thread(CmdCompThread, "xhci cmd complete thread", 196 B_NORMAL_PRIORITY, (void *)this); 197 resume_thread(fCmdCompThread); 198 199 // Install the interrupt handler 200 TRACE("installing interrupt handler\n"); 201 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 202 InterruptHandler, (void *)this, 0); 203 204 fInitOK = true; 205 TRACE("XHCI host controller driver constructed\n"); 206 } 207 208 209 XHCI::~XHCI() 210 { 211 TRACE("tear down XHCI host controller driver\n"); 212 213 WriteOpReg(XHCI_CMD, 0); 214 215 int32 result = 0; 216 fStopThreads = true; 217 delete_sem(fCmdCompSem); 218 delete_sem(fFinishTransfersSem); 219 delete_area(fRegisterArea); 220 delete_area(fErstArea); 221 delete_area(fDcbaArea); 222 wait_for_thread(fCmdCompThread, &result); 223 wait_for_thread(fFinishThread, &result); 224 put_module(B_PCI_MODULE_NAME); 225 } 226 227 228 status_t 229 XHCI::Start() 230 { 231 TRACE("starting XHCI host controller\n"); 232 TRACE("usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(XHCI_CMD), 233 ReadOpReg(XHCI_STS)); 234 235 if ((ReadOpReg(XHCI_PAGESIZE) & (1 << 0)) == 0) { 236 TRACE_ERROR("Controller does not support 4K page size.\n"); 237 return B_ERROR; 238 } 239 240 // read port count from capability register 241 uint32 capabilities = ReadCapReg32(XHCI_HCSPARAMS1); 242 243 uint8 portsCount = HCS_MAX_PORTS(capabilities); 244 if (portsCount == 0) { 245 TRACE_ERROR("Invalid number of ports: %u\n", portsCount); 246 return B_ERROR; 247 } 248 fPortCount = portsCount; 249 fSlotCount = HCS_MAX_SLOTS(capabilities); 250 WriteOpReg(XHCI_CONFIG, fSlotCount); 251 252 void *dmaAddress; 253 fDcbaArea = fStack->AllocateArea((void **)&fDcba, &dmaAddress, 254 sizeof(uint64) * XHCI_MAX_SLOTS, "DCBA Area"); 255 if (fDcbaArea < B_OK) { 256 TRACE_ERROR("unable to create the DCBA area\n"); 257 return B_ERROR; 258 } 259 memset(fDcba, 0, sizeof(uint64) * XHCI_MAX_SLOTS); 260 TRACE("setting DCBAAP\n"); 261 WriteOpReg(XHCI_DCBAAP_LO, (uint32)dmaAddress); 262 WriteOpReg(XHCI_DCBAAP_HI, 0); 263 264 fErstArea = fStack->AllocateArea((void **)&fErst, &dmaAddress, 265 (MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb) 266 + sizeof(xhci_erst_element), 267 "USB XHCI ERST CMD_RING and EVENT_RING Area"); 268 269 if (fErstArea < B_OK) { 270 TRACE_ERROR("unable to create the ERST AND RING area\n"); 271 delete_area(fDcbaArea); 272 return B_ERROR; 273 } 274 memset(fErst, 0, (MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb) 275 + sizeof(xhci_erst_element)); 276 277 fErst->rs_addr = (uint32)dmaAddress + sizeof(xhci_erst_element); 278 fErst->rs_size = MAX_EVENTS; 279 fErst->rsvdz = 0; 280 281 uint32 addr = (uint32)fErst + sizeof(xhci_erst_element); 282 fEventRing = (xhci_trb *)addr; 283 addr += MAX_EVENTS * sizeof(xhci_trb); 284 fCmdRing = (xhci_trb *)addr; 285 286 TRACE("setting ERST size\n"); 287 WriteRunReg32(XHCI_ERSTSZ(0), XHCI_ERSTS_SET(1)); 288 289 TRACE("setting ERDP addr = 0x%llx\n", fErst->rs_addr); 290 WriteRunReg32(XHCI_ERDP_LO(0), (uint32)fErst->rs_addr); 291 WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(fErst->rs_addr >> 32)); 292 293 TRACE("setting ERST base addr = 0x%llx\n", (uint64)dmaAddress); 294 WriteRunReg32(XHCI_ERSTBA_LO(0), (uint32)dmaAddress); 295 WriteRunReg32(XHCI_ERSTBA_HI(0), 0); 296 297 addr = fErst->rs_addr + MAX_EVENTS * sizeof(xhci_trb); 298 TRACE("setting CRCR addr = 0x%llx\n", (uint64)addr); 299 WriteOpReg(XHCI_CRCR_LO, addr | CRCR_RCS); 300 WriteOpReg(XHCI_CRCR_HI, 0); 301 //link trb 302 fCmdRing[MAX_COMMANDS - 1].qwtrb0 = addr; 303 304 TRACE("setting interrupt rate\n"); 305 WriteRunReg32(XHCI_IMOD(0), 160);//4000 irq/s 306 307 TRACE("enabling interrupt\n"); 308 WriteRunReg32(XHCI_IMAN(0), ReadRunReg32(XHCI_IMAN(0)) | IMAN_INTR_ENA); 309 310 WriteOpReg(XHCI_CMD, CMD_RUN | CMD_EIE | CMD_HSEIE); 311 312 fRootHubAddress = AllocateAddress(); 313 fRootHub = new(std::nothrow) XHCIRootHub(RootObject(), fRootHubAddress); 314 if (!fRootHub) { 315 TRACE_ERROR("no memory to allocate root hub\n"); 316 return B_NO_MEMORY; 317 } 318 319 if (fRootHub->InitCheck() < B_OK) { 320 TRACE_ERROR("root hub failed init check\n"); 321 return fRootHub->InitCheck(); 322 } 323 324 SetRootHub(fRootHub); 325 326 TRACE_ALWAYS("successfully started the controller\n"); 327 TRACE("No-Op test\n"); 328 QueueNoop(); 329 return BusManager::Start(); 330 } 331 332 333 status_t 334 XHCI::SubmitTransfer(Transfer *transfer) 335 { 336 // short circuit the root hub 337 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 338 return fRootHub->ProcessTransfer(this, transfer); 339 340 return B_OK; 341 } 342 343 344 status_t 345 XHCI::CancelQueuedTransfers(Pipe *pipe, bool force) 346 { 347 return B_OK; 348 } 349 350 351 status_t 352 XHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 353 { 354 TRACE("pipe change %d for pipe %p\n", change, pipe); 355 switch (change) { 356 case USB_CHANGE_CREATED: 357 case USB_CHANGE_DESTROYED: { 358 // ToDo: we should create and keep a single queue head 359 // for all transfers to/from this pipe 360 break; 361 } 362 363 case USB_CHANGE_PIPE_POLICY_CHANGED: { 364 // ToDo: for isochronous pipes we might need to adapt to new 365 // pipe policy settings here 366 break; 367 } 368 } 369 370 return B_OK; 371 } 372 373 374 status_t 375 XHCI::AddTo(Stack *stack) 376 { 377 #ifdef TRACE_USB 378 set_dprintf_enabled(true); 379 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 380 load_driver_symbols("xhci"); 381 #endif 382 #endif 383 384 if (!sPCIModule) { 385 status_t status = get_module(B_PCI_MODULE_NAME, 386 (module_info **)&sPCIModule); 387 if (status < B_OK) { 388 TRACE_MODULE_ERROR("getting pci module failed! 0x%08lx\n", status); 389 return status; 390 } 391 } 392 393 TRACE_MODULE("searching devices\n"); 394 bool found = false; 395 pci_info *item = new(std::nothrow) pci_info; 396 if (!item) { 397 sPCIModule = NULL; 398 put_module(B_PCI_MODULE_NAME); 399 return B_NO_MEMORY; 400 } 401 402 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 403 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 404 && item->class_api == PCI_usb_xhci) { 405 if (item->u.h0.interrupt_line == 0 406 || item->u.h0.interrupt_line == 0xFF) { 407 TRACE_MODULE_ERROR("found device with invalid IRQ - check IRQ " 408 "assignment\n"); 409 continue; 410 } 411 412 TRACE_MODULE("found device at IRQ %u\n", 413 item->u.h0.interrupt_line); 414 XHCI *bus = new(std::nothrow) XHCI(item, stack); 415 if (!bus) { 416 delete item; 417 sPCIModule = NULL; 418 put_module(B_PCI_MODULE_NAME); 419 return B_NO_MEMORY; 420 } 421 422 if (bus->InitCheck() < B_OK) { 423 TRACE_MODULE_ERROR("bus failed init check\n"); 424 delete bus; 425 continue; 426 } 427 428 // the bus took it away 429 item = new(std::nothrow) pci_info; 430 431 bus->Start(); 432 stack->AddBusManager(bus); 433 found = true; 434 } 435 } 436 437 if (!found) { 438 TRACE_MODULE_ERROR("no devices found\n"); 439 delete item; 440 sPCIModule = NULL; 441 put_module(B_PCI_MODULE_NAME); 442 return ENODEV; 443 } 444 445 delete item; 446 return B_OK; 447 } 448 449 450 status_t 451 XHCI::GetPortStatus(uint8 index, usb_port_status *status) 452 { 453 if (index >= fPortCount) 454 return B_BAD_INDEX; 455 456 status->status = status->change = 0; 457 uint32 portStatus = ReadOpReg(XHCI_PORTSC(index)); 458 TRACE("port status=0x%08lx\n", portStatus); 459 460 // build the status 461 switch(PS_SPEED_GET(portStatus)) { 462 case 3: 463 status->status |= PORT_STATUS_HIGH_SPEED; 464 break; 465 case 2: 466 status->status |= PORT_STATUS_LOW_SPEED; 467 break; 468 default: 469 break; 470 } 471 472 if (portStatus & PS_CCS) 473 status->status |= PORT_STATUS_CONNECTION; 474 if (portStatus & PS_PED) 475 status->status |= PORT_STATUS_ENABLE; 476 if (portStatus & PS_OCA) 477 status->status |= PORT_STATUS_OVER_CURRENT; 478 if (portStatus & PS_PR) 479 status->status |= PORT_STATUS_RESET; 480 if (portStatus & PS_PP) 481 status->status |= PORT_STATUS_POWER; 482 483 // build the change 484 if (portStatus & PS_CSC) 485 status->change |= PORT_STATUS_CONNECTION; 486 if (portStatus & PS_PEC) 487 status->change |= PORT_STATUS_ENABLE; 488 if (portStatus & PS_OCC) 489 status->change |= PORT_STATUS_OVER_CURRENT; 490 if (portStatus & PS_PRC) 491 status->change |= PORT_STATUS_RESET; 492 493 return B_OK; 494 } 495 496 497 status_t 498 XHCI::SetPortFeature(uint8 index, uint16 feature) 499 { 500 TRACE("set port feature index %u feature %u\n", index, feature); 501 if (index >= fPortCount) 502 return B_BAD_INDEX; 503 504 uint32 portRegister = XHCI_PORTSC(index); 505 uint32 portStatus = ReadOpReg(portRegister); 506 507 switch (feature) { 508 case PORT_SUSPEND: 509 if ((portStatus & PS_PED ) == 0 || (portStatus & PS_PR) 510 || (portStatus & PS_PLS_MASK) >= PS_XDEV_U3) { 511 TRACE_ERROR("USB core suspending device not in U0/U1/U2.\n"); 512 return B_BAD_VALUE; 513 } 514 portStatus &= ~PS_CLEAR; 515 portStatus &= ~PS_PLS_MASK; 516 portStatus |= PS_LWS | PS_XDEV_U3; 517 WriteOpReg(portRegister, portStatus); 518 return B_OK; 519 520 case PORT_RESET: 521 portStatus &= ~PS_CLEAR; 522 WriteOpReg(portRegister, portStatus | PS_PR); 523 return B_OK; 524 525 case PORT_POWER: 526 portStatus &= ~PS_CLEAR; 527 WriteOpReg(portRegister, portStatus | PS_PP); 528 return B_OK; 529 } 530 return B_BAD_VALUE; 531 } 532 533 534 status_t 535 XHCI::ClearPortFeature(uint8 index, uint16 feature) 536 { 537 TRACE("clear port feature index %u feature %u\n", index, feature); 538 if (index >= fPortCount) 539 return B_BAD_INDEX; 540 541 uint32 portRegister = XHCI_PORTSC(index); 542 uint32 portStatus = ReadOpReg(portRegister); 543 portStatus &= ~PS_CLEAR; 544 545 switch (feature) { 546 case PORT_SUSPEND: 547 portStatus = ReadOpReg(portRegister); 548 if (portStatus & PS_PR) 549 return B_BAD_VALUE; 550 if (portStatus & PS_XDEV_U3) { 551 if ((portStatus & PS_PED) == 0) 552 return B_BAD_VALUE; 553 portStatus &= ~PS_CLEAR; 554 portStatus &= ~PS_PLS_MASK; 555 WriteOpReg(portRegister, portStatus | PS_XDEV_U0 | PS_LWS); 556 } 557 return B_OK; 558 case PORT_ENABLE: 559 WriteOpReg(portRegister, portStatus | PS_PED); 560 return B_OK; 561 case PORT_POWER: 562 WriteOpReg(portRegister, portStatus & ~PS_PP); 563 return B_OK; 564 case C_PORT_CONNECTION: 565 WriteOpReg(portRegister, portStatus | PS_CSC); 566 return B_OK; 567 case C_PORT_ENABLE: 568 WriteOpReg(portRegister, portStatus | PS_PEC); 569 return B_OK; 570 case C_PORT_OVER_CURRENT: 571 WriteOpReg(portRegister, portStatus | PS_OCC); 572 return B_OK; 573 case C_PORT_RESET: 574 WriteOpReg(portRegister, portStatus | PS_PRC); 575 return B_OK; 576 } 577 578 return B_BAD_VALUE; 579 } 580 581 582 status_t 583 XHCI::ControllerHalt() 584 { 585 WriteOpReg(XHCI_CMD, 0); 586 587 int32 tries = 100; 588 while ((ReadOpReg(XHCI_STS) & STS_HCH) == 0) { 589 snooze(1000); 590 if (tries-- < 0) 591 return B_ERROR; 592 } 593 594 return B_OK; 595 } 596 597 598 status_t 599 XHCI::ControllerReset() 600 { 601 WriteOpReg(XHCI_CMD, CMD_HCRST); 602 603 int32 tries = 100; 604 while (ReadOpReg(XHCI_CMD) & CMD_HCRST) { 605 snooze(1000); 606 if (tries-- < 0) 607 return B_ERROR; 608 } 609 610 tries = 100; 611 while (ReadOpReg(XHCI_STS) & STS_CNR) { 612 snooze(1000); 613 if (tries-- < 0) 614 return B_ERROR; 615 } 616 617 return B_OK; 618 } 619 620 621 int32 622 XHCI::InterruptHandler(void *data) 623 { 624 return ((XHCI *)data)->Interrupt(); 625 } 626 627 628 int32 629 XHCI::Interrupt() 630 { 631 acquire_spinlock(&fSpinlock); 632 633 uint32 status = ReadOpReg(XHCI_STS); 634 uint32 temp = ReadRunReg32(XHCI_IMAN(0)); 635 WriteOpReg(XHCI_STS, status); 636 WriteRunReg32(XHCI_IMAN(0), temp); 637 TRACE("STS: %lx IRQ_PENDING: %lx\n", status, temp); 638 639 int32 result = B_HANDLED_INTERRUPT; 640 641 if (status & STS_HSE) { 642 TRACE_ERROR("Host System Error\n"); 643 return result; 644 } 645 if (status & STS_HCE) { 646 TRACE_ERROR("Host Controller Error\n"); 647 return result; 648 } 649 uint16 i = fEventIdx; 650 uint8 j = fEventCcs; 651 uint8 t = 2; 652 653 while (1) { 654 temp = fEventRing[i].dwtrb3; 655 uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0; 656 if (j != k) 657 break; 658 659 uint8 event = TRB_TYPE_GET(temp); 660 661 TRACE("event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", i, event, 662 fEventRing[i].qwtrb0, fEventRing[i].dwtrb2, fEventRing[i].dwtrb3); 663 switch (event) { 664 case TRB_COMPLETION: 665 HandleCmdComplete(&fEventRing[i]); 666 result = B_INVOKE_SCHEDULER; 667 break; 668 default: 669 TRACE_ERROR("Unhandled event = %u\n", event); 670 break; 671 } 672 673 i++; 674 if (i == MAX_EVENTS) { 675 i = 0; 676 j ^= 1; 677 if (!--t) 678 break; 679 } 680 } 681 682 fEventIdx = i; 683 fEventCcs = j; 684 685 uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb); 686 addr |= ERST_EHB; 687 WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr); 688 WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32)); 689 690 691 release_spinlock(&fSpinlock); 692 693 return result; 694 } 695 696 697 void 698 XHCI::Ring() 699 { 700 TRACE("Ding Dong!\n") 701 WriteDoorReg32(XHCI_DOORBELL(0), 0); 702 /* Flush PCI posted writes */ 703 ReadDoorReg32(XHCI_DOORBELL(0)); 704 } 705 706 707 void 708 XHCI::QueueCommand(xhci_trb *trb) 709 { 710 uint8 i, j; 711 uint32 temp; 712 713 i = fCmdIdx; 714 j = fCmdCcs; 715 716 TRACE("command[%u] = %lx (0x%016llx, 0x%08lx, 0x%08lx)\n", 717 i, TRB_TYPE_GET(trb->dwtrb3), 718 trb->qwtrb0, trb->dwtrb2, trb->dwtrb3); 719 720 fCmdRing[i].qwtrb0 = trb->qwtrb0; 721 fCmdRing[i].dwtrb2 = trb->dwtrb2; 722 temp = trb->dwtrb3; 723 724 if (j) 725 temp |= TRB_3_CYCLE_BIT; 726 else 727 temp &= ~TRB_3_CYCLE_BIT; 728 temp &= ~TRB_3_TC_BIT; 729 fCmdRing[i].dwtrb3 = temp; 730 731 fCmdAddr = fErst->rs_addr + (MAX_EVENTS + i) * sizeof(xhci_trb); 732 733 i++; 734 735 if (i == (MAX_COMMANDS - 1)) { 736 if (j) 737 temp = TRB_3_CYCLE_BIT | TRB_TYPE(TRB_LINK); 738 else 739 temp = TRB_TYPE(TRB_LINK); 740 fCmdRing[i].dwtrb3 = temp; 741 742 i = 0; 743 j ^= 1; 744 } 745 746 fCmdIdx = i; 747 fCmdCcs = j; 748 } 749 750 751 void 752 XHCI::HandleCmdComplete(xhci_trb *trb) 753 { 754 if (fCmdAddr == trb->qwtrb0) { 755 TRACE("Received command event\n"); 756 fCmdResult[0] = trb->dwtrb2; 757 fCmdResult[1] = trb->dwtrb3; 758 release_sem_etc(fCmdCompSem, 1, B_DO_NOT_RESCHEDULE); 759 } 760 761 } 762 763 764 void 765 XHCI::QueueNoop() 766 { 767 xhci_trb trb; 768 uint32 temp; 769 770 trb.qwtrb0 = 0; 771 trb.dwtrb2 = 0; 772 temp = TRB_TYPE(TRB_TR_NOOP); 773 trb.dwtrb3 = temp; 774 cpu_status state = disable_interrupts(); 775 acquire_spinlock(&fSpinlock); 776 QueueCommand(&trb); 777 Ring(); 778 release_spinlock(&fSpinlock); 779 restore_interrupts(state); 780 } 781 782 783 int32 784 XHCI::CmdCompThread(void *data) 785 { 786 ((XHCI *)data)->CmdComplete(); 787 return B_OK; 788 } 789 790 791 void 792 XHCI::CmdComplete() 793 { 794 while (!fStopThreads) { 795 if (acquire_sem(fCmdCompSem) < B_OK) 796 continue; 797 798 // eat up sems that have been released by multiple interrupts 799 int32 semCount = 0; 800 get_sem_count(fCmdCompSem, &semCount); 801 if (semCount > 0) 802 acquire_sem_etc(fCmdCompSem, semCount, B_RELATIVE_TIMEOUT, 0); 803 804 TRACE("Command Complete\n"); 805 if (COMP_CODE_GET(fCmdResult[0]) != COMP_SUCCESS) { 806 TRACE_ERROR("unsuccessful no-op command\n"); 807 //continue; 808 } 809 snooze(1000000 * 5); 810 QueueNoop(); 811 } 812 } 813 814 815 int32 816 XHCI::FinishThread(void *data) 817 { 818 ((XHCI *)data)->FinishTransfers(); 819 return B_OK; 820 } 821 822 823 void 824 XHCI::FinishTransfers() 825 { 826 while (!fStopThreads) { 827 if (acquire_sem(fFinishTransfersSem) < B_OK) 828 continue; 829 830 // eat up sems that have been released by multiple interrupts 831 int32 semCount = 0; 832 get_sem_count(fFinishTransfersSem, &semCount); 833 if (semCount > 0) 834 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 835 836 TRACE("finishing transfers\n"); 837 } 838 } 839 840 inline void 841 XHCI::WriteOpReg(uint32 reg, uint32 value) 842 { 843 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 844 } 845 846 847 inline uint32 848 XHCI::ReadOpReg(uint32 reg) 849 { 850 return *(volatile uint32 *)(fOperationalRegisters + reg); 851 } 852 853 854 inline uint8 855 XHCI::ReadCapReg8(uint32 reg) 856 { 857 return *(volatile uint8 *)(fCapabilityRegisters + reg); 858 } 859 860 861 inline uint16 862 XHCI::ReadCapReg16(uint32 reg) 863 { 864 return *(volatile uint16 *)(fCapabilityRegisters + reg); 865 } 866 867 868 inline uint32 869 XHCI::ReadCapReg32(uint32 reg) 870 { 871 return *(volatile uint32 *)(fCapabilityRegisters + reg); 872 } 873 874 875 inline void 876 XHCI::WriteCapReg32(uint32 reg, uint32 value) 877 { 878 *(volatile uint32 *)(fCapabilityRegisters + reg) = value; 879 } 880 881 882 inline uint32 883 XHCI::ReadRunReg32(uint32 reg) 884 { 885 return *(volatile uint32 *)(fRuntimeRegisters + reg); 886 } 887 888 889 inline void 890 XHCI::WriteRunReg32(uint32 reg, uint32 value) 891 { 892 *(volatile uint32 *)(fRuntimeRegisters + reg) = value; 893 } 894 895 896 inline uint32 897 XHCI::ReadDoorReg32(uint32 reg) 898 { 899 return *(volatile uint32 *)(fDoorbellRegisters + reg); 900 } 901 902 903 inline void 904 XHCI::WriteDoorReg32(uint32 reg, uint32 value) 905 { 906 *(volatile uint32 *)(fDoorbellRegisters + reg) = value; 907 } 908