aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-01-21 09:12:01 +0000
committerKeir Fraser <keir.fraser@citrix.com>2010-01-21 09:12:01 +0000
commit3a007e1577a578f525f4c2b895cf098e9c72509a (patch)
tree52afb9e6d2629ffe94f4e68d8d1287443167a590
parent1ac4cf5651e58f177621450342a943ee5457cf0a (diff)
downloadxen-3a007e1577a578f525f4c2b895cf098e9c72509a.tar.gz
xen-3a007e1577a578f525f4c2b895cf098e9c72509a.tar.bz2
xen-3a007e1577a578f525f4c2b895cf098e9c72509a.zip
VT-d: improve RMRR validity checking
Currently, Xen checks RMRR range and disables VT-d if RMRR range is set incorrectly in BIOS rigorously. But, actually we can ignore the RMRR if the device under its scope are not pci discoverable, because the RMRR won't be used by non-existed or disabled devices. This patch ignores the RMRR if the device under its scope are not pci discoverable, and only checks the validity of RMRRs that are actually used. In order to avoid duplicate pci device detection code, this patch defines a function pci_device_detect for it. Signed-off-by: Weidong Han <weidong.han@intel.com>
-rw-r--r--xen/drivers/passthrough/pci.c21
-rw-r--r--xen/drivers/passthrough/vtd/dmar.c56
-rw-r--r--xen/include/xen/pci.h1
3 files changed, 61 insertions, 17 deletions
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 75de82a90d..bc6974c122 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -362,6 +362,21 @@ out:
}
/*
+ * detect pci device, return 0 if it exists, or return 0
+ */
+int pci_device_detect(u8 bus, u8 dev, u8 func)
+{
+ u32 vendor;
+
+ vendor = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
+ /* some broken boards return 0 or ~0 if a slot is empty: */
+ if ( (vendor == 0xffffffff) || (vendor == 0x00000000) ||
+ (vendor == 0x0000ffff) || (vendor == 0xffff0000) )
+ return 0;
+ return 1;
+}
+
+/*
* scan pci devices to add all existed PCI devices to alldevs_list,
* and setup pci hierarchy in array bus2bridge. This function is only
* called in VT-d hardware setup
@@ -372,7 +387,6 @@ int __init scan_pci_devices(void)
int bus, dev, func;
u8 sec_bus, sub_bus;
int type;
- u32 l;
spin_lock(&pcidevs_lock);
for ( bus = 0; bus < 256; bus++ )
@@ -381,10 +395,7 @@ int __init scan_pci_devices(void)
{
for ( func = 0; func < 8; func++ )
{
- l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);
- /* some broken boards return 0 or ~0 if a slot is empty: */
- if ( (l == 0xffffffff) || (l == 0x00000000) ||
- (l == 0x0000ffff) || (l == 0xffff0000) )
+ if ( pci_device_detect(bus, dev, func) == 0 )
continue;
pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));
diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c
index 3ead126b79..971100fe3e 100644
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -410,14 +410,6 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
u64 base_addr = rmrr->base_address, end_addr = rmrr->end_address;
int ret = 0;
- if ( base_addr >= end_addr )
- {
- dprintk(XENLOG_ERR VTDPREFIX,
- "RMRR error: base_addr %"PRIx64" end_address %"PRIx64"\n",
- base_addr, end_addr);
- return -EFAULT;
- }
-
#ifdef CONFIG_X86
/* This check is here simply to detect when RMRR values are
* not properly represented in the system memory map and
@@ -441,9 +433,6 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
rmrru->base_address = base_addr;
rmrru->end_address = end_addr;
- dprintk(XENLOG_INFO VTDPREFIX,
- " RMRR region: base_addr %"PRIx64" end_address %"PRIx64"\n",
- rmrru->base_address, rmrru->end_address);
dev_scope_start = (void *)(rmrr + 1);
dev_scope_end = ((void *)rmrr) + header->length;
@@ -453,7 +442,50 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
if ( ret || (rmrru->scope.devices_cnt == 0) )
xfree(rmrru);
else
- acpi_register_rmrr_unit(rmrru);
+ {
+ u8 b, d, f;
+ int i, ignore = 0;
+
+ for ( i = 0; i < rmrru->scope.devices_cnt; i++ )
+ {
+ b = PCI_BUS(rmrru->scope.devices[i]);
+ d = PCI_SLOT(rmrru->scope.devices[i]);
+ f = PCI_FUNC(rmrru->scope.devices[i]);
+
+ if ( pci_device_detect(b, d, f) == 0 )
+ ignore = 1;
+ else
+ {
+ ignore = 0;
+ break;
+ }
+ }
+
+ 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 )
+ {
+ dprintk(XENLOG_WARNING VTDPREFIX,
+ " The RMRR (%"PRIx64", %"PRIx64") is incorrect!\n",
+ rmrru->base_address, rmrru->end_address);
+ xfree(rmrru);
+ ret = -EFAULT;
+ }
+ else
+ {
+ dprintk(XENLOG_INFO VTDPREFIX,
+ " RMRR region: base_addr %"PRIx64" end_address %"PRIx64"\n",
+ rmrru->base_address, rmrru->end_address);
+ acpi_register_rmrr_unit(rmrru);
+ }
+ }
+
return ret;
}
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 1740698cc6..2f2014fd64 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -74,6 +74,7 @@ enum {
DEV_TYPE_PCI,
};
+int pci_device_detect(u8 bus, u8 dev, u8 func);
int scan_pci_devices(void);
int pdev_type(u8 bus, u8 devfn);
int find_upstream_bridge(u8 *bus, u8 *devfn, u8 *secbus);