20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/machine/Bus.h"
22#include "pedigree/kernel/machine/Device.h"
23#include "pedigree/kernel/machine/Pci.h"
24#include "pedigree/kernel/machine/PciAer.h"
25#include "pedigree/kernel/machine/PciSriov.h"
26#include "pedigree/kernel/processor/types.h"
27#include "pedigree/kernel/utilities/String.h"
28#include "pedigree/kernel/utilities/utility.h"
33#include "modules/Module.h"
37 uint8_t* bytes =
reinterpret_cast<uint8_t*
>(pCs);
40 for (
unsigned int byte = 0;
byte < 4; ++byte) {
41 bytes[i * 4 + byte] = value >> (
byte * 8);
46static const char* getVendor(uint16_t vendor) {
47 for (
unsigned int i = 0; i < PCI_VENTABLE_LEN; i++) {
48 if (PciVenTable[i].VenId == vendor)
49 return PciVenTable[i].VenShort;
54static const char* getDevice(uint16_t vendor, uint16_t device) {
55 for (
unsigned int i = 0; i < PCI_DEVTABLE_LEN; i++) {
56 if (PciDevTable[i].VenId == vendor && PciDevTable[i].DevId == device)
57 return PciDevTable[i].ChipDesc;
65 if (!PciBus::instance().busRange(firstBus, lastBus)) {
68 static Bus* buses[256] = {};
69 static Device* upstream[256] = {};
70 static bool ambiguous[256] = {};
71 static uint8_t inheritedVfs[256][32] = {};
72 for (
int iBus = firstBus; iBus <= lastBus; ++iBus) {
74 char* str =
new char[256];
75 StringFormat(str,
"PCI #%d", iBus);
79 for (
int iDevice = 0; iDevice < 32; iDevice++) {
80 bool bIsMultifunc =
false;
81 for (
int iFunc = 0; iFunc < 8; iFunc++) {
82 if (iFunc > 0 && !bIsMultifunc)
84 if (inheritedVfs[iBus][iDevice] & (1U << iFunc)) {
87 NOTICE(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc
88 <<
" inherited VF withheld until DMA isolation is available");
95 uint32_t vendorAndDeviceId = PciBus::instance().
readConfigSpace(pDevice, 0);
96 if ((vendorAndDeviceId & 0xFFFF) == 0xFFFF || (vendorAndDeviceId & 0xFFFF) == 0) {
106 readConfigSpace(pDevice, &cs);
108 if (cs.header_type & 0x80)
111 auto& pci = PciBus::instance();
113 if (pci.findExtendedCapability(pDevice, PciSriov::CapabilityId, sriov) ==
114 PciExtendedCapabilities::FindResult::Found) {
118 bool read16(uint16_t offset, uint16_t& value) {
119 return pci.readConfig16(device, offset, value);
121 bool read32(uint16_t offset, uint32_t& value) {
122 return pci.readConfig32(device, offset, value);
124 } config{pci, pDevice};
126 if (PciSriov::read(config, sriov.offset, sriov.next, state)) {
127 NOTICE(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc
128 <<
" SR-IOV VFs=" << state.numVfs <<
"/" << state.totalVfs
129 <<
" VF device=" <<
Hex << state.vfDeviceId);
130 if (state.enabled()) {
131 WARNING(
"PCI: inherited SR-IOV VFs have no DMA isolation; withholding drivers");
132 for (uint16_t vf = 0; vf < state.numVfs; ++vf) {
133 uint8_t vfBus = 0, vfDevice = 0, vfFunction = 0;
134 if (!PciSriov::vfRoutingId(iBus, iDevice, iFunc, state, vf, vfBus, vfDevice,
136 vfBus < firstBus || vfBus > lastBus) {
137 WARNING(
"PCI: invalid inherited VF routing ID");
140 inheritedVfs[vfBus][vfDevice] |= 1U << vfFunction;
144 WARNING(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc
145 <<
" has invalid SR-IOV state");
149 NOTICE(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc <<
"\t Vendor:" <<
Hex
150 << cs.vendor <<
" Device:" << cs.device);
153 StringFormat(c,
"%s - %s", getDevice(cs.vendor, cs.device), getVendor(cs.vendor));
155 NOTICE(
"PCI: " << c);
156 pDevice->
setPciIdentifiers(cs.class_code, cs.subclass, cs.vendor, cs.device, cs.progif);
157 NOTICE(
"PCI: Class: " << cs.class_code <<
" Subclass: " << cs.subclass
158 <<
" ProgIF: " << cs.progif);
161 if (bars.result == PciBar::ProbeResult::DecodeDisableFailed) {
162 ERROR(
"PCI: cannot disable decoding for BAR sizing");
166 if (bars.result == PciBar::ProbeResult::RestoreFailed) {
167 ERROR(
"PCI: BAR/command restoration failed; function left disabled");
172 bool assignedBar =
false;
173 bool rejectedBar =
false;
174 for (
size_t l = 0; l < bars.count; ++l) {
175 const bool wide = !(cs.bar[l] & 1U) && (cs.bar[l] & 6U) == 4;
176 if (wide && l + 1 == bars.count) {
179 const uint32_t high = wide ? cs.bar[l + 1] : 0;
180 const uint64_t base =
181 (uint64_t(high) << 32) | (cs.bar[l] & (cs.bar[l] & 1U ? ~3U : ~15U));
182 if (!pci.
assignBar(pDevice, l, cs.bar[l], high, bars.masks[l],
183 wide ? bars.masks[l + 1] : 0)) {
185 ERROR(
"PCI: BAR" <<
Dec << l <<
" outside bridge or host window");
203 readConfigSpace(pDevice, &cs);
204 bars = PciBar::probe(pci, pDevice, cs);
205 if (bars.result != PciBar::ProbeResult::Success) {
206 ERROR(
"PCI: assigned BAR verification failed");
212 const size_t barCount = bars.count;
213 for (
size_t l = 0; l < barCount; ++l) {
214 const bool wide = !(cs.bar[l] & 1U) && (cs.bar[l] & 6U) == 4;
215 if (wide && l + 1 == barCount)
217 const uint32_t high = wide ? cs.bar[l + 1] : 0;
218 const uint32_t maskHigh = wide ? bars.masks[l + 1] : 0;
220 if (PciBar::decode(cs.bar[l], high, bars.masks[l], maskHigh, mapping) &&
221 mapping.base <= ~uintptr_t{0} && mapping.bytes <= ~size_t{0}) {
222 uint64_t cpuPhysical = 0;
223 if (!pci.
translateAddress(mapping.base, mapping.bytes, mapping.io, cpuPhysical) ||
224 cpuPhysical > ~uintptr_t{0}) {
227 StringFormat(c,
"bar%u",
static_cast<unsigned>(l));
228 if (cpuPhysical == mapping.base) {
229 NOTICE(
"PCI: BAR" <<
Dec << l <<
Hex <<
": " << mapping.base <<
".."
230 << (mapping.base + mapping.bytes) <<
" (" << mapping.io <<
")");
232 NOTICE(
"PCI: BAR" <<
Dec << l <<
Hex <<
": " << mapping.base <<
" -> "
233 << cpuPhysical <<
" (" << mapping.io <<
")");
237 static_cast<size_t>(mapping.bytes), mapping.io));
243 const uint32_t routedIrq = pci.interruptRoute(iBus, iDevice, iFunc, cs.interrupt_pin);
245 NOTICE(
"PCI: IRQ: L" << cs.interrupt_line <<
" P" << cs.interrupt_pin <<
" route "
248 NOTICE(
"PCI: IRQ: L" << cs.interrupt_line <<
" P" << cs.interrupt_pin);
256 if (cs.class_code == 6 && cs.subclass == 4 && (cs.header_type & 0x7f) == 1) {
257 uint32_t numbers = 0;
258 if (pci.readConfig32(pDevice, 0x18, numbers)) {
259 const uint8_t primary = numbers;
260 const uint8_t secondary = numbers >> 8;
261 const uint8_t subordinate = numbers >> 16;
262 if (primary == iBus && secondary > iBus && secondary <= lastBus &&
263 subordinate >= secondary && subordinate <= lastBus) {
264 if (upstream[secondary]) {
265 ambiguous[secondary] =
true;
267 upstream[secondary] = pDevice;
274 const auto aerResult = pci.findExtendedCapability(pDevice, PciAer::CapabilityId, aer);
275 if (aerResult == PciExtendedCapabilities::FindResult::Found) {
279 bool read32(uint16_t offset, uint32_t& value) {
280 return pci.readConfig32(device, offset, value);
282 } config{pci, pDevice};
284 if (!PciAer::read(config, aer.offset, aer.next, status)) {
285 WARNING(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc
286 <<
" could not read AER status");
287 }
else if (status.uncorrectable || status.correctable) {
288 WARNING(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc <<
Hex
289 <<
" AER uncorrectable=" << status.uncorrectable
290 <<
" fatal=" << status.fatal() <<
" nonfatal=" << status.nonfatal()
291 <<
" masked=" << status.maskedUncorrectable() <<
" correctable="
292 << status.correctable <<
" active=" << status.activeCorrectable());
294 }
else if (aerResult == PciExtendedCapabilities::FindResult::Malformed) {
295 WARNING(
"PCI: " <<
Dec << iBus <<
":" << iDevice <<
":" << iFunc
296 <<
" has malformed extended capabilities");
304 for (
int iBus = firstBus; iBus <= lastBus; ++iBus) {
305 Bus* bus = buses[iBus];
306 if (ambiguous[iBus]) {
307 WARNING(
"PCI: bus " <<
Dec << iBus <<
" has multiple upstream bridges");
309 if (upstream[iBus] && !ambiguous[iBus]) {
312 NOTICE(
"PCI: bus " <<
Dec << iBus <<
" behind " << upstream[iBus]->getPciBusPosition() <<
":"
313 << upstream[iBus]->getPciDevicePosition() <<
":"
314 << upstream[iBus]->getPciFunctionNumber());
322 if (!PciResources::initialize()) {
323 WARNING(
"PCI: resource allocation unavailable");
331MODULE_INFO_NON_UNLOADABLE(
"pci-enumeration", &entry, &exit,
"acpi");
static void addToRoot(Device *device)
void setPciConfigHeader(const PciBus::ConfigSpace &space)
virtual Vector< Address * > & addresses()
void setPciIdentifiers(uint8_t classCode, uint8_t subclassCode, uint16_t vendorId, uint16_t deviceId, uint8_t progIf)
virtual void setInterruptNumber(uintptr_t n)
void addChild(Device *pDevice)
virtual void setSpecificType(String str)
void setParent(Device *p)
void setPciPosition(uint32_t bus, uint32_t device, uint32_t func)
uint32_t readConfigSpace(Device *pDev, uint8_t offset)
bool translateAddress(uint64_t pciAddress, uint64_t bytes, bool io, uint64_t &cpuPhysical)
bool assignBar(Device *device, uint8_t index, uint32_t low, uint32_t high, uint32_t maskLow, uint32_t maskHigh)