[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