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>
This commit is contained in:
Kevin O'Connor 2016-02-03 01:28:20 -05:00
parent 62ff9d5f64
commit 4d8510cdcc
32 changed files with 342 additions and 314 deletions

View File

@ -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 \

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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)
{

View 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

216
src/hw/pcidevice.c Normal file
View File

@ -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;
}

77
src/hw/pcidevice.h Normal file
View File

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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"

View 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

View 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

View 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

View 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

View 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