[prev in list] [next in list] [prev in thread] [next in thread]
List: haiku-commits
Subject: [haiku-commits] r42511 - in haiku/trunk/src/add-ons/kernel: bus_managers/usb busses/usb
From: korli () users ! berlios ! de
Date: 2011-07-29 10:06:35
Message-ID: 20110729100635.DFDEF6822B () vmsvn ! haiku-os ! org
[Download RAW message or body]
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 ...]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic