2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/panic.h"
5#include "pedigree/kernel/time/Time.h"
6#include "pedigree/kernel/utilities/utility.h"
10uint32_t* Xhci::inputContext(
size_t index) {
11 return reinterpret_cast<uint32_t*
>(
static_cast<uint8_t*
>(m_Input.
virtualAddress()) +
12 index * m_ContextSize);
14uint32_t* Xhci::outputContext(uint8_t slot,
size_t index) {
15 return reinterpret_cast<uint32_t*
>(
static_cast<uint8_t*
>(m_Slots[slot].output.
virtualAddress()) +
16 index * m_ContextSize);
18uint8_t Xhci::findSlot(
const UsbEndpoint& endpoint)
const {
19 if (endpoint.nAddress >= 128 || endpoint.nRootPort >= m_PortCount || endpoint.nHubAddress)
22 endpoint.nAddress ? m_Addresses[endpoint.nAddress] : m_PortSlots[endpoint.nRootPort];
23 const uint32_t status = read(m_Op + 0x400 + endpoint.nRootPort * 16);
24 if (!slot || slot > m_SlotCount || m_Slots[slot].port != endpoint.nRootPort ||
25 m_Slots[slot].generation != endpoint.nRootPortGeneration ||
27 m_Ports[endpoint.nRootPort].changePending || !(status & 1U) || (status & (1U << 17)))
31bool Xhci::prepareDevice(uint8_t address,
const UsbEndpoint& endpoint) {
33 if (!m_Submissions.
tryAcquire(admission) || !address || address >= 128 ||
34 endpoint.nRootPort >= m_PortCount || endpoint.nHubAddress)
37 const uint8_t port = endpoint.nRootPort;
38 if (m_Addresses[address] || m_PortSlots[port])
41 if (!command({0, 0, (9U << 10) | (uint32_t{m_Ports[port].slotType} << 16)}, &slotId))
43 if (!slotId || slotId > m_SlotCount || m_Slots[slotId].logical)
44 panic(
"xHCI: controller returned invalid slot ownership");
45 auto& slot = m_Slots[slotId];
46 slot.logical = address;
48 slot.generation = endpoint.nRootPortGeneration;
49 slot.speedId = (read(m_Op + 0x400 + port * 16) >> 10) & 15U;
50 m_Addresses[address] = slotId;
51 m_PortSlots[port] = slotId;
52 if (!m_Ports[port].validSpeed[slot.speedId] || !allocate(slot.output, 1))
54 auto* ep =
new Endpoint;
55 slot.endpoints[1] = ep;
56 ep->description = endpoint;
57 if (!ep->ring.initialise())
59 static_cast<uint64_t*
>(m_Dcbaa.
virtualAddress())[slotId] = slot.output.physicalAddress();
61 inputContext(0)[1] = 3;
62 uint32_t* device = inputContext(1);
63 device[0] = (uint32_t{slot.speedId} << 20) | (1U << 27);
64 device[1] = (uint32_t{port + 1U} << 16);
65 uint32_t* control = inputContext(2);
66 control[1] = (3U << 1) | (4U << 3) | (endpoint.nMaxPacketSize << 16);
67 const uint64_t dequeue = ep->ring.enqueuePointer();
69 control[3] = dequeue >> 32;
72 if (!command({m_Input.
physicalAddress(), 0, (11U << 10) | (1U << 9) | (uint32_t{slotId} << 24)}))
74 NOTICE(
"xHCI: logical address " <<
Dec << address <<
" slot " << slotId <<
" root port "
75 << port + 1U <<
" USB" << m_Ports[port].major <<
" speed ID "
76 << slot.speedId <<
Hex);
79bool Xhci::addressDevice(uint8_t address,
const UsbEndpoint& endpoint) {
84 const uint8_t slotId = findSlot(endpoint);
85 if (!slotId || m_Slots[slotId].logical != address)
87 auto& slot = m_Slots[slotId];
88 auto* ep = slot.endpoints[1];
90 inputContext(0)[1] = 2;
91 MemoryCopy(inputContext(2), outputContext(slotId, 1), m_ContextSize);
92 inputContext(2)[0] &= ~7U;
93 inputContext(2)[1] = (inputContext(2)[1] & 0xffffU) | (endpoint.nMaxPacketSize << 16);
94 if (ep->description.nMaxPacketSize != endpoint.nMaxPacketSize &&
95 !command({m_Input.
physicalAddress(), 0, (13U << 10) | (uint32_t{slotId} << 24)}))
97 ep->description.nMaxPacketSize = endpoint.nMaxPacketSize;
98 inputContext(0)[1] = 3;
99 MemoryCopy(inputContext(1), outputContext(slotId, 0), m_ContextSize);
100 inputContext(1)[3] = 0;
101 const uint64_t dequeue = ep->ring.enqueuePointer();
102 inputContext(2)[2] = dequeue;
103 inputContext(2)[3] = dequeue >> 32;
105 return command({m_Input.
physicalAddress(), 0, (11U << 10) | (uint32_t{slotId} << 24)});
108 auto& slot = m_Slots[slotId];
109 const uint8_t dci = description.nEndpoint ? description.nEndpoint * 2 + description.nIn : 1;
110 if (dci >= 32 || description.nStreams || description.nMaxBurst > 15 ||
111 description.nTransferType == 1 || description.nMaxPacketSize > 1024)
113 if (slot.endpoints[dci]) {
114 auto* endpoint = slot.endpoints[dci];
115 if (endpoint->needsReset && !resetEndpointHardware(slotId, dci,
false))
119 if (!description.nEndpoint || (description.nTransferType != 2 && description.nTransferType != 3))
121 auto* endpoint =
new Endpoint;
122 endpoint->description = description;
123 if (!endpoint->ring.initialise()) {
127 uint32_t interval = 0;
128 if (description.nTransferType == 3) {
129 if (!description.nInterval) {
133 if (description.speed == HighSpeed || description.speed == SuperSpeed) {
134 if (description.nInterval > 16) {
138 interval = description.nInterval - 1;
141 for (
size_t frames = description.nInterval; frames >= 2; frames /= 2)
146 inputContext(0)[1] = 1U | (1U << dci);
147 MemoryCopy(inputContext(1), outputContext(slotId, 0), m_ContextSize);
148 const size_t entries = dci > slot.contextEntries ? dci : slot.contextEntries;
149 inputContext(1)[0] = (inputContext(1)[0] & ~(31U << 27)) | (entries << 27);
150 inputContext(1)[3] = 0;
151 uint32_t* context = inputContext(dci + 1);
152 size_t esit = description.nTransferType == 3
153 ? (description.nBytesPerInterval ? description.nBytesPerInterval
154 : description.nMaxPacketSize)
156 context[0] = (interval << 16) | ((esit >> 16) << 24);
157 const uint32_t type = (description.nTransferType == 2 ? 2U : 3U) + (description.nIn ? 4U : 0U);
158 context[1] = (3U << 1) | (type << 3) | (uint32_t{description.nMaxBurst} << 8) |
159 (description.nMaxPacketSize << 16);
160 const uint64_t dequeue = endpoint->ring.enqueuePointer();
161 context[2] = dequeue;
162 context[3] = dequeue >> 32;
163 context[4] = description.nMaxPacketSize | ((esit & 0xffffU) << 16);
165 if (!command({m_Input.
physicalAddress(), 0, (12U << 10) | (uint32_t{slotId} << 24)})) {
169 slot.endpoints[dci] = endpoint;
170 slot.contextEntries = entries;
173bool Xhci::resetEndpointHardware(uint8_t slotId, uint8_t dci,
bool stop) {
174 auto* endpoint = m_Slots[slotId].endpoints[dci];
177 const uint32_t state = outputContext(slotId, dci)[0] & 7U;
178 const uint32_t target = (uint32_t{slotId} << 24) | (uint32_t{dci} << 16);
180 if (!command({0, 0, (14U << 10) | target}))
182 }
else if (state == 1 && stop) {
183 if (!command({0, 0, (15U << 10) | target}))
185 }
else if (state != 3)
187 if (!command({endpoint->ring.enqueuePointer(), 0, (16U << 10) | target}))
189 endpoint->needsReset =
false;
192bool Xhci::resetEndpoint(
const UsbEndpoint& endpoint) {
197 const uint8_t slot = findSlot(endpoint);
198 const uint8_t dci = endpoint.nEndpoint ? endpoint.nEndpoint * 2 + endpoint.nIn : 1;
199 if (!slot || dci >= 32 || !m_Slots[slot].endpoints[dci])
201 return resetEndpointHardware(slot, dci,
true);
205 const uint8_t slotId = m_Addresses[address];
208 const bool retired = m_Online && command({0, 0, (10U << 10) | (uint32_t{slotId} << 24)});
209 if (m_Online && !retired) {
214 auto& slot = m_Slots[slotId];
215 for (
auto*& endpoint : slot.endpoints) {
216 if (endpoint && endpoint->active)
217 panic(
"xHCI: logical address retired with an owned transfer");
223 m_PortSlots[slot.port] = 0;
224 m_Addresses[address] = 0;
227 slot.contextEntries = 1;
228#if PEDIGREE_USB_SMOKE_TESTS
229 if (retired && !m_Failed)
230 NOTICE(
"XHCI-SMOKE: slot-retired logical=" <<
Hex << address);
void * virtualAddress() const
physical_uintptr_t physicalAddress() const
MUST_USE_RESULT bool tryAcquire(Lease &lease)
void releaseDeviceAddress(uint8_t address) override
size_t currentRootPortGeneration(size_t port) const override
void EXPORTED_PUBLIC panic(const char *msg) NORETURN