3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/machine/Device.h"
5#include "pedigree/kernel/machine/Pci.h"
6#include "pedigree/kernel/panic.h"
7#include "pedigree/kernel/processor/MemoryRegion.h"
8#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
9#include "pedigree/kernel/processor/VirtualAddressSpace.h"
16 bool read8(uint16_t offset, uint8_t& value) {
17 return PciBus::instance().readConfig8(device, offset, value);
19 bool write8(uint16_t offset, uint8_t value) {
20 return PciBus::instance().writeConfig8(device, offset, value);
23uint16_t hpetExclusions(uint32_t hptc) {
26 if (hptc == 0xffffffff || !(hptc & 0x80))
34 0xfed00000U + ((hptc & 3) << 12)))
36 auto* registers =
static_cast<volatile uint32_t*
>(hpet.virtualAddress());
37 const uint32_t capabilities = registers[0];
38 const uint32_t general = registers[0x10 / 4];
39 const uint32_t pending = registers[0x20 / 4];
40 const unsigned lastTimer = (capabilities >> 8) & 31;
41 if ((capabilities >> 16) != 0x8086 || lastTimer < 2 || general == 0xffffffff ||
42 pending == 0xffffffff)
44 uint16_t excluded = 0;
45 for (
unsigned timer = 0; timer <= lastTimer; ++timer)
46 excluded |= IntelPirq::hpetExclusion(registers[(0x100 + 0x20 * timer) / 4], pending, timer,
53 auto& pci = PciBus::instance();
55 for (
size_t i = 0; i < devices.
size(); ++i) {
56 auto* device = devices[i];
57 const auto header = device->getPciConfigHeader();
58 if (device->getPciBusPosition() == 0 && device->getPciDevicePosition() == 31 &&
59 device->getPciFunctionNumber() == 0 && header.vendor == 0x8086 && header.device == 0x1c4f &&
60 header.class_code == 6 && header.subclass == 1)
67 uint8_t acpiControl = 0;
68 if (!pci.readConfig32(lpc, 0xf0, rcba) || rcba == 0xffffffff || !(rcba & 1) ||
69 !(rcba & 0xffffc000U) || !pci.readConfig8(lpc, 0x44, acpiControl) || acpiControl == 0xff ||
70 (acpiControl & 7) == 3) {
71 ERROR(
"PCI: QM67 routing unavailable: invalid RCBA or SCI selection");
74 const uint8_t sci = (acpiControl & 7) < 3 ? 9 + (acpiControl & 7) : 16 + (acpiControl & 7);
75 uint16_t excluded = 0;
79 if (pageSize != 4096 ||
85 (rcba & 0xffffc000U) + 0x3000)) {
86 ERROR(
"PCI: cannot map QM67 interrupt routing registers");
89 auto* mapped =
static_cast<volatile uint8_t*
>(registers.virtualAddress());
91 auto read32 = [mapped](uint16_t offset) {
92 return *
reinterpret_cast<volatile uint32_t*
>(mapped + ((offset & ~3U) - 0x3000));
94 auto read16 = [&read32](uint16_t offset) {
95 return static_cast<uint16_t
>(read32(offset) >> (8 * (offset & 2)));
97 const uint8_t tcoControl = read32(0x3000);
98 if (!IntelPirq::chipsetExclusions(acpiControl, tcoControl, excluded)) {
99 ERROR(
"PCI: QM67 SCI/TCO routing state invalid");
102 excluded |= hpetExclusions(read32(0x3404));
105 excluded |= uint16_t{1} << 12;
106 NOTICE(
"PCI: QM67 native INTx routing: RCBA=" <<
Hex << rcba <<
" OIC=" << read16(0x31fe)
107 <<
" SCI=" <<
Dec << sci <<
" excluded=" <<
Hex
110 static const char* reasons[] = {
"ready",
112 "invalid or reserved IRQ",
113 "no compatible PIC line",
114 "write failed; original restored",
115 "route restoration failed"};
116 LpcConfig config{lpc};
117 uint8_t routes[8] = {};
118 bool attempted[8] = {};
120 bool downstream =
false;
121 for (
size_t i = 0; i < devices.
size(); ++i) {
122 auto* device = devices[i];
123 auto header = device->getPciConfigHeader();
124 if (!header.interrupt_pin)
126 if (device->getPciBusPosition() != 0) {
127 downstream |= header.interrupt_line == 0xff;
130 const uint8_t slot = device->getPciDevicePosition();
131 const uint8_t function = device->getPciFunctionNumber();
132 const uint16_t offset = IntelPirq::routeOffset(slot);
133 if (header.vendor != 0x8086 || !offset || function > 7)
137 device->setInterruptNumber(0xff);
138 auto unpublished = header;
139 unpublished.interrupt_line = 0xff;
140 device->setPciConfigHeader(unpublished);
141 const uint32_t pins = read32(IntelPirq::pinOffset(slot));
142 if (!IntelPirq::nativePinMatches(pins, function, header.interrupt_pin) ||
143 !IntelPirq::decode(read16(offset), header.interrupt_pin, pirq)) {
144 ERROR(
"PCI: QM67 pin/route mismatch for 0:" <<
Dec << slot <<
":" << function);
147 if (!attempted[pirq]) {
148 attempted[pirq] =
true;
149 uint8_t before = 0xff;
150 config.read8(IntelPirq::configOffset(pirq), before);
151 const auto result = IntelPirq::establish(
152 config, [&pci](uint8_t irq) {
return pci.reserveLegacyInterrupt(irq); }, pirq, excluded,
154 if (result == IntelPirq::Result::RestoreFailed)
155 panic(
"PCI: cannot restore QM67 PIRQ route after failed write");
156 ready[pirq] = result == IntelPirq::Result::Ready;
158 NOTICE(
"PCI: QM67 PIRQ" <<
char(
'A' + pirq) <<
"=" <<
Hex << before <<
" -> PIC IRQ " <<
Dec
161 ERROR(
"PCI: QM67 PIRQ" <<
char(
'A' + pirq) <<
"=" <<
Hex << before
162 <<
" unavailable: " << reasons[
static_cast<unsigned>(result)]);
166 uint8_t actual = 0, currentPin = 0;
167 if (!pci.readConfig8(device, 0x3d, currentPin) || currentPin != header.interrupt_pin ||
168 !pci.writeConfig8(device, 0x3c, routes[pirq]) || !pci.readConfig8(device, 0x3c, actual) ||
169 actual != routes[pirq]) {
170 ERROR(
"PCI: cannot publish QM67 IRQ for 0:" <<
Dec << slot <<
":" << function);
173 NOTICE(
"PCI: 0:" <<
Dec << slot <<
":" << function <<
" " <<
Hex << header.vendor <<
":"
174 << header.device <<
" INT" <<
char(
'A' + header.interrupt_pin - 1)
175 <<
" -> PIRQ" <<
char(
'A' + pirq) <<
" -> IRQ " <<
Dec << actual);
176 header.interrupt_line = actual;
177 device->setPciConfigHeader(header);
178 device->setInterruptNumber(actual);
181 NOTICE(
"PCI: unassigned downstream INTx routes require ACPI bridge routing");
Special memory entity in the kernel's virtual address space.
static const size_t continuous
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
static const size_t force
static const size_t nonRamMemory
A vector / dynamic array.
static const size_t CacheDisable
static const size_t KernelMode
void EXPORTED_PUBLIC panic(const char *msg) NORETURN