mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
PCI/ACPI: Centralize pcie_ports_native checking
If the user booted with "pcie_ports=native", we take control of the PCIe
port services unconditionally, regardless of what _OSC says.
Centralize the testing of pcie_ports_native in acpi_pci_root_create(),
where we interpret the _OSC results, so other places only have to check
host_bridge->native_X and we don't have to sprinkle tests of
pcie_ports_native everywhere.
Rather than overriding the host_bridge->native_X flags after the fact, fold
"pcie_ports=native" into the _OSC control mask we evaluate, i.e., proceed
as though the platform had granted control of the port services. That way
there is a single mechanism deciding each native_X flag, and we can report
exactly which features we are overriding _OSC for instead of just noting
that we are overriding something:
acpi PNP0A08:00: _OSC: OS forcing control ("pcie_ports=native") of [PCIeHotplug PME AER DPC]
Forcing host_bridge->native_aer also restores DPC service binding under
"pcie_ports=native", which regressed in commit 97ca178c89 ("PCI/DPC:
Allow DPC on all Downstream Ports when OS controls AER"). That commit
replaced the AER service test in get_port_device_capability() with
host->native_aer, so DPC stayed off when host_bridge->native_aer was not
set.
This also extends "pcie_ports=native" to host_bridge->native_dpc, which had
no pcie_ports_native fallback before. That effect is narrow. native_dpc
is only consumed by pci_dpc_recovered(), where with CONFIG_PCIE_EDR=n it
previously gave up immediately and now lets pciehp wait for DPC recovery
before treating a Link Down as a hotplug event.
Fold "pcie_ports=dpc-native" into the control mask the same way, so
host_bridge->native_dpc reflects it as well, with the same narrow effect on
pci_dpc_recovered(). Move the pcie_ports_dpc_native declaration to
<linux/pci.h> so acpi_pci_root_create() can test it.
host_bridge->native_ltr is deliberately not forced. "pcie_ports=" controls
PCIe port services and LTR is not one. There is no PCIE_PORT_SERVICE_LTR,
and native_ltr is only used by pci_configure_ltr() to enable ASPM L1.2, so
forcing it would be an ASPM policy decision users did not ask for.
SHPC hotplug is left alone for a simpler reason: SHPC is a conventional PCI
feature rather than a PCIe one, so "pcie_ports=" has no bearing on it.
Fixes: 97ca178c89 ("PCI/DPC: Allow DPC on all Downstream Ports when OS controls AER")
Closes: https://lore.kernel.org/linux-pci/20260901064554.2178688-1-kanie@linux.alibaba.com/
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Guixin Liu <kanie@linux.alibaba.com>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org> # ACPI core
Link: https://patch.msgid.link/20261002211828.1293177-4-sathyanarayanan.kuppuswamy@linux.intel.com
This commit is contained in:
parent
0a1fdf4546
commit
4fe37866b0
|
|
@ -999,6 +999,19 @@ static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
|
|||
flag = 0; \
|
||||
} while (0)
|
||||
|
||||
#define FLAG(x) ((x) ? '+' : '-')
|
||||
|
||||
/*
|
||||
* _OSC control bits for the features implemented by the PCIe port driver,
|
||||
* i.e., the ones "pcie_ports=native" applies to. LTR and SHPC hotplug are
|
||||
* negotiated via _OSC as well, but they are not portdrv services, so
|
||||
* "pcie_ports=" has no bearing on them.
|
||||
*/
|
||||
#define OSC_PCIE_PORT_SERVICE_CONTROLS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
OSC_PCI_EXPRESS_PME_CONTROL | \
|
||||
OSC_PCI_EXPRESS_AER_CONTROL | \
|
||||
OSC_PCI_EXPRESS_DPC_CONTROL)
|
||||
|
||||
struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
|
||||
struct acpi_pci_root_ops *ops,
|
||||
struct acpi_pci_root_info *info,
|
||||
|
|
@ -1009,7 +1022,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
|
|||
int node = acpi_get_node(device->handle);
|
||||
struct pci_bus *bus;
|
||||
struct pci_host_bridge *host_bridge;
|
||||
u32 ctrl, ext_ctrl;
|
||||
u32 ctrl, ext_ctrl, override = 0;
|
||||
|
||||
info->root = root;
|
||||
info->bridge = device;
|
||||
|
|
@ -1039,6 +1052,26 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
|
|||
ctrl = root->osc_control_set;
|
||||
ext_ctrl = root->osc_ext_control_set;
|
||||
|
||||
/*
|
||||
* If the user specified "pcie_ports=native", use the PCIe port
|
||||
* services regardless of what _OSC says, i.e., proceed as though the
|
||||
* platform had granted us control of them. "pcie_ports=dpc-native"
|
||||
* does the same for DPC alone. This may conflict with firmware that
|
||||
* expects to own those features.
|
||||
*/
|
||||
if (pcie_ports_native)
|
||||
override = OSC_PCIE_PORT_SERVICE_CONTROLS & ~ctrl;
|
||||
else if (pcie_ports_dpc_native)
|
||||
override = OSC_PCI_EXPRESS_DPC_CONTROL & ~ctrl;
|
||||
|
||||
if (override) {
|
||||
decode_osc_control(root, pcie_ports_native ?
|
||||
"OS forcing control (\"pcie_ports=native\") of" :
|
||||
"OS forcing control (\"pcie_ports=dpc-native\") of",
|
||||
override);
|
||||
ctrl |= override;
|
||||
}
|
||||
|
||||
OSC_OWNER(ctrl, OSC_PCI_EXPRESS_NATIVE_HP_CONTROL,
|
||||
host_bridge->native_pcie_hotplug);
|
||||
OSC_OWNER(ctrl, OSC_PCI_SHPC_NATIVE_HP_CONTROL,
|
||||
|
|
@ -1051,6 +1084,14 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
|
|||
OSC_OWNER(ext_ctrl, OSC_CXL_ERROR_REPORTING_CONTROL,
|
||||
host_bridge->native_cxl_error);
|
||||
|
||||
dev_info(&root->device->dev, "OS native features: SHPCHotplug%c PCIeHotplug%c PME%c AER%c DPC%c LTR%c\n",
|
||||
FLAG(host_bridge->native_shpc_hotplug),
|
||||
FLAG(host_bridge->native_pcie_hotplug),
|
||||
FLAG(host_bridge->native_pme),
|
||||
FLAG(host_bridge->native_aer),
|
||||
FLAG(host_bridge->native_dpc),
|
||||
FLAG(host_bridge->native_ltr));
|
||||
|
||||
acpi_dev_power_up_children_with_adr(device);
|
||||
|
||||
pci_scan_child_bus(bus);
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ static bool pme_is_native(struct pcie_device *dev)
|
|||
const struct pci_host_bridge *host;
|
||||
|
||||
host = pci_find_host_bridge(dev->port->bus);
|
||||
return pcie_ports_native || host->native_pme;
|
||||
return host->native_pme;
|
||||
}
|
||||
|
||||
static void pciehp_disable_interrupt(struct pcie_device *dev)
|
||||
|
|
|
|||
|
|
@ -812,9 +812,6 @@ bool pciehp_is_native(struct pci_dev *bridge)
|
|||
if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
|
||||
return false;
|
||||
|
||||
if (pcie_ports_native)
|
||||
return true;
|
||||
|
||||
host = pci_find_host_bridge(bridge->bus);
|
||||
return host->native_pcie_hotplug;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ int pcie_aer_is_native(struct pci_dev *dev)
|
|||
if (!dev->aer_cap)
|
||||
return 0;
|
||||
|
||||
return pcie_ports_native || host->native_aer;
|
||||
return host->native_aer;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(pcie_aer_is_native, "CXL");
|
||||
|
||||
|
|
@ -1847,7 +1847,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
|||
*/
|
||||
aer = root ? root->aer_cap : 0;
|
||||
|
||||
if ((host->native_aer || pcie_ports_native) && aer)
|
||||
if (host->native_aer && aer)
|
||||
aer_disable_irq(root);
|
||||
|
||||
if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {
|
||||
|
|
@ -1862,7 +1862,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
|||
pci_is_root_bus(dev->bus) ? "Root" : "Downstream", rc);
|
||||
}
|
||||
|
||||
if ((host->native_aer || pcie_ports_native) && aer) {
|
||||
if (host->native_aer && aer) {
|
||||
/* Clear Root Error Status */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, ®32);
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ static bool cxl_error_is_native(struct pci_dev *dev)
|
|||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
||||
|
||||
return (pcie_ports_native || host->native_aer);
|
||||
return host->native_aer;
|
||||
}
|
||||
|
||||
static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
|||
* it is responsible for clearing this status. In that case, the
|
||||
* signaling device may not even be visible to the OS.
|
||||
*/
|
||||
if (host->native_aer || pcie_ports_native) {
|
||||
if (host->native_aer) {
|
||||
pcie_clear_device_status(dev);
|
||||
pci_aer_clear_nonfatal_status(dev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ static int get_port_device_capability(struct pci_dev *dev)
|
|||
if (dev->is_pciehp &&
|
||||
(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) &&
|
||||
(pcie_ports_native || host->native_pcie_hotplug)) {
|
||||
host->native_pcie_hotplug) {
|
||||
services |= PCIE_PORT_SERVICE_HP;
|
||||
|
||||
/*
|
||||
|
|
@ -240,14 +240,14 @@ static int get_port_device_capability(struct pci_dev *dev)
|
|||
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC) &&
|
||||
dev->aer_cap && pci_aer_available() &&
|
||||
(pcie_ports_native || host->native_aer))
|
||||
host->native_aer)
|
||||
services |= PCIE_PORT_SERVICE_AER;
|
||||
#endif
|
||||
|
||||
/* Root Ports and Root Complex Event Collectors may generate PMEs */
|
||||
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC) &&
|
||||
(pcie_ports_native || host->native_pme)) {
|
||||
host->native_pme) {
|
||||
services |= PCIE_PORT_SERVICE_PME;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
#define PCIE_PORT_DEVICE_MAXSERVICES 5
|
||||
|
||||
extern bool pcie_ports_dpc_native;
|
||||
|
||||
#ifdef CONFIG_PCIEAER
|
||||
int pcie_aer_init(void);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1915,12 +1915,14 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d,
|
|||
#ifdef CONFIG_PCIEPORTBUS
|
||||
extern bool pcie_ports_disabled;
|
||||
extern bool pcie_ports_native;
|
||||
extern bool pcie_ports_dpc_native;
|
||||
|
||||
int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
|
||||
bool use_lt);
|
||||
#else
|
||||
#define pcie_ports_disabled true
|
||||
#define pcie_ports_native false
|
||||
#define pcie_ports_dpc_native false
|
||||
|
||||
static inline int pcie_set_target_speed(struct pci_dev *port,
|
||||
enum pci_bus_speed speed_req,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user