diff -r ca0759a08057 -r 2b40508f7645 xen/drivers/passthrough/vtd/dmar.c --- a/xen/drivers/passthrough/vtd/dmar.c Fri Jan 22 11:01:18 2010 +0000 +++ b/xen/drivers/passthrough/vtd/dmar.c Mon Jan 25 15:36:32 2010 +0900 @@ -396,8 +396,65 @@ if ( ret ) xfree(dmaru); + else if ( dmaru->include_all ) + acpi_register_drhd_unit(dmaru); else - acpi_register_drhd_unit(dmaru); + { + u8 b, d, f; + int i, invalid_cnt = 0; + + for ( i = 0; i < dmaru->scope.devices_cnt; i++ ) + { + b = PCI_BUS(dmaru->scope.devices[i]); + d = PCI_SLOT(dmaru->scope.devices[i]); + f = PCI_FUNC(dmaru->scope.devices[i]); + + if ( pci_device_detect(b, d, f) == 0 ) + { + dprintk(XENLOG_WARNING VTDPREFIX, + " Non-existent device (%x:%x.%x) is reported " + "in this DRHD's scope!\n", b, d, f); + invalid_cnt++; + } + } + + /* + * If all devices under the scope of the DRHD are non-existent, + * this DRHD is invalid but safely ignorable, so ignore it. + * If some devices under the scope of the DRHD are non-existent, + * this DRHD is invalid, so disable VT-d unless "iommu=force" + * option is specified. + * When "iommu=force" option is specified, even the invalid DRHD + * will be registered, because DRHD that has some existent devices + * must not be ignored due to security reasons. + */ + if ( invalid_cnt ) + { + if ( invalid_cnt == dmaru->scope.devices_cnt ) + { + dprintk(XENLOG_WARNING VTDPREFIX, + " Ignore the DRHD due to all devices under " + "its scope are not PCI discoverable!\n"); + xfree(dmaru); + } + else + { + dprintk(XENLOG_WARNING VTDPREFIX, + " The DRHD is invalid due to some devices under " + "its scope are not PCI discoverable!\n"); + if ( force_iommu ) + acpi_register_drhd_unit(dmaru); + else + { + xfree(dmaru); + ret = -EINVAL; + } + } + } + else + acpi_register_drhd_unit(dmaru); + } + return ret; } @@ -444,7 +501,7 @@ else { u8 b, d, f; - int i, ignore = 0; + int i, invalid_cnt = 0; for ( i = 0; i < rmrru->scope.devices_cnt; i++ ) { @@ -458,24 +515,44 @@ " Non-existent device (%x:%x.%x) is reported " "in RMRR (%"PRIx64", %"PRIx64")'s scope!\n", b, d, f, rmrru->base_address, rmrru->end_address); - ignore = 1; + invalid_cnt++; + } + } + + /* + * If all devices under the scope of the RMRR are non-existent, + * this RMMR is invalid but ignorable, so ignore it. + * If some devices under the scope of the RMRR are non-existent, + * this RMRR is invalid, so disable VT-d unless "iommu=force" + * option is specified. When "iommu=force" option is specified, + * the invalid RMRR is ignored. + */ + if ( invalid_cnt ) + { + if ( invalid_cnt == rmrru->scope.devices_cnt ) + { + dprintk(XENLOG_WARNING VTDPREFIX, + " Ignore the RMRR (%"PRIx64", %"PRIx64") due to " + "devices under its scope are not PCI discoverable!\n", + rmrru->base_address, rmrru->end_address); + xfree(rmrru); + return 0; } else { - ignore = 0; - break; + dprintk(XENLOG_WARNING VTDPREFIX, + " The RMRR (%"PRIx64", %"PRIx64") is invalid due to " + "some devices under its scope are not PCI discoverable!\n", + rmrru->base_address, rmrru->end_address); + if ( !force_iommu ) + { + xfree(rmrru); + return -EINVAL; + } } } - if ( ignore ) - { - dprintk(XENLOG_WARNING VTDPREFIX, - " Ignore the RMRR (%"PRIx64", %"PRIx64") due to " - "devices under its scope are not PCI discoverable!\n", - rmrru->base_address, rmrru->end_address); - xfree(rmrru); - } - else if ( base_addr > end_addr ) + if ( base_addr > end_addr ) { dprintk(XENLOG_WARNING VTDPREFIX, " The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n",