From 1423de718e6a0ce00372ab119fa40060ff50883e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 2 Jun 2020 15:56:55 -0500 Subject: PCI/ACPI: Make acpi_pci_osc_control_set() static acpi_pci_osc_control_set() is only called from pci_root.c, so stop exporting it and make it static. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 3 +-- include/linux/acpi.h | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0bf072cef6cf..7d5a4bd4207c 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -353,7 +353,7 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev); * _OSC bits the BIOS has granted control of, but its contents are meaningless * on failure. **/ -acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) +static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) { struct acpi_pci_root *root; acpi_status status = AE_OK; @@ -406,7 +406,6 @@ out: mutex_unlock(&osc_lock); return status; } -EXPORT_SYMBOL(acpi_pci_osc_control_set); static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, bool is_pcie) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 053bf05fb1f7..4703daafcce9 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -581,9 +581,6 @@ extern bool osc_pc_lpi_support_confirmed; #define ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES 0x0000000E #define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS 0x0000000F -extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, - u32 *mask, u32 req); - /* Enable _OST when all relevant hotplug operations are enabled */ #if defined(CONFIG_ACPI_HOTPLUG_CPU) && \ defined(CONFIG_ACPI_HOTPLUG_MEMORY) && \ -- cgit From 866e61fc40c96e7adba62c9e149e96912b10663c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 2 Jun 2020 17:27:33 -0500 Subject: PCI/ACPI: Remove unnecessary osc_lock 9778c14b4ca2 ("ACPI/PCI: Fix possible race condition on _OSC evaluation") added locking around _OSC calls to protect the acpi_osc_data_list that stored the results. 63f10f0f6df4 ("PCI/ACPI: move _OSC code to pci_root.c") moved the results from acpi_osc_data_list to the struct acpi_pci_root, where it no longer needs locking, but did not remove the lock. Remove the unnecessary locking around _OSC calls. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7d5a4bd4207c..ea08b3298e73 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -56,8 +56,6 @@ static struct acpi_scan_handler pci_root_handler = { }, }; -static DEFINE_MUTEX(osc_lock); - /** * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge * @handle: the ACPI CA node in question. @@ -223,12 +221,7 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) { - acpi_status status; - - mutex_lock(&osc_lock); - status = acpi_pci_query_osc(root, flags, NULL); - mutex_unlock(&osc_lock); - return status; + return acpi_pci_query_osc(root, flags, NULL); } struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) @@ -356,7 +349,7 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev); static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) { struct acpi_pci_root *root; - acpi_status status = AE_OK; + acpi_status status; u32 ctrl, capbuf[3]; if (!mask) @@ -370,18 +363,16 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r if (!root) return AE_NOT_EXIST; - mutex_lock(&osc_lock); - *mask = ctrl | root->osc_control_set; /* No need to evaluate _OSC if the control was already granted. */ if ((root->osc_control_set & ctrl) == ctrl) - goto out; + return AE_OK; /* Need to check the available controls bits before requesting them. */ while (*mask) { status = acpi_pci_query_osc(root, root->osc_support_set, mask); if (ACPI_FAILURE(status)) - goto out; + return status; if (ctrl == *mask) break; decode_osc_control(root, "platform does not support", @@ -392,19 +383,18 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r if ((ctrl & req) != req) { decode_osc_control(root, "not requesting control; platform does not support", req & ~(ctrl)); - status = AE_SUPPORT; - goto out; + return AE_SUPPORT; } capbuf[OSC_QUERY_DWORD] = 0; capbuf[OSC_SUPPORT_DWORD] = root->osc_support_set; capbuf[OSC_CONTROL_DWORD] = ctrl; status = acpi_pci_run_osc(handle, capbuf, mask); - if (ACPI_SUCCESS(status)) - root->osc_control_set = *mask; -out: - mutex_unlock(&osc_lock); - return status; + if (ACPI_FAILURE(status)) + return status; + + root->osc_control_set = *mask; + return AE_OK; } static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, -- cgit From 508d392ae0bb3729d4c18628e021968a1b11b32c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 2 Jun 2020 16:42:33 -0500 Subject: PCI/ACPI: Clarify message about _OSC failure This message: acpi PNP0A08:02: _OSC failed (AE_NOT_FOUND); disabling ASPM is alarming and slightly misleading. Per the PCI Firmware Spec, r3.2, sec 4.5.1, _OSC is required for PCIe hierarchies. If _OSC is absent or fails, the OS must not attempt to use any of the features defined for _OSC. That includes native hotplug, native PME, AER, and other things as well as ASPM. Rephrase the message to: acpi PNP0A08:02: _OSC: platform retains control of PCIe features (AE_NOT_FOUND) Previous discussion at https://lore.kernel.org/r/20200602223618.GA845676@bjorn-Precision-5520/ Signed-off-by: Bjorn Helgaas Reviewed-by: Sinan Kaya Acked-by: Rafael J. Wysocki Cc: Yicong Yang --- drivers/acpi/pci_root.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ea08b3298e73..dcd593766a64 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -441,9 +441,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, if ((status == AE_NOT_FOUND) && !is_pcie) return; - dev_info(&device->dev, "_OSC failed (%s)%s\n", - acpi_format_exception(status), - pcie_aspm_support_enabled() ? "; disabling ASPM" : ""); + dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", + acpi_format_exception(status)); return; } @@ -499,7 +498,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, } else { decode_osc_control(root, "OS requested", requested); decode_osc_control(root, "platform willing to grant", control); - dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n", + dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", acpi_format_exception(status)); /* -- cgit From f8ee579d53aca887d93f5f411462f25c085a5106 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 2 Feb 2021 17:07:46 +0000 Subject: PCI: pci-bridge-emul: Fix array overruns, improve safety MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We allow up to PCI_EXP_SLTSTA2 registers to be accessed, but the pcie_cap_regs_behavior[] array only covers up to PCI_EXP_RTSTA. Expand this array to avoid walking off the end of it. Do the same for pci_regs_behavior for consistency[], and add a BUILD_BUG_ON() to also check the bridge->conf structure size. Fixes: 23a5fba4d941 ("PCI: Introduce PCI bridge emulated config space common logic") Link: https://lore.kernel.org/r/E1l6z9W-0006Re-MQ@rmk-PC.armlinux.org.uk Signed-off-by: Russell King Signed-off-by: Bjorn Helgaas Reviewed-by: Pali Rohár --- drivers/pci/pci-bridge-emul.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index 139869d50eb2..fdaf86a888b7 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -21,8 +21,9 @@ #include "pci-bridge-emul.h" #define PCI_BRIDGE_CONF_END PCI_STD_HEADER_SIZEOF +#define PCI_CAP_PCIE_SIZEOF (PCI_EXP_SLTSTA2 + 2) #define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END -#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2) +#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_CAP_PCIE_SIZEOF) /** * struct pci_bridge_reg_behavior - register bits behaviors @@ -46,7 +47,8 @@ struct pci_bridge_reg_behavior { u32 w1c; }; -static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { +static const +struct pci_bridge_reg_behavior pci_regs_behavior[PCI_STD_HEADER_SIZEOF / 4] = { [PCI_VENDOR_ID / 4] = { .ro = ~0 }, [PCI_COMMAND / 4] = { .rw = (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | @@ -164,7 +166,8 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { }, }; -static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { +static const +struct pci_bridge_reg_behavior pcie_cap_regs_behavior[PCI_CAP_PCIE_SIZEOF / 4] = { [PCI_CAP_LIST_ID / 4] = { /* * Capability ID, Next Capability Pointer and @@ -260,6 +263,8 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { int pci_bridge_emul_init(struct pci_bridge_emul *bridge, unsigned int flags) { + BUILD_BUG_ON(sizeof(bridge->conf) != PCI_BRIDGE_CONF_END); + bridge->conf.class_revision |= cpu_to_le32(PCI_CLASS_BRIDGE_PCI << 16); bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; bridge->conf.cache_line_size = 0x10; -- cgit From f6bda644fa3a7070621c3bf12cd657f69a42f170 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 2 Feb 2021 11:03:32 +0100 Subject: PCI: Fix pci_register_io_range() memory leak Kmemleak reports: unreferenced object 0xc328de40 (size 64): comm "kworker/1:1", pid 21, jiffies 4294938212 (age 1484.670s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 e0 d8 fc eb 00 00 00 00 ................ 00 00 10 fe 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] pci_register_io_range+0x3c/0x80 [<2c7f139e>] of_pci_range_to_resource+0x48/0xc0 [] devm_of_pci_get_host_bridge_resources.constprop.0+0x2ac/0x3ac [] devm_of_pci_bridge_init+0x60/0x1b8 [] devm_pci_alloc_host_bridge+0x54/0x64 [] rcar_pcie_probe+0x2c/0x644 In case a PCI host driver's probe is deferred, the same I/O range may be allocated again, and be ignored, causing a memory leak. Fix this by (a) letting logic_pio_register_range() return -EEXIST if the passed range already exists, so pci_register_io_range() will free it, and by (b) making pci_register_io_range() not consider -EEXIST an error condition. Link: https://lore.kernel.org/r/20210202100332.829047-1-geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 4 ++++ lib/logic_pio.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b9fecc25d213..50b55a1e3d76 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4029,6 +4029,10 @@ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr, ret = logic_pio_register_range(range); if (ret) kfree(range); + + /* Ignore duplicates due to deferred probing */ + if (ret == -EEXIST) + ret = 0; #endif return ret; diff --git a/lib/logic_pio.c b/lib/logic_pio.c index f32fe481b492..07b4b9a1f54b 100644 --- a/lib/logic_pio.c +++ b/lib/logic_pio.c @@ -28,6 +28,8 @@ static DEFINE_MUTEX(io_range_mutex); * @new_range: pointer to the IO range to be registered. * * Returns 0 on success, the error code in case of failure. + * If the range already exists, -EEXIST will be returned, which should be + * considered a success. * * Register a new IO range node in the IO range list. */ @@ -51,6 +53,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range) list_for_each_entry(range, &io_range_list, list) { if (range->fwnode == new_range->fwnode) { /* range already there */ + ret = -EEXIST; goto end_register; } if (range->flags == LOGIC_PIO_CPU_MMIO && -- cgit