3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/Log.h"
5#include "pedigree/kernel/machine/IrqManager.h"
6#include "pedigree/kernel/machine/Machine.h"
7#include "pedigree/kernel/machine/Pci.h"
8#include "pedigree/kernel/machine/PciFunctionState.h"
9#include "pedigree/kernel/panic.h"
10#include "pedigree/kernel/process/Thread.h"
11#include "pedigree/kernel/processor/IoBase.h"
12#include "pedigree/kernel/processor/Processor.h"
13#include "pedigree/kernel/processor/ProcessorInformation.h"
14#include "pedigree/kernel/time/Time.h"
15#include "pedigree/kernel/utilities/utility.h"
16using namespace XhciHw;
21 m_Events(
"xHCI events"),
23 m_Dcbaa(
"xHCI DCBAA"),
24 m_Input(
"xHCI input context"),
25 m_ScratchPointers(
"xHCI scratchpad pointers") {}
29uint32_t Xhci::read(
size_t offset)
const {
30 return m_Registers->
read32(offset);
32void Xhci::write(
size_t offset, uint32_t value) {
33 m_Registers->
write32(value, offset);
35void Xhci::write64(
size_t offset, uint64_t value) {
37 write(offset + 4, value >> 32);
39bool Xhci::wait(
size_t offset, uint32_t mask, uint32_t expected,
size_t milliseconds) {
40 const auto deadline = Time::getTicks() + milliseconds * Time::Multiplier::Millisecond;
42 const uint32_t value = read(offset);
43 if (value != 0xffffffffU && (value & mask) == expected)
45 Time::delay(Time::Multiplier::Millisecond);
46 }
while (Time::getTicks() < deadline);
49bool Xhci::parseCapabilities(uint32_t hcc) {
50 size_t offset = (hcc >> 16) * 4U;
51 for (
size_t count = 0; offset && count < 256; ++count) {
52 if (offset + 16 > m_Registers->
size())
54 const uint32_t cap = read(offset);
55 if ((cap & 255U) == 1) {
56 write(offset, cap | (1U << 24));
57 if (!wait(offset, (1U << 16) | (1U << 24), 1U << 24, 5000))
59 write(offset + 4, (read(offset + 4) & 0x000e1feeU) | 0xe0000000U);
60 if (read(offset + 4) & 0x0000e011U)
62 }
else if ((cap & 255U) == 2) {
63 const uint32_t ports = read(offset + 8);
64 const size_t first = ports & 255U, count = (ports >> 8) & 255U;
65 const size_t psiCount = ports >> 28;
66 const uint8_t major = cap >> 24;
67 if (!first || first - 1 + count > m_PortCount || (major != 2 && major != 3) ||
68 read(offset + 4) != 0x20425355U || offset + 16 + psiCount * 4 > m_Registers->
size())
70 for (
size_t port = first - 1; port < first - 1 + count; ++port) {
71 auto& target = m_Ports[port];
75 target.slotType = read(offset + 12) & 31U;
78 target.speeds[1] = FullSpeed;
79 target.speeds[2] = LowSpeed;
80 target.speeds[3] = HighSpeed;
81 target.validSpeed[1] = target.validSpeed[2] = target.validSpeed[3] =
true;
83 const uint8_t minor = (cap >> 16) & 255U;
84 const size_t last = minor >= 0x20 ? 7 : minor >= 0x10 ? 5 : 4;
85 for (
size_t id = 4;
id <= last; ++id) {
86 target.speeds[id] = SuperSpeed;
87 target.validSpeed[id] =
true;
91 for (
size_t i = 0; i < psiCount; ++i) {
92 const uint32_t psi = read(offset + 16 + i * 4);
93 const uint8_t
id = psi & 15U;
94 if (!
id || (psi & 0xc0U))
96 uint64_t rate = psi >> 16;
97 for (
size_t exponent = (psi >> 4) & 3U; exponent; --exponent)
102 else if (rate == 12000000)
104 else if (rate == 480000000)
106 else if (rate >= 5000000000ULL)
110 target.speeds[id] = speed;
111 target.validSpeed[id] =
true;
115 const size_t next = (cap >> 8) & 255U;
122bool Xhci::initialiseController() {
123#if PEDIGREE_USB_SMOKE_TESTS
124 if (!completionRegressions())
127 auto& pci = PciBus::instance();
129 if (!pci.inspectFunction(m_Pci, pciState)) {
130 ERROR(
"xHCI: unsupported inherited PCI function state");
133 const uint32_t bar = pciState.bars[0];
134 if ((bar & 1U) || ((bar & 6U) != 0 && (bar & 6U) != 4))
136 uint64_t base = bar & ~15U;
138 base |= uint64_t{pciState.bars[1]} << 32;
141 if (address->m_Name ==
"bar0" && base && !address->m_IsIoSpace && address->m_Address == base)
143 if (!mapping || mapping->
m_Size < 0x500)
146 if (!pci.updateCommand(m_Pci, 0, 2))
149 m_Registers = mapping->
m_Io;
152 const uint32_t version = read(0);
153 m_Op = version & 255U;
154 const uint32_t hcs1 = read(4), hcs2 = read(8), hcc = read(16);
155 const size_t portCount = hcs1 >> 24;
156 if (!portCount || portCount > MaxPorts)
158 m_PortCount = portCount;
159 m_SlotCount = (hcs1 & 255U) < MaxSlots ? hcs1 & 255U : MaxSlots;
160 m_ContextSize = hcc & 4U ? 64 : 32;
161 m_Doorbells = read(20) & ~3U;
162 m_Runtime = read(24) & ~31U;
163 if ((version >> 16) < 0x100 || m_Op < 0x20 || !m_SlotCount || !m_PortCount ||
164 m_PortCount > MaxPorts || m_Op + 0x400 + m_PortCount * 16 > m_Registers->
size() ||
165 m_Runtime + 0x40 > m_Registers->
size() ||
166 m_Doorbells + (m_SlotCount + 1) * 4 > m_Registers->
size() || !parseCapabilities(hcc))
168 for (
size_t i = 0; i < m_PortCount; ++i)
169 if (!m_Ports[i].major)
171 if (!wait(m_Op + 4, 1U << 11, 0, 1000))
173 m_HardwareOwned =
true;
174 write(m_Op, read(m_Op) & ~5U);
175 if (!wait(m_Op + 4, 1, 1, 1000))
177 write(m_Op, read(m_Op) | 2U);
178 if (!wait(m_Op, 2, 0, 1000) || !wait(m_Op + 4, 1U << 11, 0, 1000) || !(read(m_Op + 8) & 1U))
180 if (!pci.updateCommand(m_Pci, 4, 2 | 0x400) || !pci.disableMessageInterrupts(m_Pci, pciState)) {
181 ERROR(
"xHCI: could not establish masked PCI interrupt state");
184 if (!m_Commands.initialise() || !allocate(m_Events, 1) || !allocate(m_Erst, 1) ||
185 !allocate(m_Dcbaa, 1) || !allocate(m_Input, 1))
187 const size_t scratchpads = ((hcs2 >> 27) & 31U) | (((hcs2 >> 21) & 31U) << 5);
188 if (scratchpads > 32)
192 if (!allocate(m_ScratchPointers, 1))
195 auto* pointers =
static_cast<uint64_t*
>(m_ScratchPointers.
virtualAddress());
196 for (
size_t i = 0; i < scratchpads; ++i) {
198 if (!allocate(*m_Scratch[i], 1))
205 erst[1] = RingEntries;
208 if (!pci.resourcesUnchanged(m_Pci, pciState) || !pci.updateCommand(m_Pci, 0, 6 | 0x400)) {
209 ERROR(
"xHCI: PCI resources or DMA command changed during handoff");
213 write64(m_Op + 0x18, m_Commands.address() | 1U);
214 write(m_Op + 0x38, m_SlotCount);
215 write(m_Runtime + 0x28, 1);
218 write(m_Runtime + 0x24, 0);
219 write(m_Runtime + 0x20, 1);
220 write(m_Op + 4, 0x1c);
221 if (read(m_Op + 4) & ((1U << 12) | 4U))
225 for (
size_t port = 0; port < m_PortCount; ++port)
226 if (!m_PortChanges[port].configure(*
this, 0, port))
231 IrqPolicy::pciIntxThreaded());
236 if (!pci.updateCommand(m_Pci, 0x400, 6))
239 write(m_Runtime + 0x20, 3);
243 if (!wait(m_Op + 4, 1, 0, 1000))
245 for (
size_t port = 0; port < m_PortCount; ++port) {
247 const size_t reg = m_Op + 0x400 + port * 16;
248 const uint32_t status = read(reg);
249 write(reg, (status & 0x0e00c200U) | (1U << 9) | (status & PortChanges));
252 notifyPortLocked(port);
254 NOTICE(
"xHCI: controller ready, " <<
Dec << m_PortCount <<
" ports, " << m_SlotCount
255 <<
" slots, shared INTx" <<
Hex);
258bool Xhci::command(
Trb trb, uint8_t* returnedSlot) {
267 if (!m_Commands.enqueue(&trb, 1, &m_CommandAddress))
269 write(m_Doorbells, 0);
270 (void)read(m_Op + 4);
272 const auto deadline = Time::getTicks() + 5 * Time::Multiplier::Second;
275 collectEventsLocked(
false);
278 if (Time::getTicks() >= deadline) {
285 *returnedSlot = m_CommandSlot;
286 if (m_CommandCode != 1)
287 WARNING(
"xHCI: command " << ((trb.control >> 10) & 63U) <<
" failed: " << m_CommandCode);
288 return m_Online && m_CommandCode == 1;
void map(size_t forcedSize=0, bool bUser=false, bool bWriteCombine=false, bool bWriteThrough=false)
virtual Vector< Address * > & addresses()
Device * getParent() const
virtual void write32(uint32_t value, size_t offset=0)=0
virtual uint32_t read32(size_t offset=0)=0
virtual size_t size() const =0
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice, const IrqPolicy &policy)=0
Special memory entity in the kernel's virtual address space.
void * virtualAddress() const
physical_uintptr_t physicalAddress() const
static ProcessorInformation & information()
virtual void initialise()
MUST_USE_RESULT size_t drainAvailable()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)