DM: refuse passthrough PCIe without reset support

Check reset method for PCIe dev according to 'reset' in sysfs, which
indicates reset capability, like FLR and secondary bus reset. PCIe dev
without reset capability is refused for passthrough to avoid failure
after UOS reboot.

Signed-off-by: Edwin Zhai <edwin.zhai@intel.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
This commit is contained in:
Edwin Zhai 2018-05-25 12:51:38 +08:00 committed by lijinxia
parent c3793e19ed
commit b19d936356

View File

@ -37,6 +37,7 @@
#include <stdbool.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <sysexits.h>
#include <unistd.h>
@ -102,6 +103,7 @@ struct passthru_dev {
int capoff;
int table_size;
} msix;
bool pcie_cap;
struct pcisel sel;
int phys_pin;
uint16_t phys_bdf;
@ -318,7 +320,7 @@ clear_mmc_mme(uint32_t *val)
#endif
static int
cfginitmsi(struct vmctx *ctx, struct passthru_dev *ptdev)
cfginit_cap(struct vmctx *ctx, struct passthru_dev *ptdev)
{
int i, ptr, capptr, cap, sts, caplen, table_size;
uint32_t u32;
@ -393,7 +395,9 @@ cfginitmsi(struct vmctx *ctx, struct passthru_dev *ptdev)
caplen -= 4;
capptr += 4;
}
}
} else if (cap == PCIY_EXPRESS)
ptdev->pcie_cap = true;
ptr = read_config(phys_dev, ptr + PCICAP_NEXTPTR, 1);
}
}
@ -439,11 +443,7 @@ cfginitmsi(struct vmctx *ctx, struct passthru_dev *ptdev)
vm_set_ptdev_msix_info(ctx, &ptirq);
}
/* Make sure one of the capabilities is present */
if (ptdev->msi.capoff == 0 && ptdev->msix.capoff == 0)
return -1;
else
return 0;
return 0;
}
static uint64_t
@ -809,18 +809,47 @@ cfginit(struct vmctx *ctx, struct passthru_dev *ptdev, int bus,
int slot, int func)
{
int irq_type = IRQ_MSI;
char reset_path[60];
FILE *f;
bzero(&ptdev->sel, sizeof(struct pcisel));
ptdev->sel.bus = bus;
ptdev->sel.dev = slot;
ptdev->sel.func = func;
if (cfginitmsi(ctx, ptdev) != 0) {
if (cfginit_cap(ctx, ptdev) != 0) {
warnx("Capability check fails for PCI %x/%x/%x",
bus, slot, func);
return -1;
}
/* Check MSI or MSIX capabilities */
if (ptdev->msi.capoff == 0 && ptdev->msix.capoff == 0) {
warnx("MSI not supported for PCI %x/%x/%x",
bus, slot, func);
irq_type = IRQ_INTX;
}
/* Check reset method for PCIe dev. If SOS kernel provides 'reset'
* entry in sysfs, related dev has some reset capability, e.g. FLR, or
* secondary bus reset. PCIe dev without any reset capability is
* refused for passthrough.
*/
if (ptdev->pcie_cap) {
snprintf(reset_path, 40,
"/sys/bus/pci/devices/0000:%02x:%02x.%x/reset",
bus, slot, func);
if ((f = fopen(reset_path, "r")))
fclose(f);
else if (errno == ENOENT) {
warnx("No reset capability for PCIe %x/%x/%x, "
"remove it from ptdev list!!\n",
bus, slot, func);
return -1;
}
}
if (cfginitbar(ctx, ptdev) != 0) {
warnx("failed to initialize BARs for PCI %x/%x/%x",
bus, slot, func);