forked from mirrors/linux
		
	PCI/ACPI: Request _OSC control once for each root bridge (v3)
Move the evaluation of acpi_pci_osc_control_set() (to request control of PCI Express native features) into acpi_pci_root_add() to avoid calling it many times for the same root complex with the same arguments. Additionally, check if all of the requisite _OSC support bits are set before calling acpi_pci_osc_control_set() for a given root complex. References: https://bugzilla.kernel.org/show_bug.cgi?id=20232 Reported-by: Ozan Caglayan <ozan@pardus.org.tr> Tested-by: Ozan Caglayan <ozan@pardus.org.tr> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
		
							parent
							
								
									6e8af08dfa
								
							
						
					
					
						commit
						415e12b237
					
				
					 10 changed files with 72 additions and 46 deletions
				
			
		|  | @ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str) | ||||||
| 
 | 
 | ||||||
| __setup("hest_disable", setup_hest_disable); | __setup("hest_disable", setup_hest_disable); | ||||||
| 
 | 
 | ||||||
| static int __init hest_init(void) | void __init acpi_hest_init(void) | ||||||
| { | { | ||||||
| 	acpi_status status; | 	acpi_status status; | ||||||
| 	int rc = -ENODEV; | 	int rc = -ENODEV; | ||||||
| 	unsigned int ghes_count = 0; | 	unsigned int ghes_count = 0; | ||||||
| 
 | 
 | ||||||
| 	if (acpi_disabled) | 	if (acpi_disabled) | ||||||
| 		goto err; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (hest_disable) { | 	if (hest_disable) { | ||||||
| 		pr_info(HEST_PFX "HEST tabling parsing is disabled.\n"); | 		pr_info(HEST_PFX "Table parsing disabled.\n"); | ||||||
| 		goto err; | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	status = acpi_get_table(ACPI_SIG_HEST, 0, | 	status = acpi_get_table(ACPI_SIG_HEST, 0, | ||||||
| 				(struct acpi_table_header **)&hest_tab); | 				(struct acpi_table_header **)&hest_tab); | ||||||
| 	if (status == AE_NOT_FOUND) { | 	if (status == AE_NOT_FOUND) { | ||||||
| 		pr_info(HEST_PFX "Table is not found!\n"); | 		pr_info(HEST_PFX "Table not found.\n"); | ||||||
| 		goto err; | 		goto err; | ||||||
| 	} else if (ACPI_FAILURE(status)) { | 	} else if (ACPI_FAILURE(status)) { | ||||||
| 		const char *msg = acpi_format_exception(status); | 		const char *msg = acpi_format_exception(status); | ||||||
|  | @ -226,15 +226,11 @@ static int __init hest_init(void) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
| 	rc = hest_ghes_dev_register(ghes_count); | 	rc = hest_ghes_dev_register(ghes_count); | ||||||
| 	if (rc) | 	if (!rc) { | ||||||
| 		goto err; | 		pr_info(HEST_PFX "Table parsing has been initialized.\n"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	pr_info(HEST_PFX "HEST table parsing is initialized.\n"); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| err: | err: | ||||||
| 	hest_disable = 1; | 	hest_disable = 1; | ||||||
| 	return rc; |  | ||||||
| } | } | ||||||
| 
 |  | ||||||
| subsys_initcall(hest_init); |  | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <acpi/acpi_bus.h> | #include <acpi/acpi_bus.h> | ||||||
| #include <acpi/acpi_drivers.h> | #include <acpi/acpi_drivers.h> | ||||||
|  | #include <acpi/apei.h> | ||||||
| 
 | 
 | ||||||
| #define PREFIX "ACPI: " | #define PREFIX "ACPI: " | ||||||
| 
 | 
 | ||||||
|  | @ -47,6 +48,11 @@ static int acpi_pci_root_add(struct acpi_device *device); | ||||||
| static int acpi_pci_root_remove(struct acpi_device *device, int type); | static int acpi_pci_root_remove(struct acpi_device *device, int type); | ||||||
| static int acpi_pci_root_start(struct acpi_device *device); | static int acpi_pci_root_start(struct acpi_device *device); | ||||||
| 
 | 
 | ||||||
|  | #define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \ | ||||||
|  | 				| OSC_ACTIVE_STATE_PWR_SUPPORT \ | ||||||
|  | 				| OSC_CLOCK_PWR_CAPABILITY_SUPPORT \ | ||||||
|  | 				| OSC_MSI_SUPPORT) | ||||||
|  | 
 | ||||||
| static const struct acpi_device_id root_device_ids[] = { | static const struct acpi_device_id root_device_ids[] = { | ||||||
| 	{"PNP0A03", 0}, | 	{"PNP0A03", 0}, | ||||||
| 	{"", 0}, | 	{"", 0}, | ||||||
|  | @ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | ||||||
| 	if (flags != base_flags) | 	if (flags != base_flags) | ||||||
| 		acpi_pci_osc_support(root, flags); | 		acpi_pci_osc_support(root, flags); | ||||||
| 
 | 
 | ||||||
|  | 	if (!pcie_ports_disabled | ||||||
|  | 	    && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) { | ||||||
|  | 		flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | ||||||
|  | 			| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | ||||||
|  | 			| OSC_PCI_EXPRESS_PME_CONTROL; | ||||||
|  | 
 | ||||||
|  | 		if (pci_aer_available()) { | ||||||
|  | 			if (aer_acpi_firmware_first()) | ||||||
|  | 				dev_dbg(root->bus->bridge, | ||||||
|  | 					"PCIe errors handled by BIOS.\n"); | ||||||
|  | 			else | ||||||
|  | 				flags |= OSC_PCI_EXPRESS_AER_CONTROL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		dev_info(root->bus->bridge, | ||||||
|  | 			"Requesting ACPI _OSC control (0x%02x)\n", flags); | ||||||
|  | 
 | ||||||
|  | 		status = acpi_pci_osc_control_set(device->handle, &flags, | ||||||
|  | 					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); | ||||||
|  | 		if (ACPI_SUCCESS(status)) | ||||||
|  | 			dev_info(root->bus->bridge, | ||||||
|  | 				"ACPI _OSC control (0x%02x) granted\n", flags); | ||||||
|  | 		else | ||||||
|  | 			dev_dbg(root->bus->bridge, | ||||||
|  | 				"ACPI _OSC request failed (code %d)\n", status); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	pci_acpi_add_bus_pm_notifier(device, root->bus); | 	pci_acpi_add_bus_pm_notifier(device, root->bus); | ||||||
| 	if (device->wakeup.flags.run_wake) | 	if (device->wakeup.flags.run_wake) | ||||||
| 		device_set_run_wake(root->bus->bridge, true); | 		device_set_run_wake(root->bus->bridge, true); | ||||||
|  | @ -603,6 +636,8 @@ static int __init acpi_pci_root_init(void) | ||||||
| 	if (acpi_pci_disabled) | 	if (acpi_pci_disabled) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | 	acpi_hest_init(); | ||||||
|  | 
 | ||||||
| 	pci_acpi_crs_quirks(); | 	pci_acpi_crs_quirks(); | ||||||
| 	if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) | 	if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
|  |  | ||||||
|  | @ -140,14 +140,6 @@ static inline void pci_no_msi(void) { } | ||||||
| static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } | static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_PCIEAER |  | ||||||
| void pci_no_aer(void); |  | ||||||
| bool pci_aer_available(void); |  | ||||||
| #else |  | ||||||
| static inline void pci_no_aer(void) { } |  | ||||||
| static inline bool pci_aer_available(void) { return false; } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| static inline int pci_no_d1d2(struct pci_dev *dev) | static inline int pci_no_d1d2(struct pci_dev *dev) | ||||||
| { | { | ||||||
| 	unsigned int parent_dstates = 0; | 	unsigned int parent_dstates = 0; | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/pci.h> | #include <linux/pci.h> | ||||||
|  | #include <linux/pci-acpi.h> | ||||||
| #include <linux/sched.h> | #include <linux/sched.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
|  |  | ||||||
|  | @ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev) | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_ACPI_APEI | #ifdef CONFIG_ACPI_APEI | ||||||
| extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); | extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); | ||||||
| extern bool aer_acpi_firmware_first(void); |  | ||||||
| #else | #else | ||||||
| static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) | static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) | ||||||
| { | { | ||||||
|  | @ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) | ||||||
| 		return pci_dev->__aer_firmware_first; | 		return pci_dev->__aer_firmware_first; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| static inline bool aer_acpi_firmware_first(void) { return false; } |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev, | static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev, | ||||||
|  |  | ||||||
|  | @ -20,9 +20,6 @@ | ||||||
| 
 | 
 | ||||||
| #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | #define get_descriptor_id(type, service) (((type - 4) << 4) | service) | ||||||
| 
 | 
 | ||||||
| extern bool pcie_ports_disabled; |  | ||||||
| extern bool pcie_ports_auto; |  | ||||||
| 
 |  | ||||||
| extern struct bus_type pcie_port_bus_type; | extern struct bus_type pcie_port_bus_type; | ||||||
| extern int pcie_port_device_register(struct pci_dev *dev); | extern int pcie_port_device_register(struct pci_dev *dev); | ||||||
| #ifdef CONFIG_PM | #ifdef CONFIG_PM | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ | ||||||
|  */ |  */ | ||||||
| int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | ||||||
| { | { | ||||||
| 	acpi_status status; | 	struct acpi_pci_root *root; | ||||||
| 	acpi_handle handle; | 	acpi_handle handle; | ||||||
| 	u32 flags; | 	u32 flags; | ||||||
| 
 | 
 | ||||||
|  | @ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | ||||||
| 	if (!handle) | 	if (!handle) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL | 	root = acpi_pci_find_root(handle); | ||||||
| 		| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | 	if (!root) | ||||||
| 		| OSC_PCI_EXPRESS_PME_CONTROL; |  | ||||||
| 
 |  | ||||||
| 	if (pci_aer_available()) { |  | ||||||
| 		if (aer_acpi_firmware_first()) |  | ||||||
| 			dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); |  | ||||||
| 		else |  | ||||||
| 			flags |= OSC_PCI_EXPRESS_AER_CONTROL; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	status = acpi_pci_osc_control_set(handle, &flags, |  | ||||||
| 					OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); |  | ||||||
| 	if (ACPI_FAILURE(status)) { |  | ||||||
| 		dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", |  | ||||||
| 			status); |  | ||||||
| 		return -ENODEV; | 		return -ENODEV; | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); | 	flags = root->osc_control_set; | ||||||
| 
 | 
 | ||||||
| 	*srv_mask = PCIE_PORT_SERVICE_VC; | 	*srv_mask = PCIE_PORT_SERVICE_VC; | ||||||
| 	if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) | 	if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) | ||||||
|  |  | ||||||
|  | @ -19,6 +19,12 @@ | ||||||
| extern int hest_disable; | extern int hest_disable; | ||||||
| extern int erst_disable; | extern int erst_disable; | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_ACPI_APEI | ||||||
|  | void __init acpi_hest_init(void); | ||||||
|  | #else | ||||||
|  | static inline void acpi_hest_init(void) { return; } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); | typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); | ||||||
| int apei_hest_parse(apei_hest_func_t func, void *data); | int apei_hest_parse(apei_hest_func_t func, void *data); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -40,4 +40,10 @@ static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) | ||||||
| { return NULL; } | { return NULL; } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_ACPI_APEI | ||||||
|  | extern bool aer_acpi_firmware_first(void); | ||||||
|  | #else | ||||||
|  | static inline bool aer_acpi_firmware_first(void) { return false; } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif	/* _PCI_ACPI_H_ */ | #endif	/* _PCI_ACPI_H_ */ | ||||||
|  |  | ||||||
|  | @ -994,6 +994,9 @@ extern void pci_restore_msi_state(struct pci_dev *dev); | ||||||
| extern int pci_msi_enabled(void); | extern int pci_msi_enabled(void); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | extern bool pcie_ports_disabled; | ||||||
|  | extern bool pcie_ports_auto; | ||||||
|  | 
 | ||||||
| #ifndef CONFIG_PCIEASPM | #ifndef CONFIG_PCIEASPM | ||||||
| static inline int pcie_aspm_enabled(void) | static inline int pcie_aspm_enabled(void) | ||||||
| { | { | ||||||
|  | @ -1003,6 +1006,14 @@ static inline int pcie_aspm_enabled(void) | ||||||
| extern int pcie_aspm_enabled(void); | extern int pcie_aspm_enabled(void); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_PCIEAER | ||||||
|  | void pci_no_aer(void); | ||||||
|  | bool pci_aer_available(void); | ||||||
|  | #else | ||||||
|  | static inline void pci_no_aer(void) { } | ||||||
|  | static inline bool pci_aer_available(void) { return false; } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifndef CONFIG_PCIE_ECRC | #ifndef CONFIG_PCIE_ECRC | ||||||
| static inline void pcie_set_ecrc_checking(struct pci_dev *dev) | static inline void pcie_set_ecrc_checking(struct pci_dev *dev) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Rafael J. Wysocki
						Rafael J. Wysocki