Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 415e12b2 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Jesse Barnes
Browse files

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: default avatarOzan Caglayan <ozan@pardus.org.tr>
Tested-by: default avatarOzan Caglayan <ozan@pardus.org.tr>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 6e8af08d
Loading
Loading
Loading
Loading
+9 −13
Original line number Original line Diff line number Diff line
@@ -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);
+35 −0
Original line number Original line Diff line number Diff line
@@ -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;
+0 −8
Original line number Original line Diff line number Diff line
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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>
+0 −3
Original line number Original line Diff line number Diff line
@@ -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,
Loading