]> xenbits.xensource.com Git - seabios.git/commitdiff
pci: Split low-level pci code from higher-level 'struct pci_device' code
authorKevin O'Connor <kevin@koconnor.net>
Wed, 3 Feb 2016 06:28:20 +0000 (01:28 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Wed, 3 Feb 2016 15:38:42 +0000 (10:38 -0500)
Split pci.c into pci.c and pcidevice.c.  The low-level code that
interacts directly with the PCI devices remains in pci.c, while
functions dealing with the higher level pci_device cache move to
pcidevice.c.  Only pci.c is needed in 16bit mode.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
32 files changed:
Makefile
src/boot.c
src/fw/acpi.c
src/fw/coreboot.c
src/fw/csm.c
src/fw/mptable.c
src/fw/paravirt.c
src/fw/pciinit.c
src/fw/smm.c
src/hw/ahci.c
src/hw/ata.c
src/hw/esp-scsi.c
src/hw/floppy.c
src/hw/lsi-scsi.c
src/hw/megasas.c
src/hw/pci.c
src/hw/pci.h
src/hw/pcidevice.c [new file with mode: 0644]
src/hw/pcidevice.h [new file with mode: 0644]
src/hw/pvscsi.c
src/hw/sdcard.c
src/hw/usb-ehci.c
src/hw/usb-ohci.c
src/hw/usb-uhci.c
src/hw/usb-xhci.c
src/hw/virtio-blk.c
src/hw/virtio-pci.c
src/hw/virtio-scsi.c
src/optionroms.c
src/output.c
src/pcibios.c
src/vgahooks.c

index cbe94544691a1806ed24fe69ffeee7cee1450dbb..b0eb2393d8d3441a8eb63a11c76e3cbffbca0870 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
 SRC16=$(SRCBOTH)
 SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c optionroms.c \
     pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \
-    hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
+    hw/pcidevice.c hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
     fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \
     fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/smp.c fw/mtrr.c fw/xen.c \
     fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \
index a045a8e18c5a0605b908b4b858b797c85b506015..706b7dfe013b45b02f2f2670633fa4a02cef5b03 100644 (file)
@@ -10,6 +10,7 @@
 #include "config.h" // CONFIG_*
 #include "fw/paravirt.h" // qemu_cfg_show_boot_menu
 #include "hw/pci.h" // pci_bdf_to_*
+#include "hw/pcidevice.h" // struct pci_device
 #include "hw/rtc.h" // rtc_read
 #include "hw/usb.h" // struct usbdevice_s
 #include "list.h" // hlist_node
index b805b44f0d97f02fdb83a5977918cb99627b0e51..8bc2ca6b584244a4e47a961c893d5f4577d5c62f 100644 (file)
@@ -10,7 +10,7 @@
 #include "config.h" // CONFIG_*
 #include "dev-q35.h"
 #include "dev-piix.h"
-#include "hw/pci.h" // pci_find_init_device
+#include "hw/pcidevice.h" // pci_find_init_device
 #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "hw/pci_regs.h" // PCI_INTERRUPT_LINE
 #include "malloc.h" // free
index 4fe12928cda87f3bd04df246e044b252885218a1..4957b80dce7084418bfa885c1459619c265f3239 100644 (file)
@@ -8,7 +8,7 @@
 #include "byteorder.h" // be32_to_cpu
 #include "config.h" // CONFIG_*
 #include "e820map.h" // e820_add
-#include "hw/pci.h" // pci_probe_devices
+#include "hw/pcidevice.h" // pci_probe_devices
 #include "lzmadecode.h" // LzmaDecode
 #include "malloc.h" // free
 #include "output.h" // dprintf
index b01f181f95c1480426604ac04625d48ff5b61419..03b4bb81e3e85757cb6ec776e4bd2067222542ca 100644 (file)
@@ -8,7 +8,8 @@
 #include "config.h" // CONFIG_*
 #include "e820map.h" // e820_add
 #include "farptr.h" // MAKE_FLATPTR
-#include "hw/pci.h" // pci_probe_devices
+#include "hw/pci.h" // pci_to_bdf
+#include "hw/pcidevice.h" // pci_probe_devices
 #include "hw/pic.h" // pic_irqmask_read
 #include "malloc.h" // malloc_csm_preinit
 #include "memmap.h" // SYMBOL
index 8e01e00439c7c09986d3cd67956dba502fb71972..47385cc5d32dddc23c5509c0f12dec3070cd0041 100644 (file)
@@ -7,8 +7,9 @@
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "config.h" // CONFIG_*
-#include "hw/pci.h"
-#include "hw/pci_regs.h"
+#include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pcidevice.h" // foreachpci
+#include "hw/pci_regs.h" // PCI_INTERRUPT_PIN
 #include "malloc.h" // free
 #include "output.h" // dprintf
 #include "romfile.h" // romfile_loadint
index 3fae13a8312fa6677db98fedf49566aa75cac6f0..8ed438074cdb1545ddeda010d01779baa951c20d 100644 (file)
@@ -11,7 +11,8 @@
 #include "byteorder.h" // be32_to_cpu
 #include "config.h" // CONFIG_QEMU
 #include "e820map.h" // e820_add
-#include "hw/pci.h" // create_pirtable
+#include "hw/pci.h" // pci_config_readw
+#include "hw/pcidevice.h" // pci_probe_devices
 #include "hw/pci_regs.h" // PCI_DEVICE_ID
 #include "hw/rtc.h" // CMOS_*
 #include "malloc.h" // malloc_tmp
index ead2c1a31249c31cd26075bda28de7137853e16a..0ed5dfbb533b9e22039389419fc7ca7cf3f2799e 100644 (file)
@@ -12,6 +12,7 @@
 #include "e820map.h" // e820_add
 #include "hw/ata.h" // PORT_ATA1_CMD_BASE
 #include "hw/pci.h" // pci_config_readl
+#include "hw/pcidevice.h" // pci_probe_devices
 #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "hw/pci_regs.h" // PCI_COMMAND
 #include "list.h" // struct hlist_node
index 8f042ee4dec5507eee1d4d44d2999b1d278baf01..95f6ba7d9a09a0c2958dfbc462a76853fda6fa5c 100644 (file)
@@ -9,6 +9,7 @@
 #include "dev-q35.h"
 #include "dev-piix.h"
 #include "hw/pci.h" // pci_config_writel
+#include "hw/pcidevice.h" // pci_find_device
 #include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
 #include "hw/pci_regs.h" // PCI_DEVICE_ID
 #include "output.h" // dprintf
index bd21bf648dc3460487efd4ba81bdfbb9beb9d436..9310850b2b4a636481c72b71c74dd4b473ada1c1 100644 (file)
@@ -10,7 +10,8 @@
 #include "blockcmd.h" // CDB_CMD_READ_10
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pci.h" // pci_config_readb
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
 #include "pci_regs.h" // PCI_INTERRUPT_LINE
 #include "stacks.h" // yield
index 12dab961cac91ab764cccff978ae806c43abd74f..9a4b43543749478940eb231cb59360f7da68ce46 100644 (file)
@@ -12,7 +12,8 @@
 #include "byteorder.h" // be16_to_cpu
 #include "malloc.h" // malloc_fseg
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pci.h" // pci_config_readb
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
 #include "pci_regs.h" // PCI_INTERRUPT_LINE
 #include "pic.h" // enable_hwirq
index 9abc361f586c4612f8edb896d1514a5b2836596e..086a0328a1551349cba066a3d6b20365583491e9 100644 (file)
@@ -17,7 +17,7 @@
 #include "fw/paravirt.h" // runningOnQEMU
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "std/disk.h" // DISK_RET_SUCCESS
index a14f7e093fcc46990a0b0cbf3c32e0a067a790f7..98ed9bbf40cd36cbb3b83577536a79d71ad501c7 100644 (file)
@@ -11,7 +11,7 @@
 #include "config.h" // CONFIG_FLOPPY
 #include "malloc.h" // malloc_fseg
 #include "output.h" // dprintf
-#include "pci.h" // pci_to_bdf
+#include "pcidevice.h" // pci_find_class
 #include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA
 #include "pic.h" // pic_eoi1
 #include "romfile.h" // romfile_loadint
index 5d872a2133e72028e418aa8b66be310f7d10f120..564c9f156c6a94887e36ae0e93cf862ae88db3d9 100644 (file)
@@ -17,7 +17,7 @@
 #include "fw/paravirt.h" // runningOnQEMU
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "std/disk.h" // DISK_RET_SUCCESS
index 71af3c308416f9f466884e324945a78f91c7e802..2ee457b89cc88595ceb07b2eb0cae5bbcc294f1b 100644 (file)
@@ -16,7 +16,8 @@
 #include "config.h" // CONFIG_*
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pci.h" // pci_config_readl
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID_XXX
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "stacks.h" // yield
index dcf240cb8dee8032fd3c463526d0e462451135a0..506ee563e7a1dc472b71ee827bf567d43cb85905 100644 (file)
@@ -5,16 +5,16 @@
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
-#include "malloc.h" // malloc_tmp
 #include "output.h" // dprintf
 #include "pci.h" // pci_config_writel
 #include "pci_regs.h" // PCI_VENDOR_ID
-#include "romfile.h" // romfile_loadint
-#include "stacks.h" // wait_preempt
-#include "string.h" // memset
 #include "util.h" // udelay
 #include "x86.h" // outl
 
+#define PORT_PCI_CMD           0x0cf8
+#define PORT_PCI_REBOOT        0x0cf9
+#define PORT_PCI_DATA          0x0cfc
+
 void pci_config_writel(u16 bdf, u32 addr, u32 val)
 {
     outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
@@ -87,9 +87,6 @@ pci_next(int bdf, int bus)
     }
 }
 
-struct hlist_head PCIDevices VARVERIFY32INIT;
-int MaxPCIBus VARFSEG;
-
 // Check if PCI is available at all
 int
 pci_probe_host(void)
@@ -102,208 +99,6 @@ pci_probe_host(void)
     return 0;
 }
 
-// Find all PCI devices and populate PCIDevices linked list.
-void
-pci_probe_devices(void)
-{
-    dprintf(3, "PCI probe\n");
-    struct pci_device *busdevs[256];
-    memset(busdevs, 0, sizeof(busdevs));
-    struct hlist_node **pprev = &PCIDevices.first;
-    int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
-    int bus = -1, lastbus = 0, rootbuses = 0, count=0;
-    while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
-        bus++;
-        int bdf;
-        foreachbdf(bdf, bus) {
-            // Create new pci_device struct and add to list.
-            struct pci_device *dev = malloc_tmp(sizeof(*dev));
-            if (!dev) {
-                warn_noalloc();
-                return;
-            }
-            memset(dev, 0, sizeof(*dev));
-            hlist_add(&dev->node, pprev);
-            pprev = &dev->node.next;
-            count++;
-
-            // Find parent device.
-            int rootbus;
-            struct pci_device *parent = busdevs[bus];
-            if (!parent) {
-                if (bus != lastbus)
-                    rootbuses++;
-                lastbus = bus;
-                rootbus = rootbuses;
-                if (bus > MaxPCIBus)
-                    MaxPCIBus = bus;
-            } else {
-                rootbus = parent->rootbus;
-            }
-
-            // Populate pci_device info.
-            dev->bdf = bdf;
-            dev->parent = parent;
-            dev->rootbus = rootbus;
-            u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
-            dev->vendor = vendev & 0xffff;
-            dev->device = vendev >> 16;
-            u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
-            dev->class = classrev >> 16;
-            dev->prog_if = classrev >> 8;
-            dev->revision = classrev & 0xff;
-            dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
-            u8 v = dev->header_type & 0x7f;
-            if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
-                u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
-                dev->secondary_bus = secbus;
-                if (secbus > bus && !busdevs[secbus])
-                    busdevs[secbus] = dev;
-                if (secbus > MaxPCIBus)
-                    MaxPCIBus = secbus;
-            }
-            dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x)\n"
-                    , dev, dev->vendor, dev->device, dev->class);
-        }
-    }
-    dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
-}
-
-// Search for a device with the specified vendor and device ids.
-struct pci_device *
-pci_find_device(u16 vendid, u16 devid)
-{
-    struct pci_device *pci;
-    foreachpci(pci) {
-        if (pci->vendor == vendid && pci->device == devid)
-            return pci;
-    }
-    return NULL;
-}
-
-// Search for a device with the specified class id.
-struct pci_device *
-pci_find_class(u16 classid)
-{
-    struct pci_device *pci;
-    foreachpci(pci) {
-        if (pci->class == classid)
-            return pci;
-    }
-    return NULL;
-}
-
-int pci_init_device(const struct pci_device_id *ids
-                    , struct pci_device *pci, void *arg)
-{
-    while (ids->vendid || ids->class_mask) {
-        if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
-            (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
-            !((ids->class ^ pci->class) & ids->class_mask)) {
-            if (ids->func)
-                ids->func(pci, arg);
-            return 0;
-        }
-        ids++;
-    }
-    return -1;
-}
-
-struct pci_device *
-pci_find_init_device(const struct pci_device_id *ids, void *arg)
-{
-    struct pci_device *pci;
-    foreachpci(pci) {
-        if (pci_init_device(ids, pci, arg) == 0)
-            return pci;
-    }
-    return NULL;
-}
-
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap)
-{
-    int i;
-    u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
-
-    if (!(status & PCI_STATUS_CAP_LIST))
-        return 0;
-
-    if (cap == 0) {
-        /* find first */
-        cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
-    } else {
-        /* find next */
-        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
-    }
-    for (i = 0; cap && i <= 0xff; i++) {
-        if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
-            return cap;
-        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
-    }
-
-    return 0;
-}
-
-// Enable PCI bus-mastering (ie, DMA) support on a pci device
-void
-pci_enable_busmaster(struct pci_device *pci)
-{
-    ASSERT32FLAT();
-    wait_preempt();
-    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
-    pci->have_driver = 1;
-}
-
-// Verify an IO bar and return it to the caller
-u16
-pci_enable_iobar(struct pci_device *pci, u32 addr)
-{
-    ASSERT32FLAT();
-    wait_preempt();
-    u32 bar = pci_config_readl(pci->bdf, addr);
-    if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
-        warn_internalerror();
-        return 0;
-    }
-    bar &= PCI_BASE_ADDRESS_IO_MASK;
-    if (bar == 0 || bar > 0xffff) {
-        warn_internalerror();
-        return 0;
-    }
-    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
-    pci->have_driver = 1;
-    return bar;
-}
-
-// Verify a memory bar and return it to the caller
-void *
-pci_enable_membar(struct pci_device *pci, u32 addr)
-{
-    ASSERT32FLAT();
-    wait_preempt();
-    u32 bar = pci_config_readl(pci->bdf, addr);
-    if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
-        warn_internalerror();
-        return NULL;
-    }
-    if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-        u32 high = pci_config_readl(pci->bdf, addr+4);
-        if (high) {
-            dprintf(1, "Can not map memory bar over 4Gig\n");
-            return NULL;
-        }
-    }
-    bar &= PCI_BASE_ADDRESS_MEM_MASK;
-    if (bar + 4*1024*1024 < 20*1024*1024) {
-        // Bar doesn't look valid (it is in last 4M or first 16M)
-        warn_internalerror();
-        return NULL;
-    }
-    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
-    pci->have_driver = 1;
-    return (void*)bar;
-}
-
 void
 pci_reboot(void)
 {
index 61eb1f388d57f9eca0c5ce36765a08c3eeb7fe61..bf50430349672c93d4c0a66f05dfb9df91cb325d 100644 (file)
@@ -2,11 +2,6 @@
 #define __PCI_H
 
 #include "types.h" // u32
-#include "list.h" // hlist_node
-
-#define PORT_PCI_CMD           0x0cf8
-#define PORT_PCI_REBOOT        0x0cf9
-#define PORT_PCI_DATA          0x0cfc
 
 static inline u8 pci_bdf_to_bus(u16 bdf) {
     return bdf >> 8;
@@ -30,6 +25,11 @@ static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) {
     return (bus << 8) | devfn;
 }
 
+#define foreachbdf(BDF, BUS)                                    \
+    for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS))  \
+         ; BDF >= 0                                             \
+         ; BDF=pci_next(BDF, (BUS)))
+
 void pci_config_writel(u16 bdf, u32 addr, u32 val);
 void pci_config_writew(u16 bdf, u32 addr, u16 val);
 void pci_config_writeb(u16 bdf, u32 addr, u8 val);
@@ -37,83 +37,8 @@ u32 pci_config_readl(u16 bdf, u32 addr);
 u16 pci_config_readw(u16 bdf, u32 addr);
 u8 pci_config_readb(u16 bdf, u32 addr);
 void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on);
-
-struct pci_device *pci_find_device(u16 vendid, u16 devid);
-struct pci_device *pci_find_class(u16 classid);
-
-struct pci_device {
-    u16 bdf;
-    u8 rootbus;
-    struct hlist_node node;
-    struct pci_device *parent;
-
-    // Configuration space device information
-    u16 vendor, device;
-    u16 class;
-    u8 prog_if, revision;
-    u8 header_type;
-    u8 secondary_bus;
-
-    // Local information on device.
-    int have_driver;
-};
-extern struct hlist_head PCIDevices;
-extern int MaxPCIBus;
-int pci_probe_host(void);
-void pci_probe_devices(void);
-static inline u32 pci_classprog(struct pci_device *pci) {
-    return (pci->class << 8) | pci->prog_if;
-}
-
-#define foreachpci(PCI)                                 \
-    hlist_for_each_entry(PCI, &PCIDevices, node)
-
 int pci_next(int bdf, int bus);
-#define foreachbdf(BDF, BUS)                                    \
-    for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS))  \
-         ; BDF >= 0                                             \
-         ; BDF=pci_next(BDF, (BUS)))
-
-#define PCI_ANY_ID      (~0)
-struct pci_device_id {
-    u32 vendid;
-    u32 devid;
-    u32 class;
-    u32 class_mask;
-    void (*func)(struct pci_device *pci, void *arg);
-};
-
-#define PCI_DEVICE(vendor_id, device_id, init_func)     \
-    {                                                   \
-        .vendid = (vendor_id),                          \
-        .devid = (device_id),                           \
-        .class = PCI_ANY_ID,                            \
-        .class_mask = 0,                                \
-        .func = (init_func)                             \
-    }
-
-#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func)   \
-    {                                                                   \
-        .vendid = (vendor_id),                                          \
-        .devid = (device_id),                                           \
-        .class = (class_code),                                          \
-        .class_mask = ~0,                                               \
-        .func = (init_func)                                             \
-    }
-
-#define PCI_DEVICE_END                          \
-    {                                           \
-        .vendid = 0,                            \
-    }
-
-int pci_init_device(const struct pci_device_id *ids
-                    , struct pci_device *pci, void *arg);
-struct pci_device *pci_find_init_device(const struct pci_device_id *ids
-                                        , void *arg);
-u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
-void pci_enable_busmaster(struct pci_device *pci);
-u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
-void *pci_enable_membar(struct pci_device *pci, u32 addr);
+int pci_probe_host(void);
 void pci_reboot(void);
 
-#endif
+#endif // pci.h
diff --git a/src/hw/pcidevice.c b/src/hw/pcidevice.c
new file mode 100644 (file)
index 0000000..cfebf66
--- /dev/null
@@ -0,0 +1,216 @@
+// Code to maintain and access the pci_device cache
+//
+// Copyright (C) 2008-2016  Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "malloc.h" // malloc_tmp
+#include "output.h" // dprintf
+#include "pci.h" // pci_config_writel
+#include "pcidevice.h" // pci_probe_devices
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "romfile.h" // romfile_loadint
+#include "stacks.h" // wait_preempt
+#include "string.h" // memset
+
+struct hlist_head PCIDevices VARVERIFY32INIT;
+int MaxPCIBus VARFSEG;
+
+// Find all PCI devices and populate PCIDevices linked list.
+void
+pci_probe_devices(void)
+{
+    dprintf(3, "PCI probe\n");
+    struct pci_device *busdevs[256];
+    memset(busdevs, 0, sizeof(busdevs));
+    struct hlist_node **pprev = &PCIDevices.first;
+    int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
+    int bus = -1, lastbus = 0, rootbuses = 0, count=0;
+    while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
+        bus++;
+        int bdf;
+        foreachbdf(bdf, bus) {
+            // Create new pci_device struct and add to list.
+            struct pci_device *dev = malloc_tmp(sizeof(*dev));
+            if (!dev) {
+                warn_noalloc();
+                return;
+            }
+            memset(dev, 0, sizeof(*dev));
+            hlist_add(&dev->node, pprev);
+            pprev = &dev->node.next;
+            count++;
+
+            // Find parent device.
+            int rootbus;
+            struct pci_device *parent = busdevs[bus];
+            if (!parent) {
+                if (bus != lastbus)
+                    rootbuses++;
+                lastbus = bus;
+                rootbus = rootbuses;
+                if (bus > MaxPCIBus)
+                    MaxPCIBus = bus;
+            } else {
+                rootbus = parent->rootbus;
+            }
+
+            // Populate pci_device info.
+            dev->bdf = bdf;
+            dev->parent = parent;
+            dev->rootbus = rootbus;
+            u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+            dev->vendor = vendev & 0xffff;
+            dev->device = vendev >> 16;
+            u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
+            dev->class = classrev >> 16;
+            dev->prog_if = classrev >> 8;
+            dev->revision = classrev & 0xff;
+            dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+            u8 v = dev->header_type & 0x7f;
+            if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+                u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+                dev->secondary_bus = secbus;
+                if (secbus > bus && !busdevs[secbus])
+                    busdevs[secbus] = dev;
+                if (secbus > MaxPCIBus)
+                    MaxPCIBus = secbus;
+            }
+            dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x)\n"
+                    , dev, dev->vendor, dev->device, dev->class);
+        }
+    }
+    dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
+}
+
+// Search for a device with the specified vendor and device ids.
+struct pci_device *
+pci_find_device(u16 vendid, u16 devid)
+{
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci->vendor == vendid && pci->device == devid)
+            return pci;
+    }
+    return NULL;
+}
+
+// Search for a device with the specified class id.
+struct pci_device *
+pci_find_class(u16 classid)
+{
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci->class == classid)
+            return pci;
+    }
+    return NULL;
+}
+
+int pci_init_device(const struct pci_device_id *ids
+                    , struct pci_device *pci, void *arg)
+{
+    while (ids->vendid || ids->class_mask) {
+        if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
+            (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
+            !((ids->class ^ pci->class) & ids->class_mask)) {
+            if (ids->func)
+                ids->func(pci, arg);
+            return 0;
+        }
+        ids++;
+    }
+    return -1;
+}
+
+struct pci_device *
+pci_find_init_device(const struct pci_device_id *ids, void *arg)
+{
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci_init_device(ids, pci, arg) == 0)
+            return pci;
+    }
+    return NULL;
+}
+
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap)
+{
+    int i;
+    u16 status = pci_config_readw(pci->bdf, PCI_STATUS);
+
+    if (!(status & PCI_STATUS_CAP_LIST))
+        return 0;
+
+    if (cap == 0) {
+        /* find first */
+        cap = pci_config_readb(pci->bdf, PCI_CAPABILITY_LIST);
+    } else {
+        /* find next */
+        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
+    }
+    for (i = 0; cap && i <= 0xff; i++) {
+        if (pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_ID) == cap_id)
+            return cap;
+        cap = pci_config_readb(pci->bdf, cap + PCI_CAP_LIST_NEXT);
+    }
+
+    return 0;
+}
+
+// Enable PCI bus-mastering (ie, DMA) support on a pci device
+void
+pci_enable_busmaster(struct pci_device *pci)
+{
+    wait_preempt();
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+    pci->have_driver = 1;
+}
+
+// Verify an IO bar and return it to the caller
+u16
+pci_enable_iobar(struct pci_device *pci, u32 addr)
+{
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
+        warn_internalerror();
+        return 0;
+    }
+    bar &= PCI_BASE_ADDRESS_IO_MASK;
+    if (bar == 0 || bar > 0xffff) {
+        warn_internalerror();
+        return 0;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+    pci->have_driver = 1;
+    return bar;
+}
+
+// Verify a memory bar and return it to the caller
+void *
+pci_enable_membar(struct pci_device *pci, u32 addr)
+{
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+        warn_internalerror();
+        return NULL;
+    }
+    if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        u32 high = pci_config_readl(pci->bdf, addr+4);
+        if (high) {
+            dprintf(1, "Can not map memory bar over 4Gig\n");
+            return NULL;
+        }
+    }
+    bar &= PCI_BASE_ADDRESS_MEM_MASK;
+    if (bar + 4*1024*1024 < 20*1024*1024) {
+        // Bar doesn't look valid (it is in last 4M or first 16M)
+        warn_internalerror();
+        return NULL;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+    pci->have_driver = 1;
+    return (void*)bar;
+}
diff --git a/src/hw/pcidevice.h b/src/hw/pcidevice.h
new file mode 100644 (file)
index 0000000..354b549
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef __PCIDEVICE_H
+#define __PCIDEVICE_H
+
+#include "types.h" // u32
+#include "list.h" // hlist_node
+
+struct pci_device {
+    u16 bdf;
+    u8 rootbus;
+    struct hlist_node node;
+    struct pci_device *parent;
+
+    // Configuration space device information
+    u16 vendor, device;
+    u16 class;
+    u8 prog_if, revision;
+    u8 header_type;
+    u8 secondary_bus;
+
+    // Local information on device.
+    int have_driver;
+};
+extern struct hlist_head PCIDevices;
+extern int MaxPCIBus;
+
+static inline u32 pci_classprog(struct pci_device *pci) {
+    return (pci->class << 8) | pci->prog_if;
+}
+
+#define foreachpci(PCI)                                 \
+    hlist_for_each_entry(PCI, &PCIDevices, node)
+
+#define PCI_ANY_ID      (~0)
+struct pci_device_id {
+    u32 vendid;
+    u32 devid;
+    u32 class;
+    u32 class_mask;
+    void (*func)(struct pci_device *pci, void *arg);
+};
+
+#define PCI_DEVICE(vendor_id, device_id, init_func)     \
+    {                                                   \
+        .vendid = (vendor_id),                          \
+        .devid = (device_id),                           \
+        .class = PCI_ANY_ID,                            \
+        .class_mask = 0,                                \
+        .func = (init_func)                             \
+    }
+
+#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func)   \
+    {                                                                   \
+        .vendid = (vendor_id),                                          \
+        .devid = (device_id),                                           \
+        .class = (class_code),                                          \
+        .class_mask = ~0,                                               \
+        .func = (init_func)                                             \
+    }
+
+#define PCI_DEVICE_END                          \
+    {                                           \
+        .vendid = 0,                            \
+    }
+
+void pci_probe_devices(void);
+struct pci_device *pci_find_device(u16 vendid, u16 devid);
+struct pci_device *pci_find_class(u16 classid);
+int pci_init_device(const struct pci_device_id *ids
+                    , struct pci_device *pci, void *arg);
+struct pci_device *pci_find_init_device(const struct pci_device_id *ids
+                                        , void *arg);
+u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
+void pci_enable_busmaster(struct pci_device *pci);
+u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
+void *pci_enable_membar(struct pci_device *pci, u32 addr);
+
+#endif // pcidevice.h
index b1dd03f829cebbbc18f5184772bae5b9c47bb583..e1685b3c7579d871adadc583091eb08b8af43fca 100644 (file)
@@ -13,7 +13,7 @@
 #include "malloc.h" // free
 #include "memmap.h" // PAGE_SHIFT, virt_to_phys
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID_VMWARE_PVSCSI
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "pvscsi.h" // pvscsi_setup
index 1524b51a16c6019de4d98804db445dc083e19995..7e0875f6de76257b2546c6b8c53c9ed1577a722e 100644 (file)
@@ -7,7 +7,7 @@
 #include "block.h" // struct drive_s
 #include "malloc.h" // malloc_fseg
 #include "output.h" // znprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_SYSTEM_SDHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "romfile.h" // romfile_findprefix
index 1d1eb5747c91ff24d2b67db8e5765d8ffc78e362..7eca55bddd9110d2883291ba21a99bf4e64c23a1 100644 (file)
@@ -9,7 +9,7 @@
 #include "output.h" // dprintf
 #include "malloc.h" // free
 #include "memmap.h" // PAGE_SIZE
-#include "pci.h" // pci_bdf_to_bus
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
index b58657582a085cc8baa5b31f1f2eef60a69156ac..90f60e6452957552412d2aa9958f00141473437a 100644 (file)
@@ -9,7 +9,7 @@
 #include "malloc.h" // free
 #include "memmap.h" // PAGE_SIZE
 #include "output.h" // dprintf
-#include "pci.h" // pci_bdf_to_bus
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_OHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
index ed7c39a4edacb1623cf0e26d8a877da9996994bd..075ed02cd854b1186342c9a667ddf4a1d43a9f51 100644 (file)
@@ -8,7 +8,8 @@
 #include "config.h" // CONFIG_*
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // pci_bdf_to_bus
+#include "pci.h" // pci_config_writew
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_4
 #include "string.h" // memset
index 6c1720de9bd8ea19570b0b543793dbddefd695b8..5e2f07188f35849a12d769674717f1da72c9e678 100644 (file)
@@ -9,7 +9,7 @@
 #include "malloc.h" // memalign_low
 #include "memmap.h" // PAGE_SIZE
 #include "output.h" // dprintf
-#include "pci.h" // pci_bdf_to_bus
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_XHCI
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memcpy
index cd0cbe90d2c0603f9d855f52fb02934cfea5fe2e..2dfd0c34bf8f509d5f4c71bfb91d8ad980001b1c 100644 (file)
@@ -12,7 +12,7 @@
 #include "block.h" // struct drive_s
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "std/disk.h" // DISK_RET_SUCCESS
index 378d901854e15b13ff92b7c7b8da9767841e20bf..ce15672279741e218e21983f90f78e23a7fa4989 100644 (file)
@@ -19,6 +19,7 @@
 #include "malloc.h" // free
 #include "output.h" // dprintf
 #include "pci.h" // pci_config_readl
+#include "pcidevice.h" // pci_find_capability
 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
 #include "string.h" // memset
 #include "virtio-pci.h"
index f7f01cda457e35c08feb0c440f105dd3d0515d34..322d469173b943aa4a1aa692c3c0578bd3a89baa 100644 (file)
@@ -13,7 +13,7 @@
 #include "config.h" // CONFIG_*
 #include "malloc.h" // free
 #include "output.h" // dprintf
-#include "pci.h" // foreachpci
+#include "pcidevice.h" // foreachpci
 #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "std/disk.h" // DISK_RET_SUCCESS
index a389dd93be93e66690ff22c7f7e703079dc96a8f..98977530b4813e3aa3913786924c3a5ff433e12c 100644 (file)
@@ -8,7 +8,8 @@
 #include "bregs.h" // struct bregs
 #include "config.h" // CONFIG_*
 #include "farptr.h" // FLATPTR_TO_SEG
-#include "hw/pci.h" // foreachpci
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pcidevice.h" // foreachpci
 #include "hw/pci_ids.h" // PCI_CLASS_DISPLAY_VGA
 #include "hw/pci_regs.h" // PCI_ROM_ADDRESS
 #include "malloc.h" // rom_confirm
index 9a8a130a0b55c3dce7376411ffb3a16875547877..ec51f5e2f6ecf012825e9069e43ccde8232f947e 100644 (file)
@@ -11,6 +11,7 @@
 #include "config.h" // CONFIG_*
 #include "biosvar.h" // GET_GLOBAL
 #include "hw/pci.h" // pci_bdf_to_bus
+#include "hw/pcidevice.h" // pci_device
 #include "hw/serialio.h" // serial_debug_putc
 #include "malloc.h" // malloc_tmp
 #include "output.h" // dprintf
index 7e5d972d9780e5ac15f7520f312f16d66e0951cc..81735e3dd6d1b8bbecc598181799192ce5089c36 100644 (file)
@@ -8,6 +8,7 @@
 #include "biosvar.h" // GET_GLOBAL
 #include "bregs.h" // struct bregs
 #include "hw/pci.h" // pci_config_readl
+#include "hw/pcidevice.h" // MaxPCIBus
 #include "hw/pci_regs.h" // PCI_VENDOR_ID
 #include "output.h" // dprintf
 #include "std/pirtable.h" // struct pir_header
index 48efb086cc34c83cd331d0d9f5fe89a0bee465f9..1f1495329ce5781e3df0ed1385b26c4e04fff5d4 100644 (file)
@@ -7,7 +7,8 @@
 #include "biosvar.h" // GET_GLOBAL
 #include "bregs.h" // set_code_invalid
 #include "config.h" // CONFIG_*
-#include "hw/pci.h" // pci_find_device
+#include "hw/pci.h" // pci_config_readb
+#include "hw/pcidevice.h" // pci_find_device
 #include "hw/pci_ids.h" // PCI_VENDOR_ID_VIA
 #include "hw/pci_regs.h" // PCI_VENDOR_ID
 #include "output.h" // dprintf