PCI: Add device-specific PCI ACS enable
Some devices support PCI ACS-like features, but don't report it using the standard PCIe capabilities. We already provide hooks for device-specific testing of ACS, but not for device-specific enabling of ACS. This provides that setup hook. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
		
							parent
							
								
									38dbfb59d1
								
							
						
					
					
						commit
						2c74424470
					
				| @ -2180,21 +2180,18 @@ void pci_request_acs(void) | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * pci_enable_acs - enable ACS if hardware support it | ||||
|  * pci_std_enable_acs - enable ACS on devices using standard ACS capabilites | ||||
|  * @dev: the PCI device | ||||
|  */ | ||||
| void pci_enable_acs(struct pci_dev *dev) | ||||
| static int pci_std_enable_acs(struct pci_dev *dev) | ||||
| { | ||||
| 	int pos; | ||||
| 	u16 cap; | ||||
| 	u16 ctrl; | ||||
| 
 | ||||
| 	if (!pci_acs_enable) | ||||
| 		return; | ||||
| 
 | ||||
| 	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS); | ||||
| 	if (!pos) | ||||
| 		return; | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap); | ||||
| 	pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl); | ||||
| @ -2212,6 +2209,23 @@ void pci_enable_acs(struct pci_dev *dev) | ||||
| 	ctrl |= (cap & PCI_ACS_UF); | ||||
| 
 | ||||
| 	pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * pci_enable_acs - enable ACS if hardware support it | ||||
|  * @dev: the PCI device | ||||
|  */ | ||||
| void pci_enable_acs(struct pci_dev *dev) | ||||
| { | ||||
| 	if (!pci_acs_enable) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!pci_std_enable_acs(dev)) | ||||
| 		return; | ||||
| 
 | ||||
| 	pci_dev_specific_enable_acs(dev); | ||||
| } | ||||
| 
 | ||||
| static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) | ||||
|  | ||||
| @ -3461,3 +3461,28 @@ int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags) | ||||
| 
 | ||||
| 	return -ENOTTY; | ||||
| } | ||||
| 
 | ||||
| static const struct pci_dev_enable_acs { | ||||
| 	u16 vendor; | ||||
| 	u16 device; | ||||
| 	int (*enable_acs)(struct pci_dev *dev); | ||||
| } pci_dev_enable_acs[] = { | ||||
| 	{ 0 } | ||||
| }; | ||||
| 
 | ||||
| void pci_dev_specific_enable_acs(struct pci_dev *dev) | ||||
| { | ||||
| 	const struct pci_dev_enable_acs *i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	for (i = pci_dev_enable_acs; i->enable_acs; i++) { | ||||
| 		if ((i->vendor == dev->vendor || | ||||
| 		     i->vendor == (u16)PCI_ANY_ID) && | ||||
| 		    (i->device == dev->device || | ||||
| 		     i->device == (u16)PCI_ANY_ID)) { | ||||
| 			ret = i->enable_acs(dev); | ||||
| 			if (ret >= 0) | ||||
| 				return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1510,6 +1510,7 @@ enum pci_fixup_pass { | ||||
| void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); | ||||
| struct pci_dev *pci_get_dma_source(struct pci_dev *dev); | ||||
| int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); | ||||
| void pci_dev_specific_enable_acs(struct pci_dev *dev); | ||||
| #else | ||||
| static inline void pci_fixup_device(enum pci_fixup_pass pass, | ||||
| 				    struct pci_dev *dev) { } | ||||
| @ -1522,6 +1523,7 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, | ||||
| { | ||||
| 	return -ENOTTY; | ||||
| } | ||||
| static inline void pci_dev_specific_enable_acs(struct pci_dev *dev) { } | ||||
| #endif | ||||
| 
 | ||||
| void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user