pci_find_dev() is not sufficient for further tests for Intel IOMMU. This patch introduced pci_dev struct, as a abstract of a specific PCI device. All the rest of current PCI APIs are changed to leverage the pci_dev struct. x86/vmexit.c is the only user of the old PCI APIs. Changing it to use the new ones. (Indentation is fixed from using 4 spaces into tab in pci.c) Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> --- lib/pci.c | 75 +++++++++++++++++++++++++++++++++++++++++------------------- lib/pci.h | 29 ++++++++++++++++++----- x86/vmexit.c | 22 ++++-------------- 3 files changed, 80 insertions(+), 46 deletions(-) diff --git a/lib/pci.c b/lib/pci.c index 0058d70..ef0b02a 100644 --- a/lib/pci.c +++ b/lib/pci.c @@ -7,37 +7,66 @@ #include "pci.h" #include "asm/pci.h" -/* 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) +/* + * Scan bus look for a specific device. Only bus 0 scanned for now. + * After the scan, a pci_dev is returned with correct BAR information. + */ +int pci_dev_init(pci_dev *dev, uint16_t vendor_id, uint16_t device_id) +{ + unsigned i; + uint32_t id; + + memset(dev, 0, sizeof(*dev)); + + for (i = 0; i < PCI_DEVFN_MAX; ++i) { + id = pci_config_read(i, 0); + if ((id & 0xFFFF) == vendor_id && (id >> 16) == device_id) + break; + } + + if (i == PCI_DEVFN_MAX) { + printf("PCI: failed init dev (vendor: 0x%04x, " + "device: 0x%04x)\n", vendor_id, device_id); + return -1; + } + + dev->pci_addr = i; + for (i = 0; i < PCI_BAR_NUM; i++) { + if (!pci_bar_is_valid(dev, i)) + continue; + dev->pci_bar[i] = pci_bar_addr(dev, i); + printf("PCI: init dev 0x%04x BAR %d [%s] addr 0x%lx\n", + dev->pci_addr, i, pci_bar_is_memory(dev, i) ? + "MEM" : "IO", dev->pci_bar[i]); + } + dev->inited = true; + + return 0; +} + +static inline uint32_t pci_config_read_bar(pci_dev *dev, int n) { - 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; + return pci_config_read(dev->pci_addr, + PCI_BASE_ADDRESS_0 + n * 4); } -unsigned long pci_bar_addr(pcidevaddr_t dev, int bar_num) +phys_addr_t pci_bar_addr(pci_dev *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; - } + uint32_t bar = pci_config_read_bar(dev, bar_num); + 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) +bool pci_bar_is_memory(pci_dev *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); + uint32_t bar = pci_config_read_bar(dev, bar_num); + return !(bar & PCI_BASE_ADDRESS_SPACE_IO); } -bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num) +bool pci_bar_is_valid(pci_dev *dev, int bar_num) { - uint32_t bar = pci_config_read(dev, PCI_BASE_ADDRESS_0 + bar_num * 4); - return bar; + return pci_config_read_bar(dev, bar_num); } diff --git a/lib/pci.h b/lib/pci.h index 9160cfb..b8755ff 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -14,10 +14,21 @@ typedef uint16_t pcidevaddr_t; enum { PCIDEVADDR_INVALID = 0xffff, }; -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); + +#define PCI_BAR_NUM (6) +#define PCI_DEVFN_MAX (256) + +struct pci_dev { + bool inited; + uint16_t pci_addr; + phys_addr_t pci_bar[PCI_BAR_NUM]; +}; +typedef struct pci_dev pci_dev; + +int pci_dev_init(pci_dev *dev, uint16_t vendor_id, uint16_t device_id); +phys_addr_t pci_bar_addr(pci_dev *dev, int bar_num); +bool pci_bar_is_memory(pci_dev *dev, int bar_num); +bool pci_bar_is_valid(pci_dev *dev, int bar_num); /* * pci-testdev is a driver for the pci-testdev qemu pci device. The @@ -27,8 +38,6 @@ bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num); #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_TEST 0x0005 -#define PCI_TESTDEV_NUM_BARS 2 - struct pci_test_dev_hdr { uint8_t test; uint8_t width; @@ -39,4 +48,12 @@ struct pci_test_dev_hdr { uint8_t name[]; }; +enum pci_dma_dir { + PCI_DMA_FROM_DEVICE = 0, + PCI_DMA_TO_DEVICE, +}; +typedef enum pci_dma_dir pci_dma_dir_t; + +typedef uint64_t iova_t; + #endif /* PCI_H */ diff --git a/x86/vmexit.c b/x86/vmexit.c index c2e1e49..908d2dc 100644 --- a/x86/vmexit.c +++ b/x86/vmexit.c @@ -371,8 +371,7 @@ int main(int ac, char **av) { struct fadt_descriptor_rev1 *fadt; int i; - unsigned long membar = 0; - pcidevaddr_t pcidev; + pci_dev dev; smp_init(); setup_vm(); @@ -385,21 +384,10 @@ int main(int ac, char **av) pm_tmr_blk = fadt->pm_tmr_blk; printf("PM timer port is %x\n", pm_tmr_blk); - pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); - if (pcidev != PCIDEVADDR_INVALID) { - for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) { - if (!pci_bar_is_valid(pcidev, i)) { - continue; - } - if (pci_bar_is_memory(pcidev, i)) { - membar = pci_bar_addr(pcidev, i); - pci_test.memaddr = ioremap(membar, PAGE_SIZE); - } else { - pci_test.iobar = pci_bar_addr(pcidev, i); - } - } - printf("pci-testdev at 0x%x membar %lx iobar %x\n", - pcidev, membar, pci_test.iobar); + if (!pci_dev_init(&dev, PCI_VENDOR_ID_REDHAT, + PCI_DEVICE_ID_REDHAT_TEST)) { + pci_test.memaddr = ioremap(dev.pci_bar[0], PAGE_SIZE); + pci_test.iobar = dev.pci_bar[1]; } for (i = 0; i < ARRAY_SIZE(tests); ++i) -- 2.7.4 -- 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