From c0b1a2d6c0e0009a32755911b2a2f65de0e50986 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 18 Sep 2025 13:47:21 -0400 Subject: kern: pci: Add initial bus enumeration Signed-off-by: Ian Moffett --- src/sys/include/io/pci/pci.h | 4 +++ src/sys/io/pci/pci.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/src/sys/include/io/pci/pci.h b/src/sys/include/io/pci/pci.h index a636ce7..8f65aa3 100644 --- a/src/sys/include/io/pci/pci.h +++ b/src/sys/include/io/pci/pci.h @@ -43,11 +43,15 @@ typedef uint32_t pcival_t; * @bus: Bus number of device * @slot: Slot number of device * @func: Function number of device + * @vendor: Vendor ID + * @device: Device ID */ struct pci_device { uint16_t bus; uint8_t slot; uint8_t func; + uint16_t vendor; + uint16_t device; }; /* diff --git a/src/sys/io/pci/pci.c b/src/sys/io/pci/pci.c index 864e4c3..a4bf125 100644 --- a/src/sys/io/pci/pci.c +++ b/src/sys/io/pci/pci.c @@ -35,8 +35,87 @@ #include #include +#define PCI_BUS_ROOT 0 + static struct cam_hook cam; +/* + * Attempt to register a PCI device and bail + * if it doesn't exist on the bus. + */ +static void +pci_register_dev(struct pci_device *dev) +{ + pcireg_t vend_dev; + uint16_t device_id; + uint16_t vendor_id; + + if (dev == NULL) { + return; + } + + /* Get the vendor and device ID */ + vend_dev = pci_readl(dev, PCIREG_VENDOR_ID); + vendor_id = vend_dev & 0xFFFF; + device_id = (vendor_id >> 16) & 0xFFFF; + + /* Does this device exist? */ + if (vendor_id == 0xFFFF) { + return; + } + + /* + * Log out the BDF notation as well as vendor, + * and logical slot ID. + */ + printf( + "bridge: device @ pci <%x.%x.%x>\n", + dev->bus, dev->slot, + dev->func, dev->vendor, + dev->slot + ); +} + +/* + * Enumerate a specifc bus of its devices + * + * @bus: Bus to enumerate + */ +static void +pci_enum_bus(uint16_t bus) +{ + pcireg_t reg; + struct pci_device dev; + if (bus > 256) { + printf("pci_enum_bus: bad bus number %x\n", bus); + return; + } + + dev.bus = bus; + for (int slot = 0; slot < 32; ++slot) { + dev.slot = slot; + dev.func = 0; + reg = pci_readl(&dev, PCIREG_HDRTYPE); + + /* + * Section 6.2.1 of the PCI spec states that some + * devices may only implement a single function. + * We can check this with bit 7 of the header type + * register. If we read a 1, it is a multifunction + * device. + */ + if (!ISSET(reg, BIT(7))) { + pci_register_dev(&dev); + continue; + } + + for (uint8_t func = 0; func < 8; ++func) { + pci_register_dev(&dev); + ++dev.func; + } + } +} + /* * Read from a specific register */ @@ -73,4 +152,6 @@ pci_init_bus(void) printf("pci_init_bus: pci_cam_init() returned %d\n", error); panic("pci_init_bus: failed to init CAM\n"); } + + pci_enum_bus(PCI_BUS_ROOT); } -- cgit v1.2.3