2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/machine/IrqManager.h"
5#include "pedigree/kernel/machine/Machine.h"
6#include "pedigree/kernel/machine/Pci.h"
7#include "pedigree/kernel/panic.h"
8#include "pedigree/kernel/process/TerminationDeferral.h"
9#include "pedigree/kernel/process/Thread.h"
12using namespace XhciHw;
16 write(m_Runtime + 0x20, 1);
17 write(m_Op, read(m_Op) & ~5U);
19 return wait(m_Op + 4, 1, 1, 1000);
21void Xhci::failLocked() {
25 panic(
"xHCI: DMA did not halt; refusing to release memory");
29 ERROR(
"xHCI: controller halted after transport failure");
31 for (
auto* transaction : m_Transactions)
32 if (transaction && transaction->submitted && !transaction->captured)
33 finishLocked(*transaction, -TransactionError, false);
35void Xhci::cancelTransfer(uintptr_t
id,
size_t generation,
bool recurring,
36 void (*callback)(uintptr_t, ssize_t), uintptr_t parameter) {
41 uint8_t slot = 0, dci = 0;
45 if (
id >= MaxTransactions || !m_Transactions[
id])
47 auto& transaction = *m_Transactions[id];
48 if (transaction.callback != callback || transaction.parameter != parameter ||
49 transaction.periodic != recurring || (recurring && transaction.generation != generation))
51 generation = transaction.generation;
52 transaction.cancelling =
true;
53 slot = transaction.slot;
54 dci = transaction.dci;
55 stop = transaction.submitted && m_Online;
57 if (stop && !resetEndpointHardware(slot, dci,
true)) {
63 auto* transaction = m_Transactions[id];
64 if (transaction && transaction->generation == generation) {
66 if (transaction->submitted)
67 transaction->endpoint->ring.retire(transaction->trbCount);
68 transaction->endpoint->active =
nullptr;
69 freeTransactionLocked(
id);
71 }
else if (!transaction->captured)
72 finishLocked(*transaction, -TransactionError,
false);
77 (void)m_Deliveries.
drain({
id, generation});
80 uintptr_t parameter) {
84 cancelTransfer(
id, 0,
false, callback, parameter);
87 void (*callback)(uintptr_t, ssize_t), uintptr_t parameter,
88 bool producerAlreadyStopped) {
91 panic(
"xHCI: interrupt cancellation raced controller destruction");
92 if (!producerAlreadyStopped)
93 cancelTransfer(token.transaction, token.generation,
true, callback, parameter);
96void Xhci::shutdown() {
101 m_PortsClosing =
true;
102 for (
size_t i = 0; i < m_PortCount; ++i)
103 m_PortChanges[i].stopAfterQuiesce();
111 panic(
"xHCI: controller teardown could not halt DMA");
114 for (
auto* transaction : m_Transactions)
115 if (transaction && transaction->submitted)
116 finishLocked(*transaction, -TransactionError, false);
118 if (m_Irq && !Machine::instance().getIrqManager()->unregisterHandler(m_Irq,
this))
119 panic(
"xHCI: interrupt retirement failed");
125 m_DeliveryStopping =
true;
129 panic(
"xHCI: callback worker did not drain");
130 m_DeliveryThread =
nullptr;
131 for (
auto* transaction : m_Transactions)
133 for (
auto& slot : m_Slots)
134 for (auto* endpoint : slot.endpoints)
136 for (
auto* scratch : m_Scratch)
138 if (m_HardwareOwned) {
139 write64(m_Op + 0x30, 0);
140 write64(m_Op + 0x18, 0);
141 write(m_Runtime + 0x28, 0);
142 write64(m_Runtime + 0x30, 0);
143 write64(m_Runtime + 0x38, 0);
145 if (m_HardwareOwned && !PciBus::instance().updateCommand(m_Pci, 4, 0x400))
146 panic(
"xHCI: teardown could not disable PCI DMA and INTx");
MUST_USE_RESULT bool tryAcquire(Lease &lease)
bool drain(const Key &key)
bool cancelSubscription(uintptr_t transaction, size_t subscription)
void disconnectAllDevices()
bool cancelInterruptInAndDrain(const UsbInterruptInToken &, void(*)(uintptr_t, ssize_t), uintptr_t, bool producerAlreadyStopped) override
void cancelAsyncAndDrain(uintptr_t transaction, void(*callback)(uintptr_t, ssize_t), uintptr_t parameter) override
void EXPORTED_PUBLIC panic(const char *msg) NORETURN