[haiku-commits] r42511 - in haiku/trunk/src/add-ons/kernel: bus_managers/usb busses/usb

  • From: korli@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 29 Jul 2011 12:06:35 +0200 (CEST)

Author: korli
Date: 2011-07-29 12:06:34 +0200 (Fri, 29 Jul 2011)
New Revision: 42511
Changeset: https://dev.haiku-os.org/changeset/42511

Added:
   haiku/trunk/src/add-ons/kernel/busses/usb/xhci_rh.cpp
Modified:
   haiku/trunk/src/add-ons/kernel/bus_managers/usb/usb_private.h
   haiku/trunk/src/add-ons/kernel/busses/usb/Jamfile
   haiku/trunk/src/add-ons/kernel/busses/usb/xhci.cpp
   haiku/trunk/src/add-ons/kernel/busses/usb/xhci.h
   haiku/trunk/src/add-ons/kernel/busses/usb/xhci_hardware.h
Log:
Patch by Jian Chiang as part of his GSoc Project (coding style fixes by 
myself): 
* xhci controller start operation
* command ring and event ring initialization
* No-Op Command test and real xhci irq handle
* xhci root hub support
* add Super Speed enumeration and xhci_rh.cpp into jamfile


Modified: haiku/trunk/src/add-ons/kernel/bus_managers/usb/usb_private.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/usb/usb_private.h       
2011-07-29 06:12:01 UTC (rev 42510)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/usb/usb_private.h       
2011-07-29 10:06:34 UTC (rev 42511)
@@ -90,7 +90,8 @@
        USB_SPEED_LOWSPEED = 0,
        USB_SPEED_FULLSPEED,
        USB_SPEED_HIGHSPEED,
-       USB_SPEED_MAX = USB_SPEED_HIGHSPEED
+       USB_SPEED_SUPER,
+       USB_SPEED_MAX = USB_SPEED_SUPER
 } usb_speed;
 
 

Modified: haiku/trunk/src/add-ons/kernel/busses/usb/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/busses/usb/Jamfile   2011-07-29 06:12:01 UTC 
(rev 42510)
+++ haiku/trunk/src/add-ons/kernel/busses/usb/Jamfile   2011-07-29 10:06:34 UTC 
(rev 42511)
@@ -28,6 +28,7 @@
 
 KernelAddon <usb>xhci :
        xhci.cpp
+       xhci_rh.cpp
        : libusb.a
        : xhci.rdef
        ;

Modified: haiku/trunk/src/add-ons/kernel/busses/usb/xhci.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/busses/usb/xhci.cpp  2011-07-29 06:12:01 UTC 
(rev 42510)
+++ haiku/trunk/src/add-ons/kernel/busses/usb/xhci.cpp  2011-07-29 10:06:34 UTC 
(rev 42511)
@@ -63,7 +63,22 @@
                fRegisterArea(-1),
                fPCIInfo(info),
                fStack(stack),
-               fPortCount(0)
+               fErstArea(-1),
+               fDcbaArea(-1),
+               fSpinlock(B_SPINLOCK_INITIALIZER),
+               fCmdCompSem(-1),
+               fCmdCompThread(-1),
+               fFinishTransfersSem(-1),
+               fFinishThread(-1),
+               fStopThreads(false),
+               fRootHub(NULL),
+               fRootHubAddress(0),
+               fPortCount(0),
+               fSlotCount(0),
+               fEventIdx(0),
+               fCmdIdx(0),
+               fEventCcs(1),
+               fCmdCcs(1)
 {
        if (BusManager::InitCheck() < B_OK) {
                TRACE_ERROR("bus manager failed to init\n");
@@ -76,7 +91,7 @@
        // enable busmaster and memory mapped access
        uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
                fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
-       command &= ~PCI_command_io;
+       command &= ~(PCI_command_io | PCI_command_int_disable);
        command |= PCI_command_master | PCI_command_memory;
 
        sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
@@ -92,7 +107,7 @@
                fPCIInfo->u.h0.base_registers[0], physicalAddress, offset,
                fPCIInfo->u.h0.base_register_sizes[0]);
 
-       fRegisterArea = map_physical_memory("EHCI memory mapped registers",
+       fRegisterArea = map_physical_memory("XHCI memory mapped registers",
                physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
                B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | 
B_WRITE_AREA,
                (void **)&fCapabilityRegisters);
@@ -103,62 +118,55 @@
 
        fCapabilityRegisters += offset;
        fOperationalRegisters = fCapabilityRegisters + 
ReadCapReg8(XHCI_CAPLENGTH);
-       fRuntimeRegisters = fCapabilityRegisters + ReadCapReg8(XHCI_RTSOFF);
+       fRuntimeRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_RTSOFF);
+       fDoorbellRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_DBOFF);
        TRACE("mapped capability registers: 0x%08lx\n", 
(uint32)fCapabilityRegisters);
        TRACE("mapped operational registers: 0x%08lx\n", 
(uint32)fOperationalRegisters);
        TRACE("mapped rumtime registers: 0x%08lx\n", (uint32)fRuntimeRegisters);
+       TRACE("mapped doorbell registers: 0x%08lx\n", 
(uint32)fDoorbellRegisters);
 
        TRACE("structural parameters1: 0x%08lx\n", 
ReadCapReg32(XHCI_HCSPARAMS1));
        TRACE("structural parameters2: 0x%08lx\n", 
ReadCapReg32(XHCI_HCSPARAMS2));
        TRACE("structural parameters3: 0x%08lx\n", 
ReadCapReg32(XHCI_HCSPARAMS3));
        TRACE("capability parameters: 0x%08lx\n", ReadCapReg32(XHCI_HCCPARAMS));
 
-       // read port count from capability register
-       fPortCount = (ReadCapReg32(XHCI_HCSPARAMS1) >> 24) & 0x7f;
+       uint32 cparams = ReadCapReg32(XHCI_HCCPARAMS);
+       uint32 eec = 0xffffffff;
+       uint32 eecp = HCS0_XECP(cparams) << 2;
+       for (; eecp != 0 && XECP_NEXT(eec); eecp += XECP_NEXT(eec) << 2) {
+               eec = ReadCapReg32(eecp);
+               if (XECP_ID(eec) != XHCI_LEGSUP_CAPID)
+                       continue;
+       }
+       if (eec & XHCI_LEGSUP_BIOSOWNED) {
+               TRACE_ALWAYS("the host controller is bios owned, claiming"
+                       " ownership\n");
+               WriteCapReg32(eecp, eec | XHCI_LEGSUP_OSOWNED);
 
-       uint32 extendedCapPointer = ((ReadCapReg32(XHCI_HCCPARAMS) >> 16) & 
0xffff)
-               << 2;
-       if (extendedCapPointer > 0) {
-               TRACE("extended capabilities register at %ld\n", 
extendedCapPointer);
+               for (int32 i = 0; i < 20; i++) {
+                       eec = ReadCapReg32(eecp);
 
-               uint32 legacySupport = ReadCapReg32(extendedCapPointer);
-               if ((legacySupport & XHCI_LEGSUP_CAPID_MASK) == 
XHCI_LEGSUP_CAPID) {
-                       if ((legacySupport & XHCI_LEGSUP_BIOSOWNED) != 0) {
-                               TRACE_ALWAYS("the host controller is bios 
owned, claiming"
-                                       " ownership\n");
-                               WriteCapReg32(extendedCapPointer, legacySupport 
-                                       | XHCI_LEGSUP_OSOWNED);
-                               for (int32 i = 0; i < 20; i++) {
-                                       legacySupport = 
ReadCapReg32(extendedCapPointer);
+                       if ((eec & XHCI_LEGSUP_BIOSOWNED) == 0)
+                               break;
 
-                                       if ((legacySupport & 
XHCI_LEGSUP_BIOSOWNED) == 0)
-                                               break;
+                       TRACE_ALWAYS("controller is still bios owned, 
waiting\n");
+                       snooze(50000);
+               }
 
-                                       TRACE_ALWAYS("controller is still bios 
owned, waiting\n");
-                                       snooze(50000);
-                               }
-                       }
+               if (eec & XHCI_LEGSUP_BIOSOWNED) {
+                       TRACE_ERROR("bios won't give up control over the host "
+                               "controller (ignoring)\n");
+               } else if (eec & XHCI_LEGSUP_OSOWNED) {
+                       TRACE_ALWAYS("successfully took ownership of the host "
+                               "controller\n");
+               }
 
-                       if (legacySupport & XHCI_LEGSUP_BIOSOWNED) {
-                               TRACE_ERROR("bios won't give up control over 
the host "
-                                       "controller (ignoring)\n");
-                       } else if (legacySupport & XHCI_LEGSUP_OSOWNED) {
-                               TRACE_ALWAYS("successfully took ownership of 
the host "
-                                       "controller\n");
-                       }
-
-                       // Force off the BIOS owned flag, and clear all SMIs. 
Some BIOSes
-                       // do indicate a successful handover but do not remove 
their SMIs
-                       // and then freeze the system when interrupts are 
generated.
-                       WriteCapReg32(extendedCapPointer, legacySupport & 
~XHCI_LEGSUP_BIOSOWNED);
-                       WriteCapReg32(extendedCapPointer + XHCI_LEGCTLSTS,
-                               XHCI_LEGCTLSTS_DISABLE_SMI);
-               } else {
-                       TRACE("extended capability is not a legacy support 
register\n");
-               }
-       } else {
-               TRACE("no extended capabilities register\n");
+               // Force off the BIOS owned flag, and clear all SMIs. Some 
BIOSes
+               // do indicate a successful handover but do not remove their 
SMIs
+               // and then freeze the system when interrupts are generated.
+               WriteCapReg32(eecp, eec & ~XHCI_LEGSUP_BIOSOWNED);
        }
+       WriteCapReg32(eecp + XHCI_LEGCTLSTS, XHCI_LEGCTLSTS_DISABLE_SMI);
 
        // halt the host controller
        if (ControllerHalt() < B_OK) {
@@ -171,6 +179,28 @@
                return;
        }
 
+       fCmdCompSem = create_sem(0, "XHCI Command Complete");
+       fFinishTransfersSem = create_sem(0, "XHCI Finish Transfers");
+       if (fFinishTransfersSem < B_OK || fCmdCompSem < B_OK) {
+               TRACE_ERROR("failed to create semaphores\n");
+               return;
+       }
+
+       // create finisher service thread
+       fFinishThread = spawn_kernel_thread(FinishThread, "xhci finish thread",
+               B_NORMAL_PRIORITY, (void *)this);
+       resume_thread(fFinishThread);
+
+       // create command complete service thread
+       fCmdCompThread = spawn_kernel_thread(CmdCompThread, "xhci cmd complete 
thread",
+               B_NORMAL_PRIORITY, (void *)this);
+       resume_thread(fCmdCompThread);
+
+       // Install the interrupt handler
+       TRACE("installing interrupt handler\n");
+       install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
+               InterruptHandler, (void *)this, 0);
+
        fInitOK = true;
        TRACE("XHCI host controller driver constructed\n");
 }
@@ -182,7 +212,15 @@
 
        WriteOpReg(XHCI_CMD, 0);
 
+       int32 result = 0;
+       fStopThreads = true;
+       delete_sem(fCmdCompSem);
+       delete_sem(fFinishTransfersSem);
        delete_area(fRegisterArea);
+       delete_area(fErstArea);
+       delete_area(fDcbaArea);
+       wait_for_thread(fCmdCompThread, &result);
+       wait_for_thread(fFinishThread, &result);
        put_module(B_PCI_MODULE_NAME);
 }
 
@@ -194,7 +232,100 @@
        TRACE("usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(XHCI_CMD),
                ReadOpReg(XHCI_STS));
 
+       if ((ReadOpReg(XHCI_PAGESIZE) & (1 << 0)) == 0) {
+               TRACE_ERROR("Controller does not support 4K page size.\n");
+               return B_ERROR;
+       }
+
+       // read port count from capability register
+       uint32 capabilities = ReadCapReg32(XHCI_HCSPARAMS1);
+
+       uint8 portsCount = HCS_MAX_PORTS(capabilities);
+       if (portsCount == 0) {
+               TRACE_ERROR("Invalid number of ports: %u\n", portsCount);
+               return B_ERROR;
+       }
+       fPortCount = portsCount;
+       fSlotCount = HCS_MAX_SLOTS(capabilities);
+       WriteOpReg(XHCI_CONFIG, fSlotCount);
+
+       void *dmaAddress;
+       fDcbaArea = fStack->AllocateArea((void **)&fDcba, &dmaAddress,
+               sizeof(uint64) * XHCI_MAX_SLOTS, "DCBA Area");
+       if (fDcbaArea < B_OK) {
+               TRACE_ERROR("unable to create the DCBA area\n");
+               return B_ERROR;
+       }
+       memset(fDcba, 0, sizeof(uint64) * XHCI_MAX_SLOTS);
+       TRACE("setting DCBAAP\n");
+       WriteOpReg(XHCI_DCBAAP_LO, (uint32)dmaAddress);
+       WriteOpReg(XHCI_DCBAAP_HI, 0);
+
+       fErstArea = fStack->AllocateArea((void **)&fErst, &dmaAddress,
+               (MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb)
+               + sizeof(xhci_erst_element),
+               "USB XHCI ERST CMD_RING and EVENT_RING Area");
+
+       if (fErstArea < B_OK) {
+               TRACE_ERROR("unable to create the ERST AND RING area\n");
+               delete_area(fDcbaArea);
+               return B_ERROR;
+       }
+       memset(fErst, 0, (MAX_COMMANDS + MAX_EVENTS) * sizeof(xhci_trb)
+               + sizeof(xhci_erst_element));
+
+       fErst->rs_addr = (uint32)dmaAddress + sizeof(xhci_erst_element);
+       fErst->rs_size = MAX_EVENTS;
+       fErst->rsvdz = 0;
+
+       uint32 addr = (uint32)fErst + sizeof(xhci_erst_element);
+       fEventRing = (xhci_trb *)addr;
+       addr += MAX_EVENTS * sizeof(xhci_trb);
+       fCmdRing = (xhci_trb *)addr;
+
+       TRACE("setting ERST size\n");
+       WriteRunReg32(XHCI_ERSTSZ(0), XHCI_ERSTS_SET(1));
+
+       TRACE("setting ERDP addr = 0x%llx\n", fErst->rs_addr);
+       WriteRunReg32(XHCI_ERDP_LO(0), (uint32)fErst->rs_addr);
+       WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(fErst->rs_addr >> 32));
+
+       TRACE("setting ERST base addr = 0x%llx\n", (uint64)dmaAddress);
+       WriteRunReg32(XHCI_ERSTBA_LO(0), (uint32)dmaAddress);
+       WriteRunReg32(XHCI_ERSTBA_HI(0), 0);
+
+       addr = fErst->rs_addr + MAX_EVENTS * sizeof(xhci_trb);
+       TRACE("setting CRCR addr = 0x%llx\n", (uint64)addr);
+       WriteOpReg(XHCI_CRCR_LO, addr | CRCR_RCS);
+       WriteOpReg(XHCI_CRCR_HI, 0);
+       //link trb
+       fCmdRing[MAX_COMMANDS - 1].qwtrb0 = addr;
+
+       TRACE("setting interrupt rate\n");
+       WriteRunReg32(XHCI_IMOD(0), 160);//4000 irq/s
+
+       TRACE("enabling interrupt\n");
+       WriteRunReg32(XHCI_IMAN(0), ReadRunReg32(XHCI_IMAN(0)) | IMAN_INTR_ENA);
+
+       WriteOpReg(XHCI_CMD, CMD_RUN | CMD_EIE | CMD_HSEIE);
+
+       fRootHubAddress = AllocateAddress();
+       fRootHub = new(std::nothrow) XHCIRootHub(RootObject(), fRootHubAddress);
+       if (!fRootHub) {
+               TRACE_ERROR("no memory to allocate root hub\n");
+               return B_NO_MEMORY;
+       }
+
+       if (fRootHub->InitCheck() < B_OK) {
+               TRACE_ERROR("root hub failed init check\n");
+               return fRootHub->InitCheck();
+       }
+
+       SetRootHub(fRootHub);
+
        TRACE_ALWAYS("successfully started the controller\n");
+       TRACE("No-Op test\n");
+       QueueNoop();
        return BusManager::Start();
 }
 
@@ -202,6 +333,10 @@
 status_t
 XHCI::SubmitTransfer(Transfer *transfer)
 {
+       // short circuit the root hub
+       if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
+               return fRootHub->ProcessTransfer(this, transfer);
+
        return B_OK;
 }
 
@@ -315,6 +450,46 @@
 status_t
 XHCI::GetPortStatus(uint8 index, usb_port_status *status)
 {
+       if (index >= fPortCount)
+               return B_BAD_INDEX;
+
+       status->status = status->change = 0;
+       uint32 portStatus = ReadOpReg(XHCI_PORTSC(index));
+       TRACE("port status=0x%08lx\n", portStatus);
+
+       // build the status
+       switch(PS_SPEED_GET(portStatus)) {
+       case 3:
+               status->status |= PORT_STATUS_HIGH_SPEED;
+               break;
+       case 2:
+               status->status |= PORT_STATUS_LOW_SPEED;
+               break;
+       default:
+               break;
+       }
+
+       if (portStatus & PS_CCS)
+               status->status |= PORT_STATUS_CONNECTION;
+       if (portStatus & PS_PED)
+               status->status |= PORT_STATUS_ENABLE;
+       if (portStatus & PS_OCA)
+               status->status |= PORT_STATUS_OVER_CURRENT;
+       if (portStatus & PS_PR)
+               status->status |= PORT_STATUS_RESET;
+       if (portStatus & PS_PP)
+               status->status |= PORT_STATUS_POWER;
+
+       // build the change
+       if (portStatus & PS_CSC)
+               status->change |= PORT_STATUS_CONNECTION;
+       if (portStatus & PS_PEC)
+               status->change |= PORT_STATUS_ENABLE;
+       if (portStatus & PS_OCC)
+               status->change |= PORT_STATUS_OVER_CURRENT;
+       if (portStatus & PS_PRC)
+               status->change |= PORT_STATUS_RESET;
+
        return B_OK;
 }
 
@@ -322,30 +497,85 @@
 status_t
 XHCI::SetPortFeature(uint8 index, uint16 feature)
 {
-       return B_BAD_VALUE;
-}
+       TRACE("set port feature index %u feature %u\n", index, feature);
+       if (index >= fPortCount)
+               return B_BAD_INDEX;
 
+       uint32 portRegister = XHCI_PORTSC(index);
+       uint32 portStatus = ReadOpReg(portRegister);
 
-status_t
-XHCI::ClearPortFeature(uint8 index, uint16 feature)
-{
+       switch (feature) {
+       case PORT_SUSPEND:
+               if ((portStatus & PS_PED ) == 0 || (portStatus & PS_PR)
+                       || (portStatus & PS_PLS_MASK) >= PS_XDEV_U3) {
+                       TRACE_ERROR("USB core suspending device not in 
U0/U1/U2.\n");
+                       return B_BAD_VALUE;
+               }
+               portStatus &= ~PS_CLEAR;
+               portStatus &= ~PS_PLS_MASK;
+               portStatus |= PS_LWS | PS_XDEV_U3;
+               WriteOpReg(portRegister, portStatus);
+               return B_OK;
+
+       case PORT_RESET:
+               portStatus &= ~PS_CLEAR;
+               WriteOpReg(portRegister, portStatus | PS_PR);
+               return B_OK;
+
+       case PORT_POWER:
+               portStatus &= ~PS_CLEAR;
+               WriteOpReg(portRegister, portStatus | PS_PP);
+               return B_OK;
+       }
        return B_BAD_VALUE;
 }
 
 
 status_t
-XHCI::ResetPort(uint8 index)
+XHCI::ClearPortFeature(uint8 index, uint16 feature)
 {
-       TRACE("reset port %d\n", index);
+       TRACE("clear port feature index %u feature %u\n", index, feature);
+       if (index >= fPortCount)
+               return B_BAD_INDEX;
 
-       return B_OK;
-}
+       uint32 portRegister = XHCI_PORTSC(index);
+       uint32 portStatus = ReadOpReg(portRegister);
+       portStatus &= ~PS_CLEAR;
 
+       switch (feature) {
+       case PORT_SUSPEND:
+               portStatus = ReadOpReg(portRegister);
+               if (portStatus & PS_PR)
+                       return B_BAD_VALUE;
+               if (portStatus & PS_XDEV_U3) {
+                       if ((portStatus & PS_PED) == 0)
+                               return B_BAD_VALUE;
+                       portStatus &= ~PS_CLEAR;
+                       portStatus &= ~PS_PLS_MASK;
+                       WriteOpReg(portRegister, portStatus | PS_XDEV_U0 | 
PS_LWS);
+               }
+               return B_OK;
+       case PORT_ENABLE:
+               WriteOpReg(portRegister, portStatus | PS_PED);
+               return B_OK;
+       case PORT_POWER:
+               WriteOpReg(portRegister, portStatus & ~PS_PP);
+               return B_OK;
+       case C_PORT_CONNECTION:
+               WriteOpReg(portRegister, portStatus | PS_CSC);
+               return B_OK;
+       case C_PORT_ENABLE:
+               WriteOpReg(portRegister, portStatus | PS_PEC);
+               return B_OK;
+       case C_PORT_OVER_CURRENT:
+               WriteOpReg(portRegister, portStatus | PS_OCC);
+               return B_OK;
+       case C_PORT_RESET:
+               WriteOpReg(portRegister, portStatus | PS_PRC);
+               return B_OK;
+       }
 
-status_t
-XHCI::SuspendPort(uint8 index)
-{
-       return B_OK;
+       return B_BAD_VALUE;
 }
 
 
@@ -388,13 +618,6 @@
 }
 
 
-status_t
-XHCI::LightReset()
-{
-       return B_ERROR;
-}
-
-
 int32
 XHCI::InterruptHandler(void *data)
 {
@@ -405,11 +628,215 @@
 int32
 XHCI::Interrupt()
 {
+       acquire_spinlock(&fSpinlock);
+
+       uint32 status = ReadOpReg(XHCI_STS);
+       uint32 temp = ReadRunReg32(XHCI_IMAN(0));
+       WriteOpReg(XHCI_STS, status);
+       WriteRunReg32(XHCI_IMAN(0), temp);
+       TRACE("STS: %lx IRQ_PENDING: %lx\n", status, temp);
+
        int32 result = B_HANDLED_INTERRUPT;
+       
+       if (status & STS_HSE) {
+               TRACE_ERROR("Host System Error\n");
+               return result;
+       }
+       if (status & STS_HCE) {
+               TRACE_ERROR("Host Controller Error\n");
+               return result;
+       }
+       uint16 i = fEventIdx;
+       uint8 j = fEventCcs;
+       uint8 t = 2;
+       
+       while (1) {
+               temp = fEventRing[i].dwtrb3;
+               uint8 k = (temp & TRB_3_CYCLE_BIT) ? 1 : 0;
+               if (j != k)
+                       break;
 
+               uint8 event = TRB_TYPE_GET(temp);
+
+               TRACE("event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", i, event,
+                       fEventRing[i].qwtrb0, fEventRing[i].dwtrb2, 
fEventRing[i].dwtrb3);
+               switch (event) {
+               case TRB_COMPLETION:
+                       HandleCmdComplete(&fEventRing[i]);
+                       result = B_INVOKE_SCHEDULER;
+                       break;
+               default:
+                       TRACE_ERROR("Unhandled event = %u\n", event);
+                       break;
+               }
+
+               i++;
+               if (i == MAX_EVENTS) {
+                       i = 0;
+                       j ^= 1;
+                       if (!--t)
+                               break;
+               }
+       }
+
+       fEventIdx = i;
+       fEventCcs = j;
+
+       uint64 addr = fErst->rs_addr + i * sizeof(xhci_trb);
+       addr |= ERST_EHB;
+       WriteRunReg32(XHCI_ERDP_LO(0), (uint32)addr);
+       WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(addr >> 32));
+
+
+       release_spinlock(&fSpinlock);
+
        return result;
 }
 
+
+void
+XHCI::Ring()
+{
+       TRACE("Ding Dong!\n")
+       WriteDoorReg32(XHCI_DOORBELL(0), 0);
+       /* Flush PCI posted writes */
+       ReadDoorReg32(XHCI_DOORBELL(0));
+}
+
+
+void
+XHCI::QueueCommand(xhci_trb *trb)
+{
+       uint8 i, j;
+       uint32 temp;
+
+       i = fCmdIdx;
+       j = fCmdCcs;
+
+       TRACE("command[%u] = %lx (0x%016llx, 0x%08lx, 0x%08lx)\n",
+               i, TRB_TYPE_GET(trb->dwtrb3),
+               trb->qwtrb0, trb->dwtrb2, trb->dwtrb3);
+
+       fCmdRing[i].qwtrb0 = trb->qwtrb0;
+       fCmdRing[i].dwtrb2 = trb->dwtrb2;
+       temp = trb->dwtrb3;
+
+       if (j)
+               temp |= TRB_3_CYCLE_BIT;
+       else
+               temp &= ~TRB_3_CYCLE_BIT;
+       temp &= ~TRB_3_TC_BIT;
+       fCmdRing[i].dwtrb3 = temp;
+
+       fCmdAddr = fErst->rs_addr + (MAX_EVENTS + i) * sizeof(xhci_trb);
+
+       i++;
+
+       if (i == (MAX_COMMANDS - 1)) {
+               if (j)
+                       temp = TRB_3_CYCLE_BIT | TRB_TYPE(TRB_LINK);
+               else
+                       temp = TRB_TYPE(TRB_LINK);
+               fCmdRing[i].dwtrb3 = temp;
+
+               i = 0;
+               j ^= 1;
+       }
+
+       fCmdIdx = i;
+       fCmdCcs = j;
+}
+
+
+void
+XHCI::HandleCmdComplete(xhci_trb *trb)
+{
+       if (fCmdAddr == trb->qwtrb0) {
+               TRACE("Received command event\n");
+               fCmdResult[0] = trb->dwtrb2;
+               fCmdResult[1] = trb->dwtrb3;
+               release_sem_etc(fCmdCompSem, 1, B_DO_NOT_RESCHEDULE);
+       }
+
+}
+
+
+void
+XHCI::QueueNoop()
+{
+       xhci_trb trb;
+       uint32 temp;
+
+       trb.qwtrb0 = 0;
+       trb.dwtrb2 = 0;
+       temp = TRB_TYPE(TRB_TR_NOOP);
+       trb.dwtrb3 = temp;
+       cpu_status state = disable_interrupts();
+       acquire_spinlock(&fSpinlock);
+       QueueCommand(&trb);
+       Ring();
+       release_spinlock(&fSpinlock);
+       restore_interrupts(state);
+}
+
+
+int32
+XHCI::CmdCompThread(void *data)
+{
+       ((XHCI *)data)->CmdComplete();
+       return B_OK;
+}
+
+
+void
+XHCI::CmdComplete()
+{
+       while (!fStopThreads) {
+               if (acquire_sem(fCmdCompSem) < B_OK)
+                       continue;
+
+               // eat up sems that have been released by multiple interrupts
+               int32 semCount = 0;
+               get_sem_count(fCmdCompSem, &semCount);
+               if (semCount > 0)
+                       acquire_sem_etc(fCmdCompSem, semCount, 
B_RELATIVE_TIMEOUT, 0);
+
+               TRACE("Command Complete\n");
+               if (COMP_CODE_GET(fCmdResult[0]) != COMP_SUCCESS) {
+                       TRACE_ERROR("unsuccessful no-op command\n");
+                       //continue;
+               }
+               snooze(1000000 * 5);
+               QueueNoop();
+       }
+}
+
+
+int32
+XHCI::FinishThread(void *data)
+{
+       ((XHCI *)data)->FinishTransfers();
+       return B_OK;
+}
+
+
+void
+XHCI::FinishTransfers()
+{
+       while (!fStopThreads) {
+               if (acquire_sem(fFinishTransfersSem) < B_OK)
+                       continue;
+
+               // eat up sems that have been released by multiple interrupts
+               int32 semCount = 0;
+               get_sem_count(fFinishTransfersSem, &semCount);
+               if (semCount > 0)
+                       acquire_sem_etc(fFinishTransfersSem, semCount, 
B_RELATIVE_TIMEOUT, 0);
+
+               TRACE("finishing transfers\n");
+       }
+}
+
 inline void
 XHCI::WriteOpReg(uint32 reg, uint32 value)
 {
@@ -451,3 +878,30 @@
        *(volatile uint32 *)(fCapabilityRegisters + reg) = value;
 }
 
+
+inline uint32
+XHCI::ReadRunReg32(uint32 reg)
+{
+       return *(volatile uint32 *)(fRuntimeRegisters + reg);
+}
+
+
+inline void
+XHCI::WriteRunReg32(uint32 reg, uint32 value)
+{
+       *(volatile uint32 *)(fRuntimeRegisters + reg) = value;
+}
+
+
+inline uint32
+XHCI::ReadDoorReg32(uint32 reg)
+{
+       return *(volatile uint32 *)(fDoorbellRegisters + reg);
+}
+
+
+inline void
+XHCI::WriteDoorReg32(uint32 reg, uint32 value)
+{
+       *(volatile uint32 *)(fDoorbellRegisters + reg) = value;
+}

Modified: haiku/trunk/src/add-ons/kernel/busses/usb/xhci.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/busses/usb/xhci.h    2011-07-29 06:12:01 UTC 
(rev 42510)
+++ haiku/trunk/src/add-ons/kernel/busses/usb/xhci.h    2011-07-29 10:06:34 UTC 
(rev 42511)
@@ -14,10 +14,45 @@
 #include "xhci_hardware.h"
 
 
+#define MAX_EVENTS             (16 * 13)
+#define MAX_COMMANDS           (16 * 1)
+#define XHCI_MAX_SLOTS         256
+#define XHCI_MAX_PORTS         127
+
+
 struct pci_info;
 struct pci_module_info;
+class XHCIRootHub;
 
 
+struct xhci_trb {
+       uint64  qwtrb0;
+       uint32  dwtrb2;
+       uint32  dwtrb3;
+};
+
+
+struct xhci_segment {
+       xhci_trb *              trbs;
+       xhci_segment *  next;
+};
+
+
+struct xhci_ring {
+       xhci_segment *  first_seg;
+       xhci_trb *              enqueue;
+       xhci_trb *              dequeue;
+};
+
+
+// Section 6.5
+struct xhci_erst_element {
+       uint64  rs_addr;
+       uint32  rs_size;
+       uint32  rsvdz;
+} __attribute__((__aligned__(64)));
+
+
 class XHCI : public BusManager {
 public:
                                                                XHCI(pci_info 
*info, Stack *stack);
@@ -32,52 +67,108 @@
 
        static  status_t                        AddTo(Stack *stack);
 
-               // Port operations for root hub
+                       // Port operations for root hub
                        uint8                           PortCount() { return 
fPortCount; };
                        status_t                        GetPortStatus(uint8 
index, usb_port_status *status);
                        status_t                        SetPortFeature(uint8 
index, uint16 feature);
                        status_t                        ClearPortFeature(uint8 
index, uint16 feature);
 
-                       status_t                        ResetPort(uint8 index);
-                       status_t                        SuspendPort(uint8 
index);
-
        virtual const char *            TypeName() const { return "xhci"; };
 
 private:
-               // Controller resets
+                       // Controller resets
                        status_t                        ControllerReset();
                        status_t                        ControllerHalt();
-                       status_t                        LightReset();
 
-               // Interrupt functions
+                       // Interrupt functions
        static  int32                           InterruptHandler(void *data);
                        int32                           Interrupt();
 
+                       // Transfer management
+       static  int32                           FinishThread(void *data);
+                       void                            FinishTransfers();
 
-               // Operational register functions
+                       // Command
+                       void                            QueueCommand(xhci_trb 
*trb);
+                       void                            
HandleCmdComplete(xhci_trb *trb);
+                       
+                       //Doorbell
+                       void                            Ring();
+
+                       //no-op
+                       void                            QueueNoop();
+       static  int32                           CmdCompThread(void *data);
+                       void                            CmdComplete();
+
+                       // Operational register functions
        inline  void                            WriteOpReg(uint32 reg, uint32 
value);
        inline  uint32                          ReadOpReg(uint32 reg);
 
-               // Capability register functions
+                       // Capability register functions
        inline  uint8                           ReadCapReg8(uint32 reg);
        inline  uint16                          ReadCapReg16(uint32 reg);
        inline  uint32                          ReadCapReg32(uint32 reg);
        inline  void                            WriteCapReg32(uint32 reg, 
uint32 value);
 
+                       // Runtime register functions
+       inline  uint32                          ReadRunReg32(uint32 reg);
+       inline  void                            WriteRunReg32(uint32 reg, 
uint32 value);
+
+                       // Doorbell register functions
+       inline  uint32                          ReadDoorReg32(uint32 reg);
+       inline  void                            WriteDoorReg32(uint32 reg, 
uint32 value);
+
        static  pci_module_info *       sPCIModule;
 
                        uint8 *                         fCapabilityRegisters;
                        uint8 *                         fOperationalRegisters;
                        uint8 *                         fRuntimeRegisters;
+                       uint8 *                         fDoorbellRegisters;
                        area_id                         fRegisterArea;
                        pci_info *                      fPCIInfo;
                        Stack *                         fStack;
 
-               // Root Hub
+                       area_id                         fErstArea;
+                       xhci_erst_element *     fErst;
+                       xhci_trb *                      fEventRing;
+                       xhci_trb *                      fCmdRing;
+                       uint64                          fCmdAddr;
+                       uint32                          fCmdResult[2];
 
-               // Port management
+                       area_id                         fDcbaArea;
+                       uint8 *                         fDcba;
+
+                       spinlock                        fSpinlock;
+
+                       sem_id                          fCmdCompSem;
+                       thread_id                       fCmdCompThread;
+                       sem_id                          fFinishTransfersSem;
+                       thread_id                       fFinishThread;
+                       bool                            fStopThreads;
+
+                       // Root Hub
+                       XHCIRootHub *           fRootHub;
+                       uint8                           fRootHubAddress;
+
+                       // Port management
                        uint8                           fPortCount;
+                       uint8                           fSlotCount;
+
+                       uint16                          fEventIdx;
+                       uint16                          fCmdIdx;
+                       uint8                           fEventCcs;
+                       uint8                           fCmdCcs;
 };
 
 
+class XHCIRootHub : public Hub {
+public:
+                                                                       
XHCIRootHub(Object *rootObject,
+                                                                               
int8 deviceAddress);
+
+static status_t                                        ProcessTransfer(XHCI 
*ehci,
+                                                                               
Transfer *transfer);
+};
+
+
 #endif // !XHCI_H

Modified: haiku/trunk/src/add-ons/kernel/busses/usb/xhci_hardware.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/busses/usb/xhci_hardware.h   2011-07-29 
06:12:01 UTC (rev 42510)
+++ haiku/trunk/src/add-ons/kernel/busses/usb/xhci_hardware.h   2011-07-29 
10:06:34 UTC (rev 42511)
@@ -13,31 +13,71 @@
 #define XHCI_CAPLENGTH         0x00            // Capability Register Length
 #define XHCI_HCIVERSION                0x02            // Interface Version 
Number
 #define XHCI_HCSPARAMS1                0x04            // Structural 
Parameters 1
+// HCSPARAMS1
+#define HCS_MAX_SLOTS(p)        (((p) >> 0) & 0xff)
+#define HCS_MAX_PORTS(p)        (((p) >> 24) & 0x7f)
 #define XHCI_HCSPARAMS2                0x08            // Structural 
Parameters 2
 #define XHCI_HCSPARAMS3                0x0C            // Structural 
Parameters 3
 #define XHCI_HCCPARAMS         0x10            // Capability Parameters
+#define XHCI_DBOFF                     0x14            // Doorbell Register 
offset
 #define XHCI_RTSOFF                    0x18            // Runtime Register 
Space offset
 
 
 // Host Controller Operational Registers
 #define XHCI_CMD                       0x00            // USB Command
-#define XHCI_STS                       0x04            // USB Status
-
-
 // USB Command Register
+#define CMD_RUN                                (1 << 0)
 #define CMD_HCRST                      (1 << 1)        // Host Controller Reset
+#define CMD_EIE                                (1 << 2)
+#define CMD_HSEIE                      (1 << 3)
 
-
+#define XHCI_STS                       0x04            // USB Status
 // USB Status Register
-#define STS_HCH                                (1<<0)
+#define STS_HCH                                (1 << 0)
+#define STS_HSE                                (1 << 2)
+#define STS_PCD                                (1 << 4)
 #define STS_CNR                                (1<<11)
+#define STS_HCE                                (1 << 12)
+#define XHCI_PAGESIZE          0x08            // PAGE SIZE
+// Section 5.4.5
+#define XHCI_CRCR_LO           0x18
+#define XHCI_CRCR_HI           0x1C
+#define CRCR_RCS               (1<<0)
+// Section 5.4.6
+#define XHCI_DCBAAP_LO         0x30
+#define XHCI_DCBAAP_HI         0x34
+// Section 5.4.7
+#define XHCI_CONFIG                    0x38
 
 
+// Host Controller Runtime Registers
+// Section 5.5.2.1
+#define XHCI_IMAN(n)           (0x0020 + (0x20 * (n)))
+// IMAN
+#define IMAN_INTR_ENA          0x00000002
+// Section 5.5.2.2
+#define XHCI_IMOD(n)           (0x0024 + (0x20 * (n)))
+// Section 5.5.2.3.1
+#define XHCI_ERSTSZ(n)         (0x0028 + (0x20 * (n)))
+// ERSTSZ
+#define XHCI_ERSTS_SET(x)      ((x) & 0xFFFF)
+// Section 5.5.2.3.2
+#define XHCI_ERSTBA_LO(n)      (0x0030 + (0x20 * (n)))
+#define XHCI_ERSTBA_HI(n)      (0x0034 + (0x20 * (n)))
+// Section 5.5.2.3.3
+#define XHCI_ERDP_LO(n)                (0x0038 + (0x20 * (n)))
+#define XHCI_ERDP_HI(n)                (0x003C + (0x20 * (n)))
+// Event Handler Busy (EHB)
+#define ERST_EHB                       (1 << 3)
 
 
+// Host Controller Doorbell Registers
+#define XHCI_DOORBELL(n)        (0x0000 + (4 * (n)))
 
 // Extended Capabilities
-#define XHCI_LEGSUP_CAPID_MASK 0xff
+#define XECP_ID(x)                             ((x) & 0xff)
+#define HCS0_XECP(x)                   (((x) >> 16) & 0xffff)
+#define XECP_NEXT(x)                   (((x) >> 8) & 0xff)
 #define XHCI_LEGSUP_CAPID              0x01
 #define XHCI_LEGSUP_OSOWNED            (1 << 24)       // OS Owned Semaphore
 #define XHCI_LEGSUP_BIOSOWNED  (1 << 16)       // BIOS Owned Semaphore
@@ -46,5 +86,48 @@
 #define XHCI_LEGCTLSTS_DISABLE_SMI     ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
 
 
+// Port status Registers
+// Section 5.4.8
+#define XHCI_PORTSC(n)                 (0x3F0 + (0x10 * (n)))
+#define PS_CCS                                 (1 << 0)
+#define PS_PED                                 (1 << 1)
+#define PS_OCA                                 (1 << 3)
+#define PS_PR                                  (1 << 4)

[... truncated: 327 lines follow ...]

Other related posts:

  • » [haiku-commits] r42511 - in haiku/trunk/src/add-ons/kernel: bus_managers/usb busses/usb - korli