From da16d2be8cdf1e788ca90fc0d7bf4602136c3358 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Mon, 18 Sep 2017 15:04:23 +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 --- Cc: Jan Beulich --- Changes since v5: - Introduce a flags field for pci_size_mem_bar. Changes since v4: - Restore printing whether the BAR is from a vf. - Make the psize pointer parameter not optional. - s/u64/uint64_t. - Remove some unneeded parentheses. - Assert the return value is never 0. - Use the newly introduced pci_sbdf_t type. Changes since v3: - Rename function to size BARs to pci_size_mem_bar. - Change the parameters passed to the function. Pass the position and whether the BAR is the last one, instead of the (base, max_bars, *index) tuple. - Make the function return the number of BARs consumed (1 for 32b, 2 for 64b BARs). - Change the dprintk back to printk. - Do not log another error message in pci_add_device in case pci_size_mem_bar fails. --- xen/drivers/passthrough/pci.c | 98 +++++++++++++++++++++++------------ xen/include/xen/pci.h | 4 ++ 2 files changed, 68 insertions(+), 34 deletions(-) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 975485fe05..ba58b4d0cc 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); +int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int pos, bool last, + 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 addr, size; + bool vf = flags & PCI_BAR_VF; + + 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 ( last ) + { + printk(XENLOG_WARNING + "%sdevice %04x:%02x:%02x.%u with 64-bit %sBAR in last slot\n", + vf ? "SR-IOV " : "", sbdf.seg, sbdf.bus, sbdf.dev, sbdf.func, + vf ? "vf " : ""); + return -EINVAL; + } + 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; + addr = (bar & PCI_BASE_ADDRESS_MEM_MASK) | ((uint64_t)hi << 32); + + if ( paddr ) + *paddr = addr; + *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) { @@ -674,11 +724,16 @@ 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 = { + .seg = seg, + .bus = bus, + .dev = slot, + .func = func, + }; if ( (bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO ) @@ -689,38 +744,13 @@ 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, i == PCI_SRIOV_NUM_BARS - 1, + NULL, &pdev->vf_rlen[i], PCI_BAR_VF); + if ( ret < 0 ) + break; + + ASSERT(ret); + i += ret; } } else diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index b7a6abfc53..2bee6a3247 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -189,6 +189,10 @@ 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 0 +#define PCI_BAR_VF (1u << _PCI_BAR_VF) +int pci_size_mem_bar(pci_sbdf_t sbdf, unsigned int pos, bool last, + uint64_t *addr, uint64_t *size, unsigned int flags); bool_t pcie_aer_get_firmware_first(const struct pci_dev *); -- 2.39.5