diff options
Diffstat (limited to 'drivers/pci/controller/vmd.c')
| -rw-r--r-- | drivers/pci/controller/vmd.c | 47 | 
1 files changed, 41 insertions, 6 deletions
| diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 9a64cf90c291..f69ef8c89f72 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -40,13 +40,19 @@ enum vmd_features {  	 * membars, in order to allow proper address translation during  	 * resource assignment to enable guest virtualization  	 */ -	VMD_FEAT_HAS_MEMBAR_SHADOW	= (1 << 0), +	VMD_FEAT_HAS_MEMBAR_SHADOW		= (1 << 0),  	/*  	 * Device may provide root port configuration information which limits  	 * bus numbering  	 */ -	VMD_FEAT_HAS_BUS_RESTRICTIONS	= (1 << 1), +	VMD_FEAT_HAS_BUS_RESTRICTIONS		= (1 << 1), + +	/* +	 * Device contains physical location shadow registers in +	 * vendor-specific capability space +	 */ +	VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP	= (1 << 2),  };  /* @@ -454,6 +460,28 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)  		}  	} +	if (features & VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP) { +		int pos = pci_find_capability(vmd->dev, PCI_CAP_ID_VNDR); +		u32 reg, regu; + +		pci_read_config_dword(vmd->dev, pos + 4, ®); + +		/* "SHDW" */ +		if (pos && reg == 0x53484457) { +			pci_read_config_dword(vmd->dev, pos + 8, ®); +			pci_read_config_dword(vmd->dev, pos + 12, ®u); +			offset[0] = vmd->dev->resource[VMD_MEMBAR1].start - +					(((u64) regu << 32 | reg) & +					 PCI_BASE_ADDRESS_MEM_MASK); + +			pci_read_config_dword(vmd->dev, pos + 16, ®); +			pci_read_config_dword(vmd->dev, pos + 20, ®u); +			offset[1] = vmd->dev->resource[VMD_MEMBAR2].start - +					(((u64) regu << 32 | reg) & +					 PCI_BASE_ADDRESS_MEM_MASK); +		} +	} +  	/*  	 * Certain VMD devices may have a root port configuration option which  	 * limits the bus range to between 0-127, 128-255, or 224-255 @@ -560,6 +588,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)  	if (!vmd->bus) {  		pci_free_resource_list(&resources);  		irq_domain_remove(vmd->irq_domain); +		irq_domain_free_fwnode(fn);  		return -ENODEV;  	} @@ -673,6 +702,7 @@ static void vmd_cleanup_srcu(struct vmd_dev *vmd)  static void vmd_remove(struct pci_dev *dev)  {  	struct vmd_dev *vmd = pci_get_drvdata(dev); +	struct fwnode_handle *fn = vmd->irq_domain->fwnode;  	sysfs_remove_link(&vmd->dev->dev.kobj, "domain");  	pci_stop_root_bus(vmd->bus); @@ -680,6 +710,7 @@ static void vmd_remove(struct pci_dev *dev)  	vmd_cleanup_srcu(vmd);  	vmd_detach_resources(vmd);  	irq_domain_remove(vmd->irq_domain); +	irq_domain_free_fwnode(fn);  }  #ifdef CONFIG_PM_SLEEP @@ -717,16 +748,20 @@ static int vmd_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(vmd_dev_pm_ops, vmd_suspend, vmd_resume);  static const struct pci_device_id vmd_ids[] = { -	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D),}, +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_201D), +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP,},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),  		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |  				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f), -		.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,}, +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d), -		.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,}, +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B), -		.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,}, +		.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP | +				VMD_FEAT_HAS_BUS_RESTRICTIONS,},  	{0,}  };  MODULE_DEVICE_TABLE(pci, vmd_ids); |