diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 9b81b941c8..84d0d2fbab 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -1465,10 +1465,9 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) pdev->fault.count = 0; - if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag)) ) - goto done; + rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag); - for ( ; pdev->phantom_stride; rc = 0 ) + while ( pdev->phantom_stride && !rc ) { devfn += pdev->phantom_stride; if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) ) @@ -1478,8 +1477,22 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag) done: if ( rc ) - printk(XENLOG_G_WARNING "%pd: assign (%pp) failed (%d)\n", - d, &PCI_SBDF3(seg, bus, devfn), rc); + { + printk(XENLOG_G_WARNING "%pd: assign %s(%pp) failed (%d)\n", + d, devfn != pdev->devfn ? "phantom function " : "", + &PCI_SBDF3(seg, bus, devfn), rc); + + if ( devfn != pdev->devfn && + deassign_device(d, seg, bus, pdev->devfn) && + !is_hardware_domain(d) && d != dom_io ) + /* + * Device with phantom functions that failed to both assign and + * rollback. Crash the target domain, as the state of the + * functions at this point is unknown and Xen has no way to assert + * consistent context assignment among them. + */ + domain_crash(d); + } /* The device is assigned to dom_io so mark it as quarantined */ else if ( d == dom_io ) pdev->quarantine = true;