aboutsummaryrefslogtreecommitdiffstats
path: root/src/hw
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2016-02-03 01:28:20 -0500
committerKevin O'Connor <kevin@koconnor.net>2016-02-03 10:38:42 -0500
commit4d8510cdcca0a6b160bb8dc3a254ab0baacb10f6 (patch)
tree03e971f2bc93a834a3dd57a304b9a6a17309eba4 /src/hw
parent62ff9d5f649c6ce0d8cbea5d90080afc9870f54a (diff)
downloadseabios-4d8510cdcca0a6b160bb8dc3a254ab0baacb10f6.tar.gz
pci: Split low-level pci code from higher-level 'struct pci_device' code
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>
Diffstat (limited to 'src/hw')
-rw-r--r--src/hw/ahci.c3
-rw-r--r--src/hw/ata.c3
-rw-r--r--src/hw/esp-scsi.c2
-rw-r--r--src/hw/floppy.c2
-rw-r--r--src/hw/lsi-scsi.c2
-rw-r--r--src/hw/megasas.c3
-rw-r--r--src/hw/pci.c213
-rw-r--r--src/hw/pci.h89
-rw-r--r--src/hw/pcidevice.c216
-rw-r--r--src/hw/pcidevice.h77
-rw-r--r--src/hw/pvscsi.c2
-rw-r--r--src/hw/sdcard.c2
-rw-r--r--src/hw/usb-ehci.c2
-rw-r--r--src/hw/usb-ohci.c2
-rw-r--r--src/hw/usb-uhci.c3
-rw-r--r--src/hw/usb-xhci.c2
-rw-r--r--src/hw/virtio-blk.c2
-rw-r--r--src/hw/virtio-pci.c1
-rw-r--r--src/hw/virtio-scsi.c2
19 files changed, 323 insertions, 305 deletions
diff --git a/src/hw/ahci.c b/src/hw/ahci.c
index bd21bf64..9310850b 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 12dab961..9a4b4354 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 9abc361f..086a0328 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 a14f7e09..98ed9bbf 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 5d872a21..564c9f15 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 71af3c30..2ee457b8 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 dcf240cb..506ee563 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 61eb1f38..bf504303 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 00000000..cfebf666
--- /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 00000000..354b5493
--- /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 b1dd03f8..e1685b3c 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 1524b51a..7e0875f6 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 1d1eb574..7eca55bd 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 b5865758..90f60e64 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 ed7c39a4..075ed02c 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 6c1720de..5e2f0718 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 cd0cbe90..2dfd0c34 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 378d9018..ce156722 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 f7f01cda..322d4691 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