From a1a6d59862f4b40a30aebba7ef49509b8ed91a7d Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Thu, 22 Mar 2018 14:59:00 +0100 Subject: [PATCH] pci: split code to size BARs from pci_add_device MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit So that it can be called from outside in order to get the size of regular PCI BARs. This will be required in order to map the BARs from PCI devices into PVH Dom0 p2m. Signed-off-by: Roger Pau Monné Reviewed-by: Jan Beulich --- xen/drivers/passthrough/pci.c | 94 ++++++++++++++++++++++------------- xen/include/xen/pci.h | 5 ++ 2 files changed, 65 insertions(+), 34 deletions(-) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index e65c7faa6f..c0846e8ebb 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -603,6 +603,56 @@ static int iommu_add_device(struct pci_dev *pdev); static int iommu_enable_device(struct pci_dev *pdev); static int iommu_remove_device(struct pci_dev *pdev); +unsigned int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int pos, + uint64_t *paddr, uint64_t *psize, + unsigned int flags) +{ + uint32_t hi = 0, bar = pci_conf_read32(sbdf.seg, sbdf.bus, sbdf.dev, + sbdf.func, pos); + uint64_t size; + + ASSERT((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY); + pci_conf_write32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos, ~0); + if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64 ) + { + if ( flags & PCI_BAR_LAST ) + { + printk(XENLOG_WARNING + "%sdevice %04x:%02x:%02x.%u with 64-bit %sBAR in last slot\n", + (flags & PCI_BAR_VF) ? "SR-IOV " : "", sbdf.seg, sbdf.bus, + sbdf.dev, sbdf.func, (flags & PCI_BAR_VF) ? "vf " : ""); + *psize = 0; + return 1; + } + hi = pci_conf_read32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos + 4); + pci_conf_write32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos + 4, ~0); + } + size = pci_conf_read32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos) & + PCI_BASE_ADDRESS_MEM_MASK; + if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64 ) + { + size |= (uint64_t)pci_conf_read32(sbdf.seg, sbdf.bus, sbdf.dev, + sbdf.func, pos + 4) << 32; + pci_conf_write32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos + 4, hi); + } + else if ( size ) + size |= (uint64_t)~0 << 32; + pci_conf_write32(sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, pos, bar); + size = -size; + + if ( paddr ) + *paddr = (bar & PCI_BASE_ADDRESS_MEM_MASK) | ((uint64_t)hi << 32); + *psize = size; + + if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64 ) + return 2; + + return 1; +} + int pci_add_device(u16 seg, u8 bus, u8 devfn, const struct pci_dev_info *info, nodeid_t node) { @@ -672,11 +722,13 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, unsigned int i; BUILD_BUG_ON(ARRAY_SIZE(pdev->vf_rlen) != PCI_SRIOV_NUM_BARS); - for ( i = 0; i < PCI_SRIOV_NUM_BARS; ++i ) + for ( i = 0; i < PCI_SRIOV_NUM_BARS; ) { unsigned int idx = pos + PCI_SRIOV_BAR + i * 4; u32 bar = pci_conf_read32(seg, bus, slot, func, idx); - u32 hi = 0; + pci_sbdf_t sbdf = { + .sbdf = PCI_SBDF3(seg, bus, devfn), + }; if ( (bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO ) @@ -687,38 +739,12 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, seg, bus, slot, func, i); continue; } - pci_conf_write32(seg, bus, slot, func, idx, ~0); - if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64 ) - { - if ( i >= PCI_SRIOV_NUM_BARS ) - { - printk(XENLOG_WARNING - "SR-IOV device %04x:%02x:%02x.%u with 64-bit" - " vf BAR in last slot\n", - seg, bus, slot, func); - break; - } - hi = pci_conf_read32(seg, bus, slot, func, idx + 4); - pci_conf_write32(seg, bus, slot, func, idx + 4, ~0); - } - pdev->vf_rlen[i] = pci_conf_read32(seg, bus, slot, func, idx) & - PCI_BASE_ADDRESS_MEM_MASK; - if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64 ) - { - pdev->vf_rlen[i] |= (u64)pci_conf_read32(seg, bus, - slot, func, - idx + 4) << 32; - pci_conf_write32(seg, bus, slot, func, idx + 4, hi); - } - else if ( pdev->vf_rlen[i] ) - pdev->vf_rlen[i] |= (u64)~0 << 32; - pci_conf_write32(seg, bus, slot, func, idx, bar); - pdev->vf_rlen[i] = -pdev->vf_rlen[i]; - if ( (bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64 ) - ++i; + ret = pci_size_mem_bar(sbdf, idx, NULL, &pdev->vf_rlen[i], + PCI_BAR_VF | + ((i == PCI_SRIOV_NUM_BARS - 1) ? + PCI_BAR_LAST : 0)); + ASSERT(ret); + i += ret; } } else diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index b7a6abfc53..2f171a8dcc 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -189,6 +189,11 @@ const char *parse_pci(const char *, unsigned int *seg, unsigned int *bus, const char *parse_pci_seg(const char *, unsigned int *seg, unsigned int *bus, unsigned int *dev, unsigned int *func, bool *def_seg); +#define PCI_BAR_VF (1u << 0) +#define PCI_BAR_LAST (1u << 1) +unsigned int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int pos, + uint64_t *paddr, uint64_t *psize, + unsigned int flags); bool_t pcie_aer_get_firmware_first(const struct pci_dev *); -- 2.30.2