Add API to scan bus for a given device, as well as API to access BAR registers. Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- config-x86-common.mak | 1 + lib/x86/pci.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/x86/pci.h | 16 +++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 lib/x86/pci.c create mode 100644 lib/x86/pci.h diff --git a/config-x86-common.mak b/config-x86-common.mak index 1f0f1ba..455032b 100644 --- a/config-x86-common.mak +++ b/config-x86-common.mak @@ -14,6 +14,7 @@ cflatobjs += lib/x86/apic.o cflatobjs += lib/x86/atomic.o cflatobjs += lib/x86/desc.o cflatobjs += lib/x86/isr.o +cflatobjs += lib/x86/pci.o $(libcflat): LDFLAGS += -nostdlib $(libcflat): CFLAGS += -ffreestanding -I lib diff --git a/lib/x86/pci.c b/lib/x86/pci.c new file mode 100644 index 0000000..f95cd88 --- /dev/null +++ b/lib/x86/pci.c @@ -0,0 +1,55 @@ +#include <linux/pci_regs.h> +#include "pci.h" + +static void outl(unsigned short port, unsigned val) +{ + asm volatile("outl %d0, %w1" : : "a"(val), "Nd"(port)); +} + +static unsigned inl(unsigned short port) +{ + unsigned data; + asm volatile("inl %w1, %d0" : "=a"(data) : "Nd"(port)); + return data; +} +static uint32_t pci_config_read(pcidevaddr_t dev, uint8_t reg) +{ + uint32_t index = reg | (dev << 8) | (0x1 << 31); + outl(0xCF8, index); + return inl(0xCFC); +} + +/* Scan bus look for a specific device. Only bus 0 scanned for now. */ +pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id) +{ + unsigned dev; + for (dev = 0; dev < 256; ++dev) { + uint32_t id = pci_config_read(dev, 0); + if ((id & 0xFFFF) == vendor_id && (id >> 16) == device_id) { + return dev; + } + } + return PCIDEVADDR_INVALID; +} + +unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num) +{ + uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4); + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + return bar & PCI_BASE_ADDRESS_IO_MASK; + } else { + return bar & PCI_BASE_ADDRESS_MEM_MASK; + } +} + +bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num) +{ + uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4); + return !(bar & PCI_BASE_ADDRESS_SPACE_IO); +} + +bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num) +{ + uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4); + return bar; +} diff --git a/lib/x86/pci.h b/lib/x86/pci.h new file mode 100644 index 0000000..0f69ef0 --- /dev/null +++ b/lib/x86/pci.h @@ -0,0 +1,16 @@ +#ifndef PCI_H +#define PCI_H + +#include <inttypes.h> +#include "libcflat.h" + +typedef uint16_t pcidevaddr_t; +enum { + PCIDEVADDR_INVALID = 0x0 +}; +pcidevaddr_t pci_find_dev(uint16_t vendor_id, uint16_t device_id); +unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num); +bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num); +bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num); + +#endif -- MST -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html