From 4dea41775d951ff1f7b472a346a8ca3ae7e74455 Mon Sep 17 00:00:00 2001 From: Kang Chen Date: Sun, 26 Feb 2023 13:54:27 +0800 Subject: ACPI: processor: Check for null return of devm_kzalloc() in fch_misc_setup() devm_kzalloc() may fail, clk_data->name might be NULL and will cause a NULL pointer dereference later. Signed-off-by: Kang Chen [ rjw: Subject and changelog edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_apd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 3bbe2276cac7..80f945cbec8a 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -83,6 +83,8 @@ static int fch_misc_setup(struct apd_private_data *pdata) if (!acpi_dev_get_property(adev, "clk-name", ACPI_TYPE_STRING, &obj)) { clk_data->name = devm_kzalloc(&adev->dev, obj->string.length, GFP_KERNEL); + if (!clk_data->name) + return -ENOMEM; strcpy(clk_data->name, obj->string.pointer); } else { -- cgit v1.2.3 From f2cba54a7fbf971d87bcd4467797c62d551401d3 Mon Sep 17 00:00:00 2001 From: Simon Gaiser Date: Mon, 13 Mar 2023 15:47:10 +0100 Subject: ACPI: s2idle: Log when enabling wakeup IRQ fails enable_irq_wake() can fail. Previously acpi_s2idle_prepare() silently ignored it's return code. Based on [1] we should try to continue even in case of an error, so just log a warning for now. Discovered when trying to go into s2idle under Xen. This leads to a system that can't be woken, since xen-pirq currently doesn't support setting wakeup IRQs [2]. With this you get at least some helpful log message if you have access to console messages. Link: https://lore.kernel.org/linux-acpi/20230313125344.2893-1-simon@invisiblethingslab.com/ # v1 Link: https://lore.kernel.org/linux-acpi/CAJZ5v0jahjt58nP6P5+xRdtD_ndYPvq4ecMVz6nfGu9tf5iaUw@mail.gmail.com/ # [1] Link: https://lore.kernel.org/xen-devel/20230313134102.3157-1-simon@invisiblethingslab.com/ # [2] Signed-off-by: Simon Gaiser [ rjw: Adjust white space ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 4ca667251272..72470b9f16c4 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -714,7 +714,13 @@ int acpi_s2idle_begin(void) int acpi_s2idle_prepare(void) { if (acpi_sci_irq_valid()) { - enable_irq_wake(acpi_sci_irq); + int error; + + error = enable_irq_wake(acpi_sci_irq); + if (error) + pr_warn("Warning: Failed to enable wakeup from IRQ %d: %d\n", + acpi_sci_irq, error); + acpi_ec_set_gpe_wake_mask(ACPI_GPE_ENABLE); } -- cgit v1.2.3 From 691a637123470bfe63bccf5836ead40fac4c7fab Mon Sep 17 00:00:00 2001 From: Petr Pavlu Date: Thu, 16 Mar 2023 16:10:36 +0100 Subject: ACPI: cpufreq: Use platform devices to load ACPI PPC and PCC drivers The acpi-cpufreq and pcc-cpufreq drivers are loaded through per-CPU module aliases. This can result in many unnecessary load requests during boot if another frequency module, such as intel_pstate, is already active. For instance, on a typical Intel system, one can observe that udev makes 2x#CPUs attempts to insert acpi_cpufreq and 1x#CPUs attempts for pcc_cpufreq. All these tries then fail if another frequency module is already registered. In the worst case, without the recent fix in commit 0254127ab977e ("module: Don't wait for GOING modules"), these module loads occupied all udev workers and had their initialization attempts ran sequentially. Resolving all these loads then on some larger machines took too long, prevented other hardware from getting its drivers initialized and resulted in a failed boot. Discussion over these duplicate module requests ended up with a conclusion that only one load attempt should be ideally made. Both acpi-cpufreq and pcc-cpufreq drivers use platform firmware controls which are defined by ACPI. It is possible to treat these interfaces as platform devices. The patch extends the ACPI parsing logic to check the ACPI namespace if the PPC or PCC interface is present and creates a virtual platform device for each if it is available. The acpi-cpufreq and pcc-cpufreq drivers are then updated to map to these devices. This allows to try loading acpi-cpufreq and pcc-cpufreq only once during boot and only if a given interface is available in the firmware. Signed-off-by: Petr Pavlu [ rjw: whitespace and error message log level adjustments, subject edits ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 6737b1cbf6d6..f9aa02cac6d1 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -148,6 +149,34 @@ static int acpi_processor_errata(void) return result; } +/* Create a platform device to represent a CPU frequency control mechanism. */ +static void cpufreq_add_device(const char *name) +{ + struct platform_device *pdev; + + pdev = platform_device_register_simple(name, PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(pdev)) + pr_info("%s device creation failed: %ld\n", name, PTR_ERR(pdev)); +} + +#ifdef CONFIG_X86 +/* Check presence of Processor Clocking Control by searching for \_SB.PCCH. */ +static void __init acpi_pcc_cpufreq_init(void) +{ + acpi_status status; + acpi_handle handle; + + status = acpi_get_handle(NULL, "\\_SB", &handle); + if (ACPI_FAILURE(status)) + return; + + if (acpi_has_method(handle, "PCCH")) + cpufreq_add_device("pcc-cpufreq"); +} +#else +static void __init acpi_pcc_cpufreq_init(void) {} +#endif /* CONFIG_X86 */ + /* Initialization */ #ifdef CONFIG_ACPI_HOTPLUG_CPU int __weak acpi_map_cpu(acpi_handle handle, @@ -280,14 +309,22 @@ static int acpi_processor_get_info(struct acpi_device *device) dev_dbg(&device->dev, "Failed to get CPU physical ID.\n"); pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id); - if (!cpu0_initialized && !acpi_has_cpu_in_madt()) { + if (!cpu0_initialized) { cpu0_initialized = 1; /* * Handle UP system running SMP kernel, with no CPU * entry in MADT */ - if (invalid_logical_cpuid(pr->id) && (num_online_cpus() == 1)) + if (!acpi_has_cpu_in_madt() && invalid_logical_cpuid(pr->id) && + (num_online_cpus() == 1)) pr->id = 0; + /* + * Check availability of Processor Performance Control by + * looking at the presence of the _PCT object under the first + * processor definition. + */ + if (acpi_has_method(pr->handle, "_PCT")) + cpufreq_add_device("acpi-cpufreq"); } /* @@ -686,6 +723,7 @@ void __init acpi_processor_init(void) acpi_processor_check_duplicates(); acpi_scan_add_handler_with_hotplug(&processor_handler, "processor"); acpi_scan_add_handler(&processor_container_handler); + acpi_pcc_cpufreq_init(); } #ifdef CONFIG_ACPI_PROCESSOR_CSTATE -- cgit v1.2.3 From 073828e954459b883f23e53999d31e4c55ab9654 Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Wed, 22 Mar 2023 12:13:29 +0100 Subject: ACPI: processor: Fix evaluating _PDC method when running as Xen dom0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ACPI systems, the OS can direct power management, as opposed to the firmware. This OS-directed Power Management is called OSPM. Part of telling the firmware that the OS going to direct power management is making ACPI "_PDC" (Processor Driver Capabilities) calls. These _PDC methods must be evaluated for every processor object. If these _PDC calls are not completed for every processor it can lead to inconsistency and later failures in things like the CPU frequency driver. In a Xen system, the dom0 kernel is responsible for system-wide power management. The dom0 kernel is in charge of OSPM. However, the number of CPUs available to dom0 can be different than the number of CPUs physically present on the system. This leads to a problem: the dom0 kernel needs to evaluate _PDC for all the processors, but it can't always see them. In dom0 kernels, ignore the existing ACPI method for determining if a processor is physically present because it might not be accurate. Instead, ask the hypervisor for this information. Fix this by introducing a custom function to use when running as Xen dom0 in order to check whether a processor object matches a CPU that's online. Such checking is done using the existing information fetched by the Xen pCPU subsystem, extending it to also store the ACPI ID. This ensures that _PDC method gets evaluated for all physically online CPUs, regardless of the number of CPUs made available to dom0. Fixes: 5d554a7bb064 ("ACPI: processor: add internal processor_physically_present()") Signed-off-by: Roger Pau Monné Reviewed-by: Juergen Gross Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_pdc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 8c3f82c9fff3..18fb04523f93 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -14,6 +14,8 @@ #include #include +#include + #include "internal.h" static bool __init processor_physically_present(acpi_handle handle) @@ -47,6 +49,15 @@ static bool __init processor_physically_present(acpi_handle handle) return false; } + if (xen_initial_domain()) + /* + * When running as a Xen dom0 the number of processors Linux + * sees can be different from the real number of processors on + * the system, and we still need to execute _PDC for all of + * them. + */ + return xen_processor_present(acpi_id); + type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0; cpuid = acpi_get_cpuid(handle, type, acpi_id); -- cgit v1.2.3 From da30a34a0edb88144ac10db5ef781ae84769af67 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 12:22:57 +0200 Subject: ACPI: SPCR: Prefix error messages with FW_BUG The table values that are not defined in the specification are considered non-fatal errors in the code. However, they are firmware bugs, so point this out in the messages by prefixing them with FW_BUG. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 1eabfcd122ee..01d29ebdb9c2 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -110,12 +110,12 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) u32 bit_width = table->serial_port.access_width; if (bit_width > ACPI_ACCESS_BIT_MAX) { - pr_err("Unacceptable wide SPCR Access Width. Defaulting to byte size\n"); + pr_err(FW_BUG "Unacceptable wide SPCR Access Width. Defaulting to byte size\n"); bit_width = ACPI_ACCESS_BIT_DEFAULT; } switch (ACPI_ACCESS_BIT_WIDTH((bit_width))) { default: - pr_err("Unexpected SPCR Access Width. Defaulting to byte size\n"); + pr_err(FW_BUG "Unexpected SPCR Access Width. Defaulting to byte size\n"); fallthrough; case 8: iotype = "mmio"; -- cgit v1.2.3 From 4f855dcead6c5be0a48a2779eeecb170ec144534 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Wed, 22 Mar 2023 12:13:13 -0700 Subject: ACPI: sysfs: Enable ACPI sysfs support for CCEL records The Confidential Computing Event Log (CCEL) table provides the address and length of the CCEL records area in UEFI reserved memory. To allow user space access to these records, expose a sysfs interface similar to the BERT table. More details about the CCEL table can be found in the ACPI specification r6.5 [1], sec 5.2.34. Link: https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#cc-event-log-acpi-table # [1] Co-developed-by: Haibo Xu Signed-off-by: Haibo Xu Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 7f4ff56c9d42..687524b50085 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -458,11 +458,28 @@ static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr) return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); } +static int acpi_ccel_data_init(void *th, struct acpi_data_attr *data_attr) +{ + struct acpi_table_ccel *ccel = th; + + if (ccel->header.length < sizeof(struct acpi_table_ccel) || + !ccel->log_area_start_address || !ccel->log_area_minimum_length) { + kfree(data_attr); + return -EINVAL; + } + data_attr->addr = ccel->log_area_start_address; + data_attr->attr.size = ccel->log_area_minimum_length; + data_attr->attr.attr.name = "CCEL"; + + return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); +} + static struct acpi_data_obj { char *name; int (*fn)(void *, struct acpi_data_attr *); } acpi_data_objs[] = { { ACPI_SIG_BERT, acpi_bert_data_init }, + { ACPI_SIG_CCEL, acpi_ccel_data_init }, }; #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs) -- cgit v1.2.3 From dcf0c2e06ac2f698354febab0b34a7135282164b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Mar 2023 16:25:12 +0300 Subject: ACPI: SPCR: Amend indentation 1) Remove unnecessary blank lines. 2) Reformat one comment for consistency. Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/acpi/spcr.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index 01d29ebdb9c2..cd36a97b0ea2 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -71,7 +71,6 @@ static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) /** * acpi_parse_spcr() - parse ACPI SPCR table and add preferred console - * * @enable_earlycon: set up earlycon for the console specified by the table * @enable_console: setup the console specified by the table. * @@ -82,7 +81,6 @@ static bool xgene_8250_erratum_present(struct acpi_table_spcr *tb) * * When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called * from arch initialization code as soon as the DT/ACPI decision is made. - * */ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) { @@ -97,9 +95,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) if (acpi_disabled) return -ENODEV; - status = acpi_get_table(ACPI_SIG_SPCR, 0, - (struct acpi_table_header **)&table); - + status = acpi_get_table(ACPI_SIG_SPCR, 0, (struct acpi_table_header **)&table); if (ACPI_FAILURE(status)) return -ENOENT; @@ -202,7 +198,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console) if (xgene_8250_erratum_present(table)) { iotype = "mmio32"; - /* for xgene v1 and v2 we don't know the clock rate of the + /* + * For xgene v1 and v2 we don't know the clock rate of the * UART so don't attempt to change to the baud rate state * in the table because driver cannot calculate the dividers */ -- cgit v1.2.3 From 47d26684185d09e083669bbbd0c465ab3493a51f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Brucker Date: Mon, 20 Mar 2023 18:05:29 +0000 Subject: ACPI: VIOT: Initialize the correct IOMMU fwspec When setting up DMA for a PCI device, we need to initialize its iommu_fwspec with all possible alias RIDs (such as PCI bridges). To do this we use pci_for_each_dma_alias() which calls viot_pci_dev_iommu_init(). This function incorrectly initializes the fwspec of the bridge instead of the device being configured. Fix it by passing the original device as context to pci_for_each_dma_alias(). Fixes: 3cf485540e7b ("ACPI: Add driver for the VIOT table") Link: https://lore.kernel.org/all/Y8qzOKm6kvhGWG1T@myrica Reported-by: Eric Auger Signed-off-by: Jean-Philippe Brucker Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Rafael J. Wysocki --- drivers/acpi/viot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/viot.c b/drivers/acpi/viot.c index ed752cbbe636..c8025921c129 100644 --- a/drivers/acpi/viot.c +++ b/drivers/acpi/viot.c @@ -328,6 +328,7 @@ static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data) { u32 epid; struct viot_endpoint *ep; + struct device *aliased_dev = data; u32 domain_nr = pci_domain_nr(pdev->bus); list_for_each_entry(ep, &viot_pci_ranges, list) { @@ -338,7 +339,7 @@ static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data) epid = ((domain_nr - ep->segment_start) << 16) + dev_id - ep->bdf_start + ep->endpoint_id; - return viot_dev_iommu_init(&pdev->dev, ep->viommu, + return viot_dev_iommu_init(aliased_dev, ep->viommu, epid); } } @@ -372,7 +373,7 @@ int viot_iommu_configure(struct device *dev) { if (dev_is_pci(dev)) return pci_for_each_dma_alias(to_pci_dev(dev), - viot_pci_dev_iommu_init, NULL); + viot_pci_dev_iommu_init, dev); else if (dev_is_platform(dev)) return viot_mmio_dev_iommu_init(to_platform_device(dev)); return -ENODEV; -- cgit v1.2.3