2#include "pedigree/kernel/Log.h"
3#include "pedigree/kernel/machine/Device.h"
4#include "pedigree/kernel/machine/PciDrivers.h"
5#include "pedigree/kernel/machine/PciSriov.h"
6#include "pedigree/kernel/panic.h"
7#include "pedigree/kernel/utilities/new"
9#include "Enumeration.h"
15 auto* bytes =
reinterpret_cast<uint8_t*
>(&header);
16 for (uint16_t offset = 0; offset <
sizeof(header); offset += 4) {
18 if (!PciBus::instance().readConfig32(device, offset, value)) {
21 for (
unsigned byte = 0;
byte < 4; ++byte) {
22 bytes[offset + byte] = value >> (
byte * 8);
28bool writeBar(
Device* device,
size_t index, uint32_t value) {
30 auto& pci = PciBus::instance();
31 return pci.writeConfig32(device, 0x10 + 4 * index, value) &&
32 pci.readConfig32(device, 0x10 + 4 * index, actual) && actual == value;
38 !PciBus::instance().readConfig32(port, 0x18, buses) ||
39 uint8_t(buses) != port->
getPciBusPosition() || uint8_t(buses >> 8) <= uint8_t(buses) ||
40 uint8_t(buses >> 16) < uint8_t(buses >> 8)) {
58bool noVirtualFunctions(
Device* device) {
60 auto& pci = PciBus::instance();
61 const auto found = pci.findExtendedCapability(device, PciSriov::CapabilityId, capability);
62 if (found == PciExtendedCapabilities::FindResult::Absent) {
66 return found == PciExtendedCapabilities::FindResult::Found &&
67 pci.readConfig16(device, capability.offset + 8, control) &&
68 !(control & PciSriov::VfControl);
77 const auto header = device->getPciConfigHeader();
78 return !header.header_type && !device->getPciDevicePosition() &&
79 !device->getPciFunctionNumber() && !device->getPhysicalFunction()
85namespace PciEnumeration {
86bool probeSlot(
Device* port) {
88 Device* bus = slotBus(port, number);
93 return leaf(bus) !=
nullptr;
95 auto& pci = PciBus::instance();
97 device->setPciPosition(number, 0, 0);
98 device->setParent(bus);
100 if (!readHeader(device, original) || !original.vendor || original.vendor == 0xffff ||
101 original.header_type || (original.command & 7U) || (original.rom_base_address & 1U) ||
102 !noVirtualFunctions(device)) {
106 device->setPciIdentifiers(original.class_code, original.subclass, original.vendor,
107 original.device, original.progif);
109 bool registered =
false;
110 auto rollback = [&]() {
111 if (!pci.updateCommand(device, 7U, 0)) {
112 panic(
"PCI hotplug: cannot stop decoding during probe rollback");
114 for (
size_t i = 0; i < 6; ++i) {
115 if (!writeBar(device, i, original.bar[i])) {
116 panic(
"PCI hotplug: cannot restore BARs during probe rollback");
119 if (registered && !PciResources::removeFunction(device)) {
120 panic(
"PCI hotplug: cannot reclaim failed probe resources");
127 for (
size_t i = 0; i < 6; ++i) {
128 const uint32_t low = original.bar[i];
129 assigned.bar[i] = low & ((low & 1U) ? 3U : 15U);
130 if (!writeBar(device, i, assigned.bar[i])) {
133 if (!(low & 1U) && (low & 6U) == 4) {
138 if (!writeBar(device, i, 0)) {
143 device->setPciConfigHeader(assigned);
144 if (!PciResources::addFunction(device)) {
148 const auto probe = PciBar::probe(pci, device, assigned);
149 if (probe.result != PciBar::ProbeResult::Success) {
152 for (
size_t i = 0; i < 6; ++i) {
153 const uint32_t low = assigned.bar[i];
154 const bool wide = !(low & 1U) && (low & 6U) == 4;
155 if ((low & 6U) && !wide) {
158 uint64_t mask = probe.masks[i] & ~uint32_t{15};
163 mask |= uint64_t(probe.masks[i + 1]) << 32;
174 const uint64_t width = wide ? ~uint64_t{0} : 0xffffffffU;
175 const uint64_t bytes = ((~mask) & width) + 1;
176 uint64_t base = 0, cpu = 0;
177 if (!bytes || (bytes & (bytes - 1)) || bytes > ~
size_t{0} ||
178 !PciResources::allocate(device, bytes, bytes, low & 8U, width, base) ||
179 !pci.translateAddress(base, bytes,
false, cpu) || cpu > ~uintptr_t{0}) {
182 assigned.bar[i] = uint32_t(base) | low;
183 if (!writeBar(device, i, assigned.bar[i])) {
186 char name[] = {
'b',
'a',
'r',
static_cast<char>(
'0' + i), 0};
189 assigned.bar[++i] = base >> 32;
190 if (!writeBar(device, i, assigned.bar[i])) {
195 device->setPciConfigHeader(assigned);
196 const uint32_t route = pci.interruptRoute(number, 0, 0, assigned.interrupt_pin);
197 device->setInterruptNumber(route ? route : assigned.interrupt_line);
202 const bool bound = PciDrivers::attach(device);
203 NOTICE(
"PCI hotplug: inserted " <<
Dec <<
unsigned(number) <<
":0.0 driver bound=" << bound);
207bool prepareRemoveSlot(
Device* port) {
209 Device* device = leaf(slotBus(port, number));
210 return device && noVirtualFunctions(device) && PciDrivers::prepareRemove(device);
213void cancelRemoveSlot(
Device* port) {
215 if (
Device* device = leaf(slotBus(port, number))) {
216 PciDrivers::cancelRemove(device);
220bool removeSlot(
Device* port) {
222 Device* bus = slotBus(port, number);
223 Device* device = leaf(bus);
224 if (!device || !PciDrivers::remove(device)) {
227 auto& pci = PciBus::instance();
228 if (!pci.updateCommand(device, 7U, 0) || !PciResources::removeFunction(device)) {
229 panic(
"PCI hotplug: cannot retire endpoint resources");
234 device->setParent(
nullptr);
237 NOTICE(
"PCI hotplug: removed " <<
Dec <<
unsigned(number) <<
":0.0");
Device * getChild(size_t n)
uint8_t getPciClassCode()
void addChild(Device *pDevice)
virtual const String & getSpecificType()
uint8_t getPciSubclassCode()
uint32_t getPciBusPosition()
void removeChild(size_t n)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN