XHCI: Refactor register area access and handling.

* Don't bother aligning the PCI memory addresses; they will already
   be aligned, and even if by some mystery they aren't, map_physical_memory
   should be able to handle that. This greatly simplifies the code.
 * Use one pointer and then four different offset fields instead of four
   different pointers. This is what DragonFlyBSD and FreeBSD do; it's
   a negligible loss in performance (or none at all, depending on arch
   and compiler) as it requires only one more add, and greatly clarifies
   the code as to what's going on.
 * Remove (both previously and now) unused fields from the header.
 * Compute runtime and doorbell register offsets correctly (there
   was a missing bitmask.) This is how it's done on FreeBSD and
   DragonFlyBSD.
 * Actually write the high bits of the DMA addresses. Checked against
   FreeBSD and DragonFlyBSD.
 * Tweak error message.

Possibly fixes the "invalid bus space memory access" crash, but
I don't have any hardware that occurs on so I couldn't check.

Tested in VMware, VirtualBox, and on a ThinkPad E550 (Broadwell).
This commit is contained in:
Augustin Cavalier 2019-01-16 17:21:03 -05:00
parent abdd597add
commit 8fa626d09d
2 changed files with 36 additions and 45 deletions

View File

@ -1,9 +1,7 @@
/*
* Copyright 2006-2014, Haiku Inc. All rights reserved.
* Copyright 2006-2019, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Some code borrowed from the Haiku EHCI driver
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
* Jian Chiang <j.jian.chiang@gmail.com>
@ -108,9 +106,8 @@ module_info *modules[] = {
XHCI::XHCI(pci_info *info, Stack *stack)
: BusManager(stack),
fCapabilityRegisters(NULL),
fOperationalRegisters(NULL),
fRegisterArea(-1),
fRegisters(NULL),
fPCIInfo(info),
fStack(stack),
fIRQ(0),
@ -160,37 +157,33 @@ XHCI::XHCI(pci_info *info, Stack *stack)
if ((fPCIInfo->u.h0.base_register_flags[0] & 0xC) == PCI_address_type_64)
physicalAddress += (phys_addr_t)fPCIInfo->u.h0.base_registers[1] << 32;
uint32 offset = physicalAddress & (B_PAGE_SIZE - 1);
phys_addr_t physicalAddressAligned = physicalAddress - offset;
size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0]
+ offset + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
size_t mapSize = fPCIInfo->u.h0.base_register_sizes[0];
TRACE("map physical memory 0x%08" B_PRIx32 " : 0x%08" B_PRIx32 " "
"(base: 0x%08" B_PRIxPHYSADDR "; offset: 0x%" B_PRIx32 ");"
TRACE("map physical memory %08" B_PRIx32 " : %08" B_PRIx32 " "
"(base: %08" B_PRIxPHYSADDR "; offset: %" B_PRIx32 ");"
"size: %" B_PRId32 "\n", fPCIInfo->u.h0.base_registers[0],
fPCIInfo->u.h0.base_registers[1], physicalAddress, offset,
fPCIInfo->u.h0.base_register_sizes[0]);
fRegisterArea = map_physical_memory("XHCI memory mapped registers",
physicalAddressAligned, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
(void **)&fCapabilityRegisters);
(void **)&fRegisters);
if (fRegisterArea < B_OK) {
TRACE("failed to map register memory\n");
TRACE_ERROR("failed to map register memory\n");
return;
}
uint32 hciCapLength = ReadCapReg32(XHCI_HCI_CAPLENGTH);
fCapabilityRegisters += offset;
fCapabilityLength = HCI_CAPLENGTH(hciCapLength);
TRACE("mapped capability length: 0x%" B_PRIx32 "\n", fCapabilityLength);
fOperationalRegisters = fCapabilityRegisters + fCapabilityLength;
fRuntimeRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_RTSOFF);
fDoorbellRegisters = fCapabilityRegisters + ReadCapReg32(XHCI_DBOFF);
TRACE("mapped capability registers: 0x%p\n", fCapabilityRegisters);
TRACE("mapped operational registers: 0x%p\n", fOperationalRegisters);
TRACE("mapped runtime registers: 0x%p\n", fRuntimeRegisters);
TRACE("mapped doorbell registers: 0x%p\n", fDoorbellRegisters);
// determine the register offsets
fCapabilityRegisterOffset = 0;
fOperationalRegisterOffset = HCI_CAPLENGTH(ReadCapReg32(XHCI_HCI_CAPLENGTH));
fRuntimeRegisterOffset = ReadCapReg32(XHCI_RTSOFF) & ~0x1F;
fDoorbellRegisterOffset = ReadCapReg32(XHCI_DBOFF) & ~0x3;
TRACE("mapped registers: %p\n", fRegisters);
TRACE("operational register offset: %d\n", fOperationalRegisterOffset);
TRACE("runtime register offset: %p\n", fRuntimeRegisterOffset);
TRACE("doorbell register offset: %p\n", fDoorbellRegisterOffset);
TRACE_ALWAYS("interface version: 0x%04" B_PRIx32 "\n",
HCI_VERSION(ReadCapReg32(XHCI_HCI_VERSION)));
@ -521,11 +514,11 @@ XHCI::Start()
TRACE("setting ERDP addr = 0x%" B_PRIx64 "\n", fErst->rs_addr);
WriteRunReg32(XHCI_ERDP_LO(0), (uint32)fErst->rs_addr);
WriteRunReg32(XHCI_ERDP_HI(0), /*(uint32)(fErst->rs_addr >> 32)*/0);
WriteRunReg32(XHCI_ERDP_HI(0), (uint32)(fErst->rs_addr >> 32));
TRACE("setting ERST base addr = 0x%" B_PRIxPHYSADDR "\n", dmaAddress);
WriteRunReg32(XHCI_ERSTBA_LO(0), (uint32)dmaAddress);
WriteRunReg32(XHCI_ERSTBA_HI(0), /*(uint32)(dmaAddress >> 32)*/0);
WriteRunReg32(XHCI_ERSTBA_HI(0), (uint32)(dmaAddress >> 32));
dmaAddress += sizeof(xhci_erst_element) + XHCI_MAX_EVENTS
* sizeof(xhci_trb);
@ -544,7 +537,7 @@ XHCI::Start()
}
TRACE("setting CRCR addr = 0x%" B_PRIxPHYSADDR "\n", dmaAddress);
WriteOpReg(XHCI_CRCR_LO, (uint32)dmaAddress | CRCR_RCS);
WriteOpReg(XHCI_CRCR_HI, /*(uint32)(dmaAddress >> 32)*/0);
WriteOpReg(XHCI_CRCR_HI, (uint32)(dmaAddress >> 32));
// link trb
fCmdRing[XHCI_MAX_COMMANDS - 1].qwtrb0 = dmaAddress;
@ -2134,7 +2127,7 @@ XHCI::DoCommand(xhci_trb* trb)
TRACE("Command Complete. Result: %" B_PRId32 "\n", completionCode);
if (completionCode != COMP_SUCCESS) {
uint32 errorCode = TRB_2_COMP_CODE_GET(fCmdResult[0]);
TRACE_ERROR("unsuccessful command %s (%" B_PRId32 ")\n",
TRACE_ERROR("unsuccessful command, error %s (%" B_PRId32 ")\n",
xhci_error_string(errorCode), errorCode);
status = B_IO_ERROR;
}
@ -2456,7 +2449,6 @@ XHCI::FinishTransfers()
Lock();
}
Unlock();
}
}
@ -2464,14 +2456,14 @@ XHCI::FinishTransfers()
inline void
XHCI::WriteOpReg(uint32 reg, uint32 value)
{
*(volatile uint32 *)(fOperationalRegisters + reg) = value;
*(volatile uint32 *)(fRegisters + fOperationalRegisterOffset + reg) = value;
}
inline uint32
XHCI::ReadOpReg(uint32 reg)
{
return *(volatile uint32 *)(fOperationalRegisters + reg);
return *(volatile uint32 *)(fRegisters + fOperationalRegisterOffset + reg);
}
@ -2501,42 +2493,42 @@ XHCI::WaitOpBits(uint32 reg, uint32 mask, uint32 expected)
inline uint32
XHCI::ReadCapReg32(uint32 reg)
{
return *(volatile uint32 *)(fCapabilityRegisters + reg);
return *(volatile uint32 *)(fRegisters + fCapabilityRegisterOffset + reg);
}
inline void
XHCI::WriteCapReg32(uint32 reg, uint32 value)
{
*(volatile uint32 *)(fCapabilityRegisters + reg) = value;
*(volatile uint32 *)(fRegisters + fCapabilityRegisterOffset + reg) = value;
}
inline uint32
XHCI::ReadRunReg32(uint32 reg)
{
return *(volatile uint32 *)(fRuntimeRegisters + reg);
return *(volatile uint32 *)(fRegisters + fRuntimeRegisterOffset + reg);
}
inline void
XHCI::WriteRunReg32(uint32 reg, uint32 value)
{
*(volatile uint32 *)(fRuntimeRegisters + reg) = value;
*(volatile uint32 *)(fRegisters + fRuntimeRegisterOffset + reg) = value;
}
inline uint32
XHCI::ReadDoorReg32(uint32 reg)
{
return *(volatile uint32 *)(fDoorbellRegisters + reg);
return *(volatile uint32 *)(fRegisters + fDoorbellRegisterOffset + reg);
}
inline void
XHCI::WriteDoorReg32(uint32 reg, uint32 value)
{
*(volatile uint32 *)(fDoorbellRegisters + reg) = value;
*(volatile uint32 *)(fRegisters + fDoorbellRegisterOffset + reg) = value;
}

View File

@ -210,14 +210,13 @@ private:
static pci_module_info * sPCIModule;
static pci_x86_module_info *sPCIx86Module;
uint8 * fCapabilityRegisters;
uint32 fCapabilityLength;
uint8 * fOperationalRegisters;
uint32 fOperationalLength;
uint8 * fRuntimeRegisters;
uint32 fRuntimeLength;
uint8 * fDoorbellRegisters;
area_id fRegisterArea;
uint8 * fRegisters;
uint32 fCapabilityRegisterOffset;
uint32 fOperationalRegisterOffset;
uint32 fRuntimeRegisterOffset;
uint32 fDoorbellRegisterOffset;
pci_info * fPCIInfo;
Stack * fStack;
uint8 fIRQ;