The Pedigree Project 0.1
enumeration.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
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"
29
30#include "Bar.h"
31#include "ProbeBars.h"
32#include "Resources.h"
33#include "modules/Module.h"
34#include "pci_list.h"
35
36static void readConfigSpace(Device* pDev, PciBus::ConfigSpace* pCs) {
37 uint8_t* bytes = reinterpret_cast<uint8_t*>(pCs);
38 for (unsigned int i = 0; i < sizeof(PciBus::ConfigSpace) / 4; i++) {
39 const uint32_t value = PciBus::instance().readConfigSpace(pDev, i);
40 for (unsigned int byte = 0; byte < 4; ++byte) {
41 bytes[i * 4 + byte] = value >> (byte * 8);
42 }
43 }
44}
45
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;
50 }
51 return "";
52}
53
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;
58 }
59 return "";
60}
61
62static bool entry() {
63 uint8_t firstBus = 0;
64 uint8_t lastBus = 0;
65 if (!PciBus::instance().busRange(firstBus, lastBus)) {
66 return true;
67 }
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) {
73 // Firstly add the ISA bus.
74 char* str = new char[256];
75 StringFormat(str, "PCI #%d", iBus);
76 Bus* pBus = new Bus(str);
77 pBus->setSpecificType(String("pci"));
78
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)
83 break;
84 if (inheritedVfs[iBus][iDevice] & (1U << iFunc)) {
85 // A withheld function zero must not hide unrelated functions in the slot.
86 bIsMultifunc = true;
87 NOTICE("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc
88 << " inherited VF withheld until DMA isolation is available");
89 continue;
90 }
91
92 Device* pDevice = new Device();
93 pDevice->setPciPosition(iBus, iDevice, iFunc);
94
95 uint32_t vendorAndDeviceId = PciBus::instance().readConfigSpace(pDevice, 0);
96 if ((vendorAndDeviceId & 0xFFFF) == 0xFFFF || (vendorAndDeviceId & 0xFFFF) == 0) {
97 delete pDevice;
101 continue;
102 // break;
103 }
104
105 PciBus::ConfigSpace cs = {};
106 readConfigSpace(pDevice, &cs);
107
108 if (cs.header_type & 0x80)
109 bIsMultifunc = true;
110
111 auto& pci = PciBus::instance();
113 if (pci.findExtendedCapability(pDevice, PciSriov::CapabilityId, sriov) ==
114 PciExtendedCapabilities::FindResult::Found) {
115 struct SriovConfig {
116 PciBus& pci;
117 Device* device;
118 bool read16(uint16_t offset, uint16_t& value) {
119 return pci.readConfig16(device, offset, value);
120 }
121 bool read32(uint16_t offset, uint32_t& value) {
122 return pci.readConfig32(device, offset, value);
123 }
124 } config{pci, pDevice};
125 PciSriov::State state;
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,
135 vfFunction) ||
136 vfBus < firstBus || vfBus > lastBus) {
137 WARNING("PCI: invalid inherited VF routing ID");
138 break;
139 }
140 inheritedVfs[vfBus][vfDevice] |= 1U << vfFunction;
141 }
142 }
143 } else {
144 WARNING("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc
145 << " has invalid SR-IOV state");
146 }
147 }
148
149 NOTICE("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc << "\t Vendor:" << Hex
150 << cs.vendor << " Device:" << cs.device);
151
152 char c[256];
153 StringFormat(c, "%s - %s", getDevice(cs.vendor, cs.device), getVendor(cs.vendor));
154 pDevice->setSpecificType(String(c));
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);
159
160 PciBar::Probe bars = PciBar::probe(pci, pDevice, cs);
161 if (bars.result == PciBar::ProbeResult::DecodeDisableFailed) {
162 ERROR("PCI: cannot disable decoding for BAR sizing");
163 delete pDevice;
164 continue;
165 }
166 if (bars.result == PciBar::ProbeResult::RestoreFailed) {
167 ERROR("PCI: BAR/command restoration failed; function left disabled");
168 delete pDevice;
169 continue;
170 }
171#if ARM64 || ARMV7
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) {
177 break;
178 }
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)) {
184 if (base) {
185 ERROR("PCI: BAR" << Dec << l << " outside bridge or host window");
186 rejectedBar = true;
187 break;
188 }
189 continue;
190 }
191 if (!base) {
192 assignedBar = true;
193 }
194 if (wide) {
195 ++l;
196 }
197 }
198 if (rejectedBar) {
199 delete pDevice;
200 continue;
201 }
202 if (assignedBar) {
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");
207 delete pDevice;
208 continue;
209 }
210 }
211#endif
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)
216 break;
217 const uint32_t high = wide ? cs.bar[l + 1] : 0;
218 const uint32_t maskHigh = wide ? bars.masks[l + 1] : 0;
219 PciBar::Mapping mapping;
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}) {
225 continue;
226 }
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 << ")");
231 } else {
232 NOTICE("PCI: BAR" << Dec << l << Hex << ": " << mapping.base << " -> "
233 << cpuPhysical << " (" << mapping.io << ")");
234 }
235 pDevice->addresses().pushBack(
236 new Device::Address(String(c), static_cast<uintptr_t>(cpuPhysical),
237 static_cast<size_t>(mapping.bytes), mapping.io));
238 }
239 if (wide)
240 ++l;
241 }
242
243 const uint32_t routedIrq = pci.interruptRoute(iBus, iDevice, iFunc, cs.interrupt_pin);
244 if (routedIrq) {
245 NOTICE("PCI: IRQ: L" << cs.interrupt_line << " P" << cs.interrupt_pin << " route "
246 << routedIrq);
247 } else {
248 NOTICE("PCI: IRQ: L" << cs.interrupt_line << " P" << cs.interrupt_pin);
249 }
250 pDevice->setInterruptNumber(routedIrq ? routedIrq : cs.interrupt_line);
251 pBus->addChild(pDevice);
252 pDevice->setParent(pBus);
253
254 pDevice->setPciConfigHeader(cs);
255
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;
266 } else {
267 upstream[secondary] = pDevice;
268 }
269 }
270 }
271 }
272
274 const auto aerResult = pci.findExtendedCapability(pDevice, PciAer::CapabilityId, aer);
275 if (aerResult == PciExtendedCapabilities::FindResult::Found) {
276 struct AerConfig {
277 PciBus& pci;
278 Device* device;
279 bool read32(uint16_t offset, uint32_t& value) {
280 return pci.readConfig32(device, offset, value);
281 }
282 } config{pci, pDevice};
283 PciAer::Status status;
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());
293 }
294 } else if (aerResult == PciExtendedCapabilities::FindResult::Malformed) {
295 WARNING("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc
296 << " has malformed extended capabilities");
297 }
298 }
299 }
300
301 buses[iBus] = pBus;
302 }
303
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");
308 }
309 if (upstream[iBus] && !ambiguous[iBus]) {
310 upstream[iBus]->addChild(bus);
311 bus->setParent(upstream[iBus]);
312 NOTICE("PCI: bus " << Dec << iBus << " behind " << upstream[iBus]->getPciBusPosition() << ":"
313 << upstream[iBus]->getPciDevicePosition() << ":"
314 << upstream[iBus]->getPciFunctionNumber());
315 } else if (bus->getNumChildren()) {
317 } else {
318 delete bus;
319 }
320 }
321
322 if (!PciResources::initialize()) {
323 WARNING("PCI: resource allocation unavailable");
324 }
325 return true;
326}
327
328static void exit() {}
329
330// The enumerated nodes outlive module initialization and have no removal path.
331MODULE_INFO_NON_UNLOADABLE("pci-enumeration", &entry, &exit, "acpi");
Definition Bus.h:31
size_t getNumChildren()
Definition Device.cc:143
static void addToRoot(Device *device)
Definition Device.cc:114
void setPciConfigHeader(const PciBus::ConfigSpace &space)
Definition Device.h:208
virtual Vector< Address * > & addresses()
Definition Device.h:266
void setPciIdentifiers(uint8_t classCode, uint8_t subclassCode, uint16_t vendorId, uint16_t deviceId, uint8_t progIf)
Definition Device.h:199
virtual void setInterruptNumber(uintptr_t n)
Definition Device.h:276
void addChild(Device *pDevice)
Definition Device.cc:135
virtual void setSpecificType(String str)
Definition Device.h:187
void setParent(Device *p)
Definition Device.h:170
void setPciPosition(uint32_t bus, uint32_t device, uint32_t func)
Definition Device.h:192
Definition Pci.h:31
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)
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124