diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/boot.c | 1 | ||||
-rw-r--r-- | src/fw/acpi.c | 2 | ||||
-rw-r--r-- | src/fw/coreboot.c | 2 | ||||
-rw-r--r-- | src/fw/csm.c | 3 | ||||
-rw-r--r-- | src/fw/mptable.c | 5 | ||||
-rw-r--r-- | src/fw/paravirt.c | 3 | ||||
-rw-r--r-- | src/fw/pciinit.c | 1 | ||||
-rw-r--r-- | src/fw/smm.c | 1 | ||||
-rw-r--r-- | src/hw/ahci.c | 3 | ||||
-rw-r--r-- | src/hw/ata.c | 3 | ||||
-rw-r--r-- | src/hw/esp-scsi.c | 2 | ||||
-rw-r--r-- | src/hw/floppy.c | 2 | ||||
-rw-r--r-- | src/hw/lsi-scsi.c | 2 | ||||
-rw-r--r-- | src/hw/megasas.c | 3 | ||||
-rw-r--r-- | src/hw/pci.c | 213 | ||||
-rw-r--r-- | src/hw/pci.h | 89 | ||||
-rw-r--r-- | src/hw/pcidevice.c | 216 | ||||
-rw-r--r-- | src/hw/pcidevice.h | 77 | ||||
-rw-r--r-- | src/hw/pvscsi.c | 2 | ||||
-rw-r--r-- | src/hw/sdcard.c | 2 | ||||
-rw-r--r-- | src/hw/usb-ehci.c | 2 | ||||
-rw-r--r-- | src/hw/usb-ohci.c | 2 | ||||
-rw-r--r-- | src/hw/usb-uhci.c | 3 | ||||
-rw-r--r-- | src/hw/usb-xhci.c | 2 | ||||
-rw-r--r-- | src/hw/virtio-blk.c | 2 | ||||
-rw-r--r-- | src/hw/virtio-pci.c | 1 | ||||
-rw-r--r-- | src/hw/virtio-scsi.c | 2 | ||||
-rw-r--r-- | src/optionroms.c | 3 | ||||
-rw-r--r-- | src/output.c | 1 | ||||
-rw-r--r-- | src/pcibios.c | 1 | ||||
-rw-r--r-- | src/vgahooks.c | 3 |
32 files changed, 342 insertions, 314 deletions
@@ -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 \ @@ -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 diff --git a/src/fw/acpi.c b/src/fw/acpi.c index b805b44..8bc2ca6 100644 --- a/src/fw/acpi.c +++ b/src/fw/acpi.c @@ -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 diff --git a/src/fw/coreboot.c b/src/fw/coreboot.c index 4fe1292..4957b80 100644 --- a/src/fw/coreboot.c +++ b/src/fw/coreboot.c @@ -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 diff --git a/src/fw/csm.c b/src/fw/csm.c index b01f181..03b4bb8 100644 --- a/src/fw/csm.c +++ b/src/fw/csm.c @@ -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 diff --git a/src/fw/mptable.c b/src/fw/mptable.c index 8e01e00..47385cc 100644 --- a/src/fw/mptable.c +++ b/src/fw/mptable.c @@ -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 diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index 3fae13a..8ed4380 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -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 diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index ead2c1a..0ed5dfb 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -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 diff --git a/src/fw/smm.c b/src/fw/smm.c index 8f042ee..95f6ba7 100644 --- a/src/fw/smm.c +++ b/src/fw/smm.c @@ -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 diff --git a/src/hw/ahci.c b/src/hw/ahci.c index bd21bf6..9310850 100644 --- a/src/hw/ahci.c +++ b/src/hw/ahci.c @@ -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 diff --git a/src/hw/ata.c b/src/hw/ata.c index 12dab96..9a4b435 100644 --- a/src/hw/ata.c +++ b/src/hw/ata.c @@ -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 diff --git a/src/hw/esp-scsi.c b/src/hw/esp-scsi.c index 9abc361..086a032 100644 --- a/src/hw/esp-scsi.c +++ b/src/hw/esp-scsi.c @@ -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 diff --git a/src/hw/floppy.c b/src/hw/floppy.c index a14f7e0..98ed9bb 100644 --- a/src/hw/floppy.c +++ b/src/hw/floppy.c @@ -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 diff --git a/src/hw/lsi-scsi.c b/src/hw/lsi-scsi.c index 5d872a2..564c9f1 100644 --- a/src/hw/lsi-scsi.c +++ b/src/hw/lsi-scsi.c @@ -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 diff --git a/src/hw/megasas.c b/src/hw/megasas.c index 71af3c3..2ee457b 100644 --- a/src/hw/megasas.c +++ b/src/hw/megasas.c @@ -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 diff --git a/src/hw/pci.c b/src/hw/pci.c index dcf240c..506ee56 100644 --- a/src/hw/pci.c +++ b/src/hw/pci.c @@ -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) { diff --git a/src/hw/pci.h b/src/hw/pci.h index 61eb1f3..bf50430 100644 --- a/src/hw/pci.h +++ b/src/hw/pci.h @@ -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 index 0000000..cfebf66 --- /dev/null +++ b/src/hw/pcidevice.c @@ -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 index 0000000..354b549 --- /dev/null +++ b/src/hw/pcidevice.h @@ -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 diff --git a/src/hw/pvscsi.c b/src/hw/pvscsi.c index b1dd03f..e1685b3 100644 --- a/src/hw/pvscsi.c +++ b/src/hw/pvscsi.c @@ -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 diff --git a/src/hw/sdcard.c b/src/hw/sdcard.c index 1524b51..7e0875f 100644 --- a/src/hw/sdcard.c +++ b/src/hw/sdcard.c @@ -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 diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c index 1d1eb57..7eca55b 100644 --- a/src/hw/usb-ehci.c +++ b/src/hw/usb-ehci.c @@ -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 diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c index b586575..90f60e6 100644 --- a/src/hw/usb-ohci.c +++ b/src/hw/usb-ohci.c @@ -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 diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c index ed7c39a..075ed02 100644 --- a/src/hw/usb-uhci.c +++ b/src/hw/usb-uhci.c @@ -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 diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 6c1720d..5e2f071 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -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 diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c index cd0cbe9..2dfd0c3 100644 --- a/src/hw/virtio-blk.c +++ b/src/hw/virtio-blk.c @@ -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 diff --git a/src/hw/virtio-pci.c b/src/hw/virtio-pci.c index 378d901..ce15672 100644 --- a/src/hw/virtio-pci.c +++ b/src/hw/virtio-pci.c @@ -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" diff --git a/src/hw/virtio-scsi.c b/src/hw/virtio-scsi.c index f7f01cd..322d469 100644 --- a/src/hw/virtio-scsi.c +++ b/src/hw/virtio-scsi.c @@ -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 diff --git a/src/optionroms.c b/src/optionroms.c index a389dd9..9897753 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -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 diff --git a/src/output.c b/src/output.c index 9a8a130..ec51f5e 100644 --- a/src/output.c +++ b/src/output.c @@ -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 diff --git a/src/pcibios.c b/src/pcibios.c index 7e5d972..81735e3 100644 --- a/src/pcibios.c +++ b/src/pcibios.c @@ -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 diff --git a/src/vgahooks.c b/src/vgahooks.c index 48efb08..1f14953 100644 --- a/src/vgahooks.c +++ b/src/vgahooks.c @@ -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 |