9#include "pedigree/kernel/LockGuard.h"
10#include "pedigree/kernel/Log.h"
11#include "pedigree/kernel/machine/Device.h"
12#include "pedigree/kernel/machine/IrqHandler.h"
13#include "pedigree/kernel/machine/Pci.h"
14#include "pedigree/kernel/machine/SchedulerIrqHandler.h"
15#include "pedigree/kernel/processor/Processor.h"
17#include "DeviceTree.h"
18#include "system/kernel/core/processor/DeviceHardIrqContext.h"
21constexpr uintptr_t DistControl = 0x000;
22constexpr uintptr_t DistType = 0x004;
23constexpr uintptr_t DistGroup = 0x080;
24constexpr uintptr_t DistEnable = 0x100;
25constexpr uintptr_t DistDisable = 0x180;
26constexpr uintptr_t DistClearPending = 0x280;
27constexpr uintptr_t DistPriority = 0x400;
28constexpr uintptr_t DistTarget = 0x800;
29constexpr uintptr_t DistConfig = 0xc00;
30constexpr uintptr_t DistRouter = 0x6000;
31constexpr uintptr_t CpuControl = 0x000;
32constexpr uintptr_t CpuPriorityMask = 0x004;
33constexpr uintptr_t CpuAcknowledge = 0x00c;
34constexpr uintptr_t CpuEndOfInterrupt = 0x010;
35constexpr uintptr_t RedistWaker = 0x014;
36constexpr uintptr_t RedistSgi = 0x10000;
39uint32_t read32(uintptr_t base, uintptr_t offset) {
42 asm volatile(
"ldr %0, [%1]" :
"=r"(value) :
"r"(base + offset) :
"memory");
44 asm volatile(
"ldr %w0, [%1]" :
"=r"(value) :
"r"(base + offset) :
"memory");
49void write32(uintptr_t base, uintptr_t offset, uint32_t value) {
51 asm volatile(
"str %1, [%0]" : :
"r"(base + offset),
"r"(value) :
"memory");
53 asm volatile(
"str %w1, [%0]" : :
"r"(base + offset),
"r"(value) :
"memory");
58void write64(uintptr_t base, uintptr_t offset, uint64_t value) {
59 asm volatile(
"str %1, [%0]" : :
"r"(base + offset),
"r"(value) :
"memory");
64 asm volatile(
"dsb sy\n\tisb" : : :
"memory");
68uint64_t processorAffinity() {
70 asm volatile(
"mrs %0, mpidr_el1" :
"=r"(mpidr));
71 return (mpidr & 0xff00000000ULL) | (mpidr & 0x00ffffffULL);
82VirtIrqManager::VirtIrqManager()
86 m_PciDispatcher(MakeConstantString(
"Virt PCI IRQ"), MaxPciLines, dispatchPciLine, this),
96 m_Initialised(false) {}
98bool VirtIrqManager::initialise() {
102 m_Version = VirtDeviceTree::gicVersion();
103 m_Initialised = m_Version == 2 ? initialiseV2() : m_Version == 3 && initialiseV3();
105 m_MsiReady = initialiseMsi();
107 return m_Initialised;
110bool VirtIrqManager::initialiseThreaded() {
111 return m_Initialised && m_PciDispatcher.
initialise();
114bool VirtIrqManager::shutdownThreaded() {
117 for (
const PciLine& line : m_PciLines) {
118 if (line.handlers || line.reserved) {
122 for (
const PciLine& line : m_PciLines) {
124 setEnabled(line.irq,
false);
131bool VirtIrqManager::initialiseV2() {
132 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
133 const uintptr_t cpu = VirtDeviceTree::gicCpuBase();
138 write32(dist, DistControl, 0);
139 const size_t lines = ((read32(dist, DistType) & 0x1f) + 1) * 32;
140 const size_t count = lines < MaxIrqs ? lines : MaxIrqs;
142 for (
size_t irq = 0; irq < count; irq += 32) {
143 write32(dist, DistDisable + irq / 8, 0xffffffff);
145 for (
size_t irq = 0; irq < count; irq += 4) {
146 write32(dist, DistPriority + irq, 0xa0a0a0a0);
148 write32(dist, DistTarget + irq, 0x01010101);
151 write32(cpu, CpuPriorityMask, 0xff);
152 write32(cpu, CpuControl, 1);
153 write32(dist, DistControl, 1);
158bool VirtIrqManager::initialiseV3() {
162 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
163 const uintptr_t redist = VirtDeviceTree::gicRedistributorBase();
164 if (!dist || !redist) {
168 write32(dist, DistControl, 0);
169 for (
size_t wait = 0; wait < 100000 && (read32(dist, DistControl) & (1U << 31)); ++wait) {
170 asm volatile(
"yield");
173 write32(dist, DistControl, 1U << 4);
174 for (
size_t wait = 0; wait < 100000 && (read32(dist, DistControl) & (1U << 31)); ++wait) {
175 asm volatile(
"yield");
177 if (!(read32(dist, DistControl) & (1U << 4))) {
180 const size_t lines = ((read32(dist, DistType) & 0x1f) + 1) * 32;
181 const size_t count = lines < MaxIrqs ? lines : MaxIrqs;
183 for (
size_t irq = 32; irq < count; irq += 32) {
184 write32(dist, DistDisable + irq / 8, 0xffffffff);
185 write32(dist, DistGroup + irq / 8, 0xffffffff);
187 for (
size_t irq = 32; irq < count; irq += 4) {
188 write32(dist, DistPriority + irq, 0xa0a0a0a0);
191 const uint64_t affinity = processorAffinity();
192 for (
size_t irq = 32; irq < count; ++irq) {
193 write64(dist, DistRouter + irq * 8, affinity);
196 write32(redist, RedistWaker, read32(redist, RedistWaker) & ~(1U << 1));
197 for (
size_t wait = 0; wait < 100000 && (read32(redist, RedistWaker) & (1U << 2)); ++wait) {
198 asm volatile(
"yield");
200 if (read32(redist, RedistWaker) & (1U << 2)) {
204 const uintptr_t sgi = redist + RedistSgi;
205 write32(sgi, DistDisable, 0xffffffff);
206 write32(sgi, DistGroup, 0xffffffff);
207 for (
size_t irq = 0; irq < 32; irq += 4) {
208 write32(sgi, DistPriority + irq, 0xa0a0a0a0);
212 asm volatile(
"mrs %0, ICC_SRE_EL1" :
"=r"(sre));
214 asm volatile(
"msr ICC_SRE_EL1, %0\n\tisb" : :
"r"(sre) :
"memory");
216 asm volatile(
"mrs %0, ICC_CTLR_EL1" :
"=r"(cpuControl));
217 cpuControl &= ~(1U << 1);
218 asm volatile(
"msr ICC_CTLR_EL1, %0" : :
"r"(cpuControl) :
"memory");
219 asm volatile(
"msr ICC_PMR_EL1, %0" : :
"r"(uint64_t(0xff)) :
"memory");
220 asm volatile(
"msr ICC_BPR1_EL1, %0" : :
"r"(uint64_t(0)) :
"memory");
221 asm volatile(
"msr ICC_IGRPEN1_EL1, %0" : :
"r"(uint64_t(1)) :
"memory");
224 write32(dist, DistControl, (1U << 4) | (1U << 1) | 1U);
230bool VirtIrqManager::setEnabled(uint32_t irq,
bool enabled) {
231 if (!m_Initialised) {
234 if (irq >= MaxIrqs) {
235 return m_Its.setEnabled(irq, enabled);
237 uintptr_t base = VirtDeviceTree::gicDistributorBase();
238 if (m_Version == 3 && irq < 32) {
239 base = VirtDeviceTree::gicRedistributorBase() + RedistSgi;
241 write32(base, (enabled ? DistEnable : DistDisable) + (irq / 32) * 4, 1U << (irq % 32));
246void VirtIrqManager::setLevel(uint32_t irq) {
247 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
248 const uintptr_t offset = DistConfig + (irq / 16) * 4;
249 write32(dist, offset, read32(dist, offset) & ~(2U << ((irq % 16) * 2)));
253void VirtIrqManager::setEdge(uint32_t irq) {
254 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
255 const uintptr_t offset = DistConfig + (irq / 16) * 4;
256 write32(dist, offset, read32(dist, offset) | (2U << ((irq % 16) * 2)));
260bool VirtIrqManager::initialiseMsi() {
262 if (!VirtDeviceTree::pciMsiController(controller)) {
265 if (controller.type == VirtMsiController::Type::GicV3Its) {
266 if (!m_Its.initialise(controller, VirtDeviceTree::gicRedistributorBase(),
267 VirtDeviceTree::gicRedistributorPhysical())) {
270 m_MsiAddress = m_Its.messageAddress();
271 NOTICE(
"PCI: GICv3 ITS LPIs " <<
Dec << GicIts::FirstLpi <<
".."
272 << GicIts::FirstLpi + MaxPciLines - 1);
275 if (controller.type != VirtMsiController::Type::GicV2m || controller.size < 0x44 ||
276 controller.base > UINT64_MAX - 0x40) {
280 constexpr uintptr_t DirectMapBase = 0x80000000;
282 constexpr uintptr_t DirectMapBase = 0xffff000000000000ULL;
284 const uint32_t typer = read32(DirectMapBase + controller.base, 0x8);
285 const uint32_t first = controller.spiBase ? controller.spiBase : (typer >> 16) & 0x3ff;
286 const uint32_t count = controller.spiCount ? controller.spiCount : typer & 0x3ff;
287 if (first < 32 || first >= m_IrqCount || !count || count > m_IrqCount - first) {
291 m_MsiLast = first + count;
292 m_MsiAddress = controller.base + 0x40;
293 NOTICE(
"PCI: GICv2m MSI SPIs " <<
Dec << m_MsiFirst <<
".." << m_MsiLast - 1);
297void VirtIrqManager::enable(uint8_t irq,
bool enabled) {
298 setEnabled(irq, enabled);
305size_t VirtIrqManager::pciLine(uint32_t irq)
const {
306 for (
size_t i = 0; i < MaxPciLines; ++i) {
307 if (m_PciLines[i].irq == irq) {
314uint8_t VirtIrqManager::pciRegistryLine(
size_t slot)
const {
315 return static_cast<uint8_t
>(m_PciLines[slot].lpi ? slot : m_PciLines[slot].irq);
320 if (!m_Initialised || !device || !handler || policy.trigger() != IrqTrigger::Level ||
321 (hard ? !policy.validForHard() : !policy.validForThreaded()) ||
322 (!hard && !m_PciDispatcher.isInitialised())) {
326 PciBus& pci = PciBus::instance();
327 if (!pci.readConfig8(device, 0x3d, pin)) {
331 pci.interruptRoute(device->getPciBusPosition(), device->getPciDevicePosition(),
332 device->getPciFunctionNumber(), pin);
333 if (irq < 32 || irq >= MaxIrqs || irq != device->getInterruptNumber()) {
338 if (m_Hard[irq] || m_Scheduler[irq]) {
341 size_t slot = pciLine(irq);
342 if (slot == MaxPciLines) {
343 for (
size_t i = 0; i < MaxPciLines; ++i) {
344 if (!m_PciLines[i].irq) {
350 if (slot == MaxPciLines) {
353 PciLine& line = m_PciLines[slot];
354 if (line.removing || line.quarantined || line.reserved || line.message ||
355 (line.handlers && line.hard != hard)) {
358 const bool first = !line.handlers;
360 setEnabled(irq,
false);
363 const bool registered =
374 if (!line.inFlight) {
375 setEnabled(irq,
true);
382 return registerPciHandler(handler, device, policy,
false);
386 bool hard,
bool& allowFallback) {
387 allowFallback =
true;
388 if (!m_MsiReady || !handler || !device || (!hard && !m_PciDispatcher.isInitialised())) {
391 PciBus& pci = PciBus::instance();
393 if (!pci.inspectFunction(device, original,
false) || (!original.msi && !original.msix)) {
396 uint32_t deviceId = 0;
397 if (!VirtDeviceTree::pciMsiDeviceId(device->getPciBusPosition(), device->getPciDevicePosition(),
398 device->getPciFunctionNumber(), deviceId)) {
401 const bool lpi = m_Its.ready();
402 size_t slot = MaxPciLines;
406 for (
const PciLine& line : m_PciLines) {
407 if (line.message && line.deviceId == deviceId) {
408 allowFallback =
false;
412 for (
size_t i = 0; i < MaxPciLines; ++i) {
413 if (!m_PciLines[i].irq && !m_PciLines[i].reserved && !m_PciLines[i].quarantined) {
418 if (slot == MaxPciLines) {
422 irq = GicIts::FirstLpi + slot;
424 for (uint32_t candidate = m_MsiFirst; candidate < m_MsiLast; ++candidate) {
425 if (pciLine(candidate) == MaxPciLines && !m_Hard[candidate] && !m_Scheduler[candidate]) {
434 PciLine& line = m_PciLines[slot];
436 line.reserved =
true;
439 line.deviceId = deviceId;
440 line.device = device;
442 line.spuriousSafe = !hard &&
static_cast<IrqHandler*
>(handler)->acceptsSpuriousInterrupts();
444 setEnabled(irq,
false);
446 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
447 write32(dist, DistClearPending + (irq / 32) * 4, 1U << (irq % 32));
452 if (lpi && !m_Its.mapDevice(slot, deviceId, irq)) {
454 PciLine& line = m_PciLines[slot];
455 line.reserved =
false;
456 if (m_Its.mappingActive(slot)) {
457 line.quarantined =
true;
458 allowFallback =
false;
461 line.message =
false;
463 line.device =
nullptr;
468 bool registered =
false;
471 const uint8_t key = pciRegistryLine(slot);
473 key,
static_cast<HardIrqHandler*
>(handler), IrqPolicy::edgeHard())
475 key,
static_cast<IrqHandler*
>(handler), IrqPolicy::edgeThreaded());
477 PciLine& line = m_PciLines[slot];
482 const uint32_t data = lpi ? 0 : irq;
483 const bool msix = registered && original.msix && pci.enableMsix(device, m_MsiAddress, data);
484 const bool msi = registered && !msix && original.msi && pci.enableMsi(device, m_MsiAddress, data);
487 PciLine& line = m_PciLines[slot];
489 line.reserved =
false;
490 if (setEnabled(irq,
true)) {
493 line.quarantined =
true;
496 uint16_t command = 0;
497 const bool disabled =
499 (pci.disableMessageInterrupts(device, original) &&
500 pci.updateCommand(device, 0x400U, original.command & 0x400U) &&
501 pci.readConfig16(device, 4, command) && ((command ^ original.command) & 0x400U) == 0);
504 lpi ?
static_cast<uint8_t
>(slot) :
static_cast<uint8_t
>(irq), handler)
505 : IrqHandlerRegistry::UnregisterResult::Completed;
506 const bool unmapped = !lpi || (disabled && m_Its.unmapDevice(slot));
509 PciLine& line = m_PciLines[slot];
510 line.reserved =
false;
511 if (disabled && unmapped && removed == IrqHandlerRegistry::UnregisterResult::Completed) {
514 line.message =
false;
517 line.device =
nullptr;
519 line.quarantined =
true;
520 allowFallback =
false;
528 bool fallback =
true;
529 const irq_id_t
id = registerPciMessageHandler(handler, device,
false, fallback);
534 size_t count, irq_id_t* ids,
bool& fallbackSafe,
537 if (!m_MsiReady || !m_PciDispatcher.isInitialised() || !device || !handlers || !ids || !count ||
538 count > MaxPciLines) {
541 for (
size_t i = 0; i < count; ++i) {
548 PciBus& pci = PciBus::instance();
550 if (!pci.inspectFunction(device, original,
false) || !original.msix) {
553 uint32_t deviceId = 0;
554 if (!VirtDeviceTree::pciMsiDeviceId(device->getPciBusPosition(), device->getPciDevicePosition(),
555 device->getPciFunctionNumber(), deviceId)) {
559 const bool lpi = m_Its.ready();
560 size_t slots[MaxPciLines] = {};
561 uint32_t irqs[MaxPciLines] = {};
562 uint32_t data[MaxPciLines] = {};
566 for (
const PciLine& line : m_PciLines) {
567 if (line.message && line.deviceId == deviceId) {
568 fallbackSafe =
false;
572 for (; reserved < count; ++reserved) {
573 size_t slot = MaxPciLines;
574 for (
size_t i = 0; i < MaxPciLines; ++i) {
575 if (!m_PciLines[i].irq && !m_PciLines[i].reserved && !m_PciLines[i].quarantined) {
580 if (slot == MaxPciLines) {
583 uint32_t irq = lpi ? GicIts::FirstLpi + slot : 0;
585 for (uint32_t candidate = m_MsiFirst; candidate < m_MsiLast; ++candidate) {
586 if (pciLine(candidate) == MaxPciLines && !m_Hard[candidate] && !m_Scheduler[candidate]) {
595 slots[reserved] = slot;
596 irqs[reserved] = irq;
597 data[reserved] = lpi ?
static_cast<uint32_t
>(reserved) : irq;
598 PciLine& line = m_PciLines[slot];
600 line.reserved =
true;
603 line.msixIndex =
static_cast<uint8_t
>(reserved);
605 line.deviceId = deviceId;
606 line.device = device;
608 setEnabled(irq,
false);
610 const uintptr_t dist = VirtDeviceTree::gicDistributorBase();
611 write32(dist, DistClearPending + (irq / 32) * 4, 1U << (irq % 32));
615 if (reserved != count) {
616 for (
size_t i = 0; i < reserved; ++i) {
617 PciLine& line = m_PciLines[slots[i]];
618 const size_t cookie = line.cookie;
620 line.cookie = cookie;
626 if (lpi && !m_Its.mapDeviceGroup(slots, count, deviceId)) {
628 for (
size_t i = 0; i < count; ++i) {
629 active = m_Its.mappingActive(slots[i]) || active;
632 for (
size_t i = 0; i < count; ++i) {
633 PciLine& line = m_PciLines[slots[i]];
635 line.quarantined =
true;
637 const size_t cookie = line.cookie;
639 line.cookie = cookie;
642 fallbackSafe = !active;
646 size_t registered = 0;
649 for (; registered < count; ++registered) {
650 const uint8_t key = pciRegistryLine(slots[registered]);
652 IrqPolicy::edgeThreaded())) {
655 m_PciLines[slots[registered]].handlers = 1;
656 m_PciLines[slots[registered]].spuriousSafe =
661 bool enabled = registered == count;
664 for (
size_t i = 0; i < count; ++i) {
665 m_PciLines[slots[i]].reserved =
false;
666 if (!setEnabled(irqs[i],
true)) {
673 bool touched =
false;
674 if (enabled && pci.enableMsixVectors(device, m_MsiAddress, data, count, &touched)) {
675 for (
size_t i = 0; i < count; ++i) {
683 uint16_t command = 0;
684 safe = pci.disableMessageInterrupts(device, original);
686 for (
size_t i = 0; i < count; ++i) {
687 const bool masked = pci.setMsixVectorMask(device, i,
true);
688 safe = masked && safe;
691 safe = pci.updateCommand(device, 0x400U, original.command & 0x400U) && safe;
692 safe = pci.readConfig16(device, 4, command) && ((command ^ original.command) & 0x400U) == 0 &&
696 size_t cookies[MaxPciLines] = {};
699 for (
size_t i = 0; i < count; ++i) {
700 PciLine& line = m_PciLines[slots[i]];
701 line.removing =
true;
702 const bool masked = setEnabled(irqs[i],
false);
703 safe = masked && safe;
704 cookies[i] = line.cookie;
711 for (
size_t i = 0; i < registered; ++i) {
712 const uint8_t key = lpi ?
static_cast<uint8_t
>(slots[i]) :
static_cast<uint8_t
>(irqs[i]);
715 IrqHandlerRegistry::UnregisterResult::Completed) {
716 FATAL(
"ARM PCI MSI-X setup could not drain its handler");
720 for (
size_t i = 0; i < count; ++i) {
721 const bool unmapped = m_Its.unmapDevice(slots[i]);
722 safe = unmapped && safe;
727 for (
size_t i = 0; i < count; ++i) {
728 PciLine& line = m_PciLines[slots[i]];
730 const size_t cookie = line.cookie;
732 line.cookie = cookie;
734 line.quarantined =
true;
735 line.reserved =
true;
746 if (!m_Initialised || irq < 16 || !handler || !policy.validForHard()) {
751 if (m_Hard[irq] || m_Scheduler[irq]) {
755 m_Hard[irq] = handler;
756 setEnabled(irq,
true);
763 return registerPciHandler(handler, device, policy,
true);
768 bool fallback =
true;
769 const irq_id_t
id = registerPciMessageHandler(handler, device,
true, fallback);
775 if (!m_Initialised || irq < 16 || !handler || !policy.validForHard()) {
780 if (m_Hard[irq] || m_Scheduler[irq]) {
784 m_Scheduler[irq] = handler;
785 setEnabled(irq,
true);
791 if (!m_Initialised ||
id >= MaxIrqs || !handler) {
796 if (m_Scheduler[
id] != handler) {
800 setEnabled(
id,
false);
801 m_Scheduler[id] =
nullptr;
807 if (!m_Initialised || !handler ||
809 (!m_Its.ready() || id < GicIts::FirstLpi || id >= GicIts::FirstLpi + MaxPciLines))) {
812 size_t slot = MaxPciLines;
813 Device* messageDevice =
nullptr;
814 bool messageMsix =
false;
815 bool messageLpi =
false;
816 bool messageLast =
false;
817 uint8_t msixIndex = 0;
818 uint8_t registryKey = 0;
822 if (slot != MaxPciLines) {
825 ERROR(
"PCI: IRQ " <<
Dec <<
id <<
" retirement requires a waitable thread");
828 PciLine& line = m_PciLines[slot];
829 if (line.removing || !line.handlers) {
830 ERROR(
"PCI: IRQ " <<
Dec <<
id <<
" is not active for retirement");
834 for (
size_t i = 0; i < MaxPciLines; ++i) {
835 if (i != slot && m_PciLines[i].
message && m_PciLines[i].device == line.device &&
836 m_PciLines[i].removing) {
837 ERROR(
"PCI: IRQ " <<
Dec <<
id <<
" has another vector retiring");
842 line.removing =
true;
843 if (!setEnabled(
id,
false)) {
844 ERROR(
"PCI: could not mask GIC IRQ " <<
Dec <<
id);
845 line.removing =
false;
846 line.quarantined =
true;
849 registryKey = pciRegistryLine(slot);
851 messageDevice = line.device;
852 messageMsix = line.msix;
853 messageLpi = line.lpi;
854 msixIndex = line.msixIndex;
856 for (
size_t i = 0; i < MaxPciLines; ++i) {
857 if (i != slot && m_PciLines[i].
message && m_PciLines[i].device == messageDevice) {
865 if (slot != MaxPciLines) {
866 bool sourceDisabled =
true;
869 sourceDisabled = PciBus::instance().setMsixVectorMask(messageDevice, msixIndex,
true);
870 if (sourceDisabled && messageLast) {
871 sourceDisabled = PciBus::instance().disableMsix(messageDevice);
874 sourceDisabled = PciBus::instance().disableMsi(messageDevice);
877 if (!sourceDisabled) {
878 ERROR(
"PCI: could not disable message source for IRQ " <<
Dec <<
id);
880 PciLine& line = m_PciLines[slot];
881 line.removing =
false;
882 line.quarantined =
true;
885 if (messageLpi && !m_Its.unmapDevice(slot)) {
886 ERROR(
"PCI: could not unmap ITS LPI " <<
Dec <<
id);
888 PciLine& line = m_PciLines[slot];
889 line.removing =
false;
890 line.quarantined =
true;
894 size_t retiredCookie = 0;
897 PciLine& line = m_PciLines[slot];
898 if (removed != IrqHandlerRegistry::UnregisterResult::Completed) {
899 ERROR(
"PCI: could not retire IRQ handler " <<
Dec <<
id);
900 if (removed != IrqHandlerRegistry::UnregisterResult::NotFound) {
901 line.quarantined =
true;
903 line.removing =
false;
904 if (line.handlers && !line.message && !line.inFlight && !line.quarantined) {
905 setEnabled(
id,
true);
910 if (!line.handlers) {
911 retiredCookie = line.cookie;
916 line.inFlight =
false;
917 line.quarantined =
false;
920 line.message =
false;
923 line.device =
nullptr;
932 PciLine& line = m_PciLines[slot];
933 line.removing =
false;
934 if (line.handlers && !line.inFlight && !line.quarantined) {
935 setEnabled(
id,
true);
949 setEnabled(
id,
false);
950 m_Hard[id] =
nullptr;
955void VirtIrqManager::dispatchPciLine(
void* context, uint8_t slot,
size_t cookie) {
958 uint8_t registryKey = 0;
961 if (slot >= MaxPciLines || !manager.m_PciLines[slot].irq ||
962 manager.m_PciLines[slot].cookie != cookie || manager.m_PciLines[slot].hard) {
965 irq = manager.m_PciLines[slot].irq;
966 registryKey = manager.pciRegistryLine(slot);
970 const bool admitted =
971 manager.m_PciHandlers.dispatchThreaded(registryKey, cookie, result,
nullptr, irq);
974 PciLine& line = manager.m_PciLines[slot];
975 if (line.irq != irq || line.cookie != cookie) {
978 line.inFlight =
false;
979 if (!admitted || (!result.allowRearm && !(line.message && line.spuriousSafe))) {
980 line.quarantined =
true;
982 if (line.handlers && !line.removing && !line.quarantined) {
983 if (!manager.setEnabled(irq,
true)) {
984 line.quarantined =
true;
990uint32_t VirtIrqManager::acknowledge() {
992 if (m_Version == 3) {
994 asm volatile(
"mrs %0, ICC_IAR1_EL1" :
"=r"(value));
995 asm volatile(
"isb" : : :
"memory");
996 return static_cast<uint32_t
>(value);
999 return read32(VirtDeviceTree::gicCpuBase(), CpuAcknowledge);
1002void VirtIrqManager::complete(uint32_t value) {
1004 if (m_Version == 3) {
1005 asm volatile(
"msr ICC_EOIR1_EL1, %0\n\tisb" : :
"r"(uint64_t(value)) :
"memory");
1008 write32(VirtDeviceTree::gicCpuBase(), CpuEndOfInterrupt, value);
1014void VirtIrqManager::handle(InterruptState& state) {
1015 if (!m_Initialised) {
1018 const uint32_t acknowledgeValue = acknowledge();
1019 const uint32_t irq = acknowledgeValue & (m_Version == 3 ? 0xffffff : 0x3ff);
1020 if (irq >= 1020 && irq <= 1023) {
1023 if (irq >= MaxIrqs &&
1024 (!m_Its.ready() || irq < GicIts::FirstLpi || irq >= GicIts::FirstLpi + MaxPciLines)) {
1025 complete(acknowledgeValue);
1031 if (irq == VirtDeviceTree::virtualTimerIrq()) {
1033 uint32_t disabled = 0;
1034 asm volatile(
"mcr p15, 0, %0, c14, c3, 1\n\tisb" : :
"r"(disabled) :
"memory");
1036 asm volatile(
"msr cntv_ctl_el0, %0\n\tisb" : :
"r"(uint64_t(0)) :
"memory");
1040 complete(acknowledgeValue);
1041 scheduler->schedulerIrq(irq, state);
1045 size_t pciSlot = MaxPciLines;
1046 size_t pciCookie = 0;
1047 bool pciHard =
false;
1048 bool pciMessage =
false;
1049 uint8_t registryKey = 0;
1052 pciSlot = pciLine(irq);
1053 if (pciSlot != MaxPciLines) {
1054 PciLine& line = m_PciLines[pciSlot];
1055 if (!setEnabled(irq,
false)) {
1056 line.quarantined =
true;
1057 complete(acknowledgeValue);
1060 if (!line.handlers || line.reserved || line.inFlight || line.removing || line.quarantined) {
1061 complete(acknowledgeValue);
1064 line.inFlight =
true;
1069 pciCookie = line.cookie;
1070 pciHard = line.hard;
1071 pciMessage = line.message;
1072 registryKey = pciRegistryLine(pciSlot);
1074 complete(acknowledgeValue);
1077 const bool published =
1082 line.inFlight =
false;
1083 line.quarantined =
true;
1086 complete(acknowledgeValue);
1093 if (pciSlot != MaxPciLines && pciHard) {
1095 const bool admitted =
1096 m_PciHandlers.
dispatchHard(registryKey, state, disposition,
nullptr, 0, irq);
1098 PciLine& line = m_PciLines[pciSlot];
1100 complete(acknowledgeValue);
1102 if (line.cookie == pciCookie) {
1103 line.inFlight =
false;
1104 if (!admitted || disposition != HardIrqDisposition::Handled) {
1105 line.quarantined =
true;
1107 if (line.handlers && !line.removing && !line.quarantined) {
1108 if (!setEnabled(irq,
true)) {
1109 line.quarantined =
true;
1116 if (irq >= MaxIrqs) {
1117 complete(acknowledgeValue);
1123 size_t previousDepth = 0;
1124 bool restoreDepth =
false;
1127 setEnabled(irq,
false);
1130 setEnabled(irq,
false);
1132 complete(acknowledgeValue);
1135extern "C" void virtHandleIrq(InterruptState& state) {
1136 VirtIrqManager::instance().handle(state);
virtual HardIrqDisposition irq(irq_id_t number, InterruptState &state)=0
void invalidateThreadedGenerationFromInterrupt(uint8_t irq, size_t throughGeneration)
bool publishThreadedDispatch(uint8_t irq, size_t dispatchGeneration)
bool registerThreadedHandler(uint8_t irq, IrqHandler *handler)
UnregisterResult unregisterHandler(uint8_t irq, IrqHandlerBase *handler)
bool dispatchHard(uint8_t irq, InterruptState &state, HardIrqDisposition &disposition, HardIrqHandler *onlyHandler=nullptr, size_t dispatchGeneration=0, irq_id_t callbackId=0)
void invalidateThreadedLine(uint8_t irq, size_t throughGeneration)
bool registerHardHandler(uint8_t irq, HardIrqHandler *handler)
virtual bool acceptsSpuriousInterrupts() const
static bool getInterrupts()
static ExecutionContext executionContext()
static void setInterrupts(bool bEnable)
bool isCurrentWorker() const
bool initialise(bool lazy=false)
bool publishFromInterrupt(uint8_t line, size_t cookie)
irq_id_t registerHardPciIrqHandler(HardIrqHandler *handler, Device *device, const IrqPolicy &policy) override
irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, const IrqPolicy &policy) override
irq_id_t registerPciMessageIrqHandler(IrqHandler *handler, Device *device, const IrqPolicy &intxFallbackPolicy) override
bool unregisterHandler(irq_id_t id, IrqHandlerBase *handler) override
bool registerPciMsixIrqHandlers(Device *device, IrqHandler *const *handlers, size_t count, irq_id_t *ids, bool &fallbackSafe, const size_t *processors=nullptr) override
bool unregisterSchedulerIrqHandler(irq_id_t id, SchedulerIrqHandler *handler) override
irq_id_t registerHardPciMessageIrqHandler(HardIrqHandler *handler, Device *device, const IrqPolicy &intxFallbackPolicy) override
irq_id_t registerHardIsaIrqHandler(uint8_t irq, HardIrqHandler *handler, const IrqPolicy &policy) override
irq_id_t registerSchedulerIrqHandler(uint8_t irq, SchedulerIrqHandler *handler, const IrqPolicy &policy) override
irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *device, const IrqPolicy &policy) override