diff options
Diffstat (limited to 'drivers/pci/controller/vmd.c')
| -rw-r--r-- | drivers/pci/controller/vmd.c | 27 | 
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index e06e9f4fc50f..769eedeb8802 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -719,6 +719,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)  	resource_size_t offset[2] = {0};  	resource_size_t membar2_offset = 0x2000;  	struct pci_bus *child; +	struct pci_dev *dev;  	int ret;  	/* @@ -859,8 +860,25 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)  	pci_scan_child_bus(vmd->bus);  	vmd_domain_reset(vmd); -	list_for_each_entry(child, &vmd->bus->children, node) -		pci_reset_bus(child->self); + +	/* When Intel VMD is enabled, the OS does not discover the Root Ports +	 * owned by Intel VMD within the MMCFG space. pci_reset_bus() applies +	 * a reset to the parent of the PCI device supplied as argument. This +	 * is why we pass a child device, so the reset can be triggered at +	 * the Intel bridge level and propagated to all the children in the +	 * hierarchy. +	 */ +	list_for_each_entry(child, &vmd->bus->children, node) { +		if (!list_empty(&child->devices)) { +			dev = list_first_entry(&child->devices, +					       struct pci_dev, bus_list); +			if (pci_reset_bus(dev)) +				pci_warn(dev, "can't reset device: %d\n", ret); + +			break; +		} +	} +  	pci_assign_unassigned_bus_resources(vmd->bus);  	/* @@ -980,6 +998,11 @@ static int vmd_resume(struct device *dev)  	struct vmd_dev *vmd = pci_get_drvdata(pdev);  	int err, i; +       if (vmd->irq_domain) +               vmd_set_msi_remapping(vmd, true); +       else +               vmd_set_msi_remapping(vmd, false); +  	for (i = 0; i < vmd->msix_count; i++) {  		err = devm_request_irq(dev, vmd->irqs[i].virq,  				       vmd_irq, IRQF_NO_THREAD,  |