7#include "pedigree/kernel/LockGuard.h"
8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/machine/Device.h"
10#include "pedigree/kernel/machine/IrqHandler.h"
11#include "pedigree/kernel/machine/IrqManager.h"
12#include "pedigree/kernel/machine/Pci.h"
13#include "pedigree/kernel/processor/InterruptManager.h"
14#include "pedigree/kernel/processor/Processor.h"
15#include "pedigree/kernel/processor/ProcessorInformation.h"
19#include "PciMessageInterrupts.h"
21PciMessageInterrupts::PciMessageInterrupts()
22 : m_RegistrationLock(),
25 m_Dispatcher(MakeConstantString(
"PCI message IRQ"), VectorCount, dispatchThreaded, this),
27 m_DestinationApicId(0),
29 m_ShuttingDown(false) {}
31bool PciMessageInterrupts::initialise() {
34 for (; installed < VectorCount; ++installed) {
36 for (
size_t i = 0; i < installed; ++i) {
42 m_DestinationApicId = Pc::instance().getLocalApic().getId();
47bool PciMessageInterrupts::initialiseThreaded() {
49 return m_Initialised && m_Dispatcher.initialise(
true);
52bool PciMessageInterrupts::shutdownThreaded() {
53 if (!m_Dispatcher.canShutdown()) {
63 m_ShuttingDown =
true;
64 for (Line& line : m_Lines) {
66 if (line.device && !(line.msix ? PciBus::instance().disableMsix(line.device)
67 :
PciBus::instance().disableMsi(line.device))) {
72 return disabled && (!m_Dispatcher.isInitialised() || m_Dispatcher.shutdown());
75irq_id_t PciMessageInterrupts::registerThreaded(
Device* device,
IrqHandler* handler,
77 return registerHandler(device, handler, Mode::Threaded, fallbackSafe);
80bool PciMessageInterrupts::registerThreadedVectors(
Device* device,
IrqHandler*
const* handlers,
81 size_t count, irq_id_t* ids,
bool& fallbackSafe,
82 const size_t* processors) {
84 if (!device || !handlers || !ids || !count || count > VectorCount || !m_Initialised ||
85 !m_Dispatcher.isInitialised()) {
89 m_Dispatcher.isCurrentWorker()) {
93 for (
size_t i = 0; i < count; ++i) {
100 PciBus& pci = PciBus::instance();
102 if (!pci.inspectFunction(device, state,
false) || !state.msix) {
105 uint16_t control = 0;
106 if (!pci.readConfig16(device, state.msix + 2, control) || count > (control & 0x7ffU) + 1) {
110 uint8_t slots[VectorCount] = {};
111 uint32_t data[VectorCount] = {};
112 uint64_t addresses[VectorCount] = {};
113 bool selected[VectorCount] = {};
114 bool reused[VectorCount] = {};
117 if (m_ShuttingDown) {
120 for (
const Line& line : m_Lines) {
121 if (line.device == device) {
122 fallbackSafe =
false;
126 for (
size_t i = 0; i < count; ++i) {
127 const size_t cpu = processors ? processors[i] : 0;
130 for (; slot < VectorCount; ++slot) {
131 const Line& line = m_Lines[slot];
132 if (!selected[slot] && !line.device && (!line.used || (line.reusable && spuriousSafe)) &&
133 (!(line.used || line.workerPrepared) || line.processor == cpu)) {
137 if (slot == VectorCount) {
140 slots[i] =
static_cast<uint8_t
>(slot);
141 selected[slot] =
true;
142 reused[i] = m_Lines[slot].used;
147 for (
size_t i = 0; i < count; ++i) {
148 const size_t cpu = processors ? processors[i] : 0;
149 if (!m_Dispatcher.prepareLine(slots[i], cpu)) {
153 Line& line = m_Lines[slots[i]];
154 line.workerPrepared =
true;
155 line.processor = cpu;
160 for (
size_t i = 0; i < count; ++i) {
161 const uint8_t vector = FirstVector + slots[i];
162 if (!m_Handlers.registerThreadedHandler(vector, handlers[i], IrqPolicy::edgeThreaded())) {
163 for (
size_t j = 0; j < i; ++j) {
164 const uint8_t previous = FirstVector + slots[j];
165 if (m_Handlers.unregisterHandler(previous, handlers[j]) !=
166 IrqHandlerRegistry::UnregisterResult::Completed) {
167 FATAL(
"PCI message registration could not drain its unpublished handler");
169 Line& previousLine = m_Lines[slots[j]];
170 previousLine.device =
nullptr;
171 previousLine.handler =
nullptr;
172 previousLine.mode = Mode::None;
173 previousLine.enabled =
false;
177 Line& line = m_Lines[slots[i]];
178 line.device = device;
179 line.handler = handlers[i];
180 line.mode = Mode::Threaded;
183 line.removing =
false;
184 line.deferred =
false;
186 line.enabled =
false;
188 line.msixIndex =
static_cast<uint8_t
>(i);
191 for (
size_t i = 0; i < count; ++i) {
192 m_Lines[slots[i]].enabled =
true;
196 bool touched =
false;
197 if (pci.enableMsixVectors(device, addresses[0], data, count, &touched, addresses)) {
200 for (
size_t i = 0; i < count; ++i) {
201 m_Lines[slots[i]].used =
true;
202 m_Lines[slots[i]].reusable =
false;
203 ids[i] =
static_cast<irq_id_t
>(data[i]);
206 for (
size_t i = 0; i < count; ++i) {
207 NOTICE(
"PCI MSI-X: vector " <<
Dec << data[i] <<
" CPU " << m_Lines[slots[i]].processor
208 << (reused[i] ?
" reused" :
" allocated") <<
Hex);
213 uint16_t command = 0;
214 bool disabled = pci.disableMessageInterrupts(device, state);
216 for (
size_t i = 0; i < count; ++i) {
217 const bool masked = pci.setMsixVectorMask(device, i,
true);
218 disabled = masked && disabled;
221 disabled = pci.updateCommand(device, 0x400U, state.command & 0x400U) && disabled;
223 pci.readConfig16(device, 4, command) && ((command ^ state.command) & 0x400U) == 0 && disabled;
224 size_t cookies[VectorCount] = {};
227 for (
size_t i = 0; i < count; ++i) {
228 Line& line = m_Lines[slots[i]];
229 line.enabled =
false;
230 line.removing =
true;
231 cookies[i] = advanceCookie(line);
234 for (
size_t i = 0; i < count; ++i) {
235 const uint8_t vector = FirstVector + slots[i];
236 m_Handlers.invalidateThreadedLine(vector, cookies[i]);
237 if (m_Handlers.unregisterHandler(vector, handlers[i]) !=
238 IrqHandlerRegistry::UnregisterResult::Completed) {
239 FATAL(
"PCI message registration could not drain its unpublished handler");
244 for (
size_t i = 0; i < count; ++i) {
245 Line& line = m_Lines[slots[i]];
246 line.device =
nullptr;
247 line.handler =
nullptr;
248 line.mode = Mode::None;
249 line.used = line.used || touched || !disabled;
250 line.reusable = disabled;
254 fallbackSafe =
false;
255 ERROR(
"PCI MSI-X setup failed without verified source shutdown");
261 bool& fallbackSafe) {
262 return registerHandler(device, handler, Mode::Hard, fallbackSafe);
265irq_id_t PciMessageInterrupts::registerHandler(
Device* device,
IrqHandlerBase* handler, Mode mode,
266 bool& fallbackSafe) {
268 if (!device || !handler || !m_Initialised ||
269 (mode == Mode::Threaded && !m_Dispatcher.isInitialised())) {
273 m_Dispatcher.isCurrentWorker()) {
277 const bool spuriousSafe =
278 mode == Mode::Threaded &&
static_cast<IrqHandler*
>(handler)->acceptsSpuriousInterrupts();
279 PciBus& pci = PciBus::instance();
281 if (!pci.inspectFunction(device, state,
false) || (!state.msi && !state.msix)) {
285 size_t slot = VectorCount;
288 if (m_ShuttingDown) {
291 for (
size_t i = 0; i < VectorCount; ++i) {
292 if (m_Lines[i].device == device) {
293 fallbackSafe =
false;
296 const Line& candidate = m_Lines[i];
297 if (slot == VectorCount && !candidate.device &&
298 (!candidate.used || (candidate.reusable && spuriousSafe)) &&
299 (!(candidate.used || candidate.workerPrepared) || !candidate.processor)) {
303 if (slot == VectorCount) {
307 if (mode == Mode::Threaded && !m_Dispatcher.prepareLine(slot, 0)) {
312 m_Lines[slot].processor = 0;
313 m_Lines[slot].workerPrepared |= mode == Mode::Threaded;
314 const uint8_t vector = FirstVector + slot;
315 const bool registered =
316 mode == Mode::Threaded
317 ? m_Handlers.registerThreadedHandler(vector,
static_cast<IrqHandler*
>(handler),
318 IrqPolicy::edgeThreaded())
319 : m_Handlers.registerHardHandler(
321 IrqPolicy(IrqTrigger::Edge, IrqControllerAck::AfterHardStage,
322 IrqLineRelease::AfterHardStage));
326 Line& line = m_Lines[slot];
327 line.device = device;
328 line.handler = handler;
331 line.spuriousSafe = spuriousSafe;
332 line.reusable =
false;
333 line.removing =
false;
337 line.deferred =
false;
342 const uint8_t vector = FirstVector + slot;
343 const uint64_t address = 0xFEE00000ULL | (uint64_t{m_DestinationApicId} << 12);
344 if (state.msix && pci.enableMsix(device, address, vector)) {
349 m_Lines[slot].msix =
false;
351 if (state.msi && pci.enableMsi(device, address, vector)) {
358 uint16_t command = 0;
359 fallbackSafe = pci.disableMessageInterrupts(device, state) &&
360 pci.updateCommand(device, 0x400U, state.command & 0x400U) &&
361 pci.readConfig16(device, 4, command) && ((command ^ state.command) & 0x400U) == 0;
365 m_Lines[slot].enabled =
false;
366 m_Lines[slot].removing =
true;
371 cookie = advanceCookie(m_Lines[slot]);
373 m_Handlers.invalidateThreadedLine(vector, cookie);
374 if (m_Handlers.unregisterHandler(vector, handler) !=
375 IrqHandlerRegistry::UnregisterResult::Completed) {
376 FATAL(
"PCI message registration could not drain its unpublished handler");
380 m_Lines[slot].device =
nullptr;
381 m_Lines[slot].handler =
nullptr;
382 m_Lines[slot].mode = Mode::None;
383 m_Lines[slot].reusable = fallbackSafe;
386 ERROR(
"PCI message setup failed without a safe INTx fallback");
391bool PciMessageInterrupts::disableSource(
Device* device,
bool msix, uint8_t msixIndex) {
392 return msix ? PciBus::instance().setMsixVectorMask(device, msixIndex,
true)
393 : PciBus::instance().disableMsi(device);
396bool PciMessageInterrupts::unregisterHandler(irq_id_t
id,
IrqHandlerBase* handler) {
397 if (!contains(
id) || !handler) {
401 m_Dispatcher.isCurrentWorker()) {
405 const uint8_t slot =
id - FirstVector;
408 Line& line = m_Lines[slot];
409 if (line.handler != handler || !line.device) {
412 line.removing =
true;
413 line.enabled =
false;
414 if (!disableSource(line.device, line.msix, line.msixIndex)) {
421 cookie = advanceCookie(m_Lines[slot]);
423 m_Handlers.invalidateThreadedLine(
id, cookie);
424 const IrqHandlerRegistry::UnregisterResult result = m_Handlers.unregisterHandler(
id, handler);
425 if (result == IrqHandlerRegistry::UnregisterResult::Deferred) {
427 m_Lines[slot].deferred =
true;
430 if (result == IrqHandlerRegistry::UnregisterResult::NotFound) {
431 bool deferred =
false;
434 deferred = m_Lines[slot].deferred;
436 size_t generation = 0;
438 if (!deferred || m_Handlers.handlerCount(
id) || m_Handlers.hardDispatchState(
id, generation) ||
439 m_Handlers.threadedDispatchState(
id,
identity)) {
442 }
else if (result != IrqHandlerRegistry::UnregisterResult::Completed) {
447 Line& line = m_Lines[slot];
449 for (
const Line& other : m_Lines) {
450 if (&other != &line && other.device == line.device) {
455 if (last && line.msix && !PciBus::instance().disableMsix(line.device)) {
456 line.deferred =
true;
459 line.device =
nullptr;
460 line.handler =
nullptr;
461 line.mode = Mode::None;
462 line.reusable =
true;
467void PciMessageInterrupts::enable(irq_id_t
id,
bool enabled) {
471 const uint8_t slot =
id - FirstVector;
472 bool success =
false;
475 Line& line = m_Lines[slot];
476 if (!line.device || line.removing || m_ShuttingDown || line.enabled == enabled) {
479 const uint64_t address = 0xFEE00000ULL | (uint64_t{m_DestinationApicId} << 12);
482 ? (line.msix ? PciBus::instance().setMsixVectorMask(line.device, line.msixIndex,
false)
483 : PciBus::instance().enableMsi(line.device, address,
id))
484 : disableSource(line.device, line.msix, line.msixIndex);
485 line.enabled = enabled && success;
491 WARNING(
"PCI message IRQ " <<
Dec <<
id <<
" could not be "
492 << (enabled ?
"enabled" :
"disabled"));
496void PciMessageInterrupts::quarantine(uint8_t slot,
size_t expectedCookie) {
500 Line& line = m_Lines[slot];
501 if (!line.enabled || line.removing || (expectedCookie && line.cookie != expectedCookie)) {
504 line.enabled =
false;
505 masked = disableSource(line.device, line.msix, line.msixIndex);
508 ERROR(
"PCI message IRQ " <<
Dec << FirstVector + slot <<
" could not be masked");
512void PciMessageInterrupts::interrupt(
size_t interruptNumber, InterruptState& state) {
513 if (interruptNumber < FirstVector || interruptNumber >= FirstVector + VectorCount) {
516 const uint8_t slot = interruptNumber - FirstVector;
518 Mode mode = Mode::None;
520 bool published =
false;
524 Line& line = m_Lines[slot];
525 if (line.enabled && !line.removing && !m_ShuttingDown) {
527 cookie = advanceCookie(line);
528 const uint8_t vector = FirstVector + slot;
529 if (m_Handlers.captureAdmissionCutoff(vector, cutoff)) {
530 if (mode == Mode::Threaded) {
531 published = m_Handlers.publishThreadedDispatch(vector, cookie, cutoff);
532 if (published && !m_Dispatcher.publishFromInterrupt(slot, cookie)) {
533 m_Handlers.invalidateThreadedGenerationFromInterrupt(vector, cookie);
543 if (mode == Mode::Hard && published) {
545 const bool admitted =
546 m_Handlers.dispatchHard(FirstVector + slot, state, result,
nullptr, cookie, cutoff);
547 if (!admitted || result != HardIrqDisposition::Handled) {
548 quarantine(slot, cookie);
550 }
else if (mode != Mode::None && !published) {
551 quarantine(slot, cookie);
553 Pc::instance().getLocalApic().ack();
556void PciMessageInterrupts::dispatchThreaded(
void* context, uint8_t slot,
size_t cookie) {
557 PciMessageInterrupts* self =
static_cast<PciMessageInterrupts*
>(context);
558 if (slot >= VectorCount) {
563 const Line& line = self->m_Lines[slot];
564 if (!line.enabled || line.removing || line.mode != Mode::Threaded || cookie != line.cookie) {
569 const bool admitted = self->m_Handlers.dispatchThreaded(FirstVector + slot, cookie, result);
570 bool mask = !admitted;
573 Line& line = self->m_Lines[slot];
574 if (line.enabled && !line.removing && line.mode == Mode::Threaded && cookie == line.cookie) {
575 if (result.allowRearm) {
577 }
else if (!line.spuriousSafe) {
580 if (line.unhandled < 8) {
583 mask = line.unhandled == 8;
588 self->quarantine(slot, cookie);
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
virtual bool acceptsSpuriousInterrupts() const
static ExecutionContext executionContext()
static ProcessorInformation * informationAt(size_t cpu)