[05/24] RISC-V: ACPI: Add basic functions to build ACPI core
Commit Message
Introduce acpi.c and its related header files to provide
fundamental needs of extern variables and functions for ACPI core.
- asm/acpi.h for arch specific variables and functions needed by
ACPI driver core;
- acpi.c - Add function to initialize ACPI tables.
- acpi.c for RISC-V related ACPI implementation for ACPI driver
core;
Code is mostly leveraged from ARM64.
Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
---
arch/riscv/include/asm/acpi.h | 60 ++++++++++++
arch/riscv/kernel/Makefile | 2 +
arch/riscv/kernel/acpi.c | 178 ++++++++++++++++++++++++++++++++++
3 files changed, 240 insertions(+)
create mode 100644 arch/riscv/include/asm/acpi.h
create mode 100644 arch/riscv/kernel/acpi.c
Comments
On Mon, Jan 30, 2023 at 11:52:06PM +0530, Sunil V L wrote:
> Introduce acpi.c and its related header files to provide
> fundamental needs of extern variables and functions for ACPI core.
> - asm/acpi.h for arch specific variables and functions needed by
> ACPI driver core;
> - acpi.c - Add function to initialize ACPI tables.
> - acpi.c for RISC-V related ACPI implementation for ACPI driver
> core;
>
> Code is mostly leveraged from ARM64.
> diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
> + * __acpi_map_table() will be called before page_init(), so early_ioremap()
rg "\bpage_init\("
arch/riscv/kernel/acpi.c
54: * __acpi_map_table() will be called before page_init(), so early_ioremap()
arch/arm64/kernel/acpi.c
86: * __acpi_map_table() will be called before page_init(), so early_ioremap()
This function doesn't appear to exist, perhaps what you are looking for is
paging_init()?
> + * or early_memremap() should be called here to for ACPI table mapping.
> + */
> +void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
> +{
> + if (!size)
> + return NULL;
> +
> + return early_memremap(phys, size);
> +}
> +void __init acpi_boot_table_init(void)
> +{
> + /*
> + * Enable ACPI instead of device tree unless
> + * - ACPI has been disabled explicitly (acpi=off), or
> + * - firmware has not populated ACPI ptr in EFI system table
> + */
> +
> + if (param_acpi_off || (efi.acpi20 == EFI_INVALID_TABLE_ADDR))
There's an extraneous set of () around the second item here.
> + goto done;
> + /*
A small nit: a newline before opening the comment block here please!
On Wed, Feb 08, 2023 at 08:58:31PM +0000, Conor Dooley wrote:
> On Mon, Jan 30, 2023 at 11:52:06PM +0530, Sunil V L wrote:
> > Introduce acpi.c and its related header files to provide
> > fundamental needs of extern variables and functions for ACPI core.
> > - asm/acpi.h for arch specific variables and functions needed by
> > ACPI driver core;
> > - acpi.c - Add function to initialize ACPI tables.
> > - acpi.c for RISC-V related ACPI implementation for ACPI driver
> > core;
> >
> > Code is mostly leveraged from ARM64.
>
>
>
> > diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
>
> > + * __acpi_map_table() will be called before page_init(), so early_ioremap()
>
> rg "\bpage_init\("
> arch/riscv/kernel/acpi.c
> 54: * __acpi_map_table() will be called before page_init(), so early_ioremap()
>
> arch/arm64/kernel/acpi.c
> 86: * __acpi_map_table() will be called before page_init(), so early_ioremap()
>
> This function doesn't appear to exist, perhaps what you are looking for is
> paging_init()?
>
Yes, will update.
> > + * or early_memremap() should be called here to for ACPI table mapping.
> > + */
> > +void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
> > +{
> > + if (!size)
> > + return NULL;
> > +
> > + return early_memremap(phys, size);
> > +}
>
> > +void __init acpi_boot_table_init(void)
> > +{
> > + /*
> > + * Enable ACPI instead of device tree unless
> > + * - ACPI has been disabled explicitly (acpi=off), or
> > + * - firmware has not populated ACPI ptr in EFI system table
> > + */
> > +
> > + if (param_acpi_off || (efi.acpi20 == EFI_INVALID_TABLE_ADDR))
>
> There's an extraneous set of () around the second item here.
>
Okay.
> > + goto done;
> > + /*
>
> A small nit: a newline before opening the comment block here please!
Thanks, will fix these in the next revision.
-Sunil
new file mode 100644
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2013-2014, Linaro Ltd.
+ * Author: Al Stone <al.stone@linaro.org>
+ * Author: Graeme Gregory <graeme.gregory@linaro.org>
+ * Author: Hanjun Guo <hanjun.guo@linaro.org>
+ *
+ * Copyright (C) 2021-2023, Ventana Micro Systems Inc.
+ * Author: Sunil V L <sunilvl@ventanamicro.com>
+ */
+
+#ifndef _ASM_ACPI_H
+#define _ASM_ACPI_H
+
+/* Basic configuration for ACPI */
+#ifdef CONFIG_ACPI
+
+/* ACPI table mapping after acpi_permanent_mmap is set */
+void *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
+#define acpi_os_ioremap acpi_os_ioremap
+
+#define acpi_strict 1 /* No out-of-spec workarounds on RISC-V */
+extern int acpi_disabled;
+extern int acpi_noirq;
+extern int acpi_pci_disabled;
+static inline void disable_acpi(void)
+{
+ acpi_disabled = 1;
+ acpi_pci_disabled = 1;
+ acpi_noirq = 1;
+}
+
+static inline void enable_acpi(void)
+{
+ acpi_disabled = 0;
+ acpi_pci_disabled = 0;
+ acpi_noirq = 0;
+}
+
+/*
+ * The ACPI processor driver for ACPI core code needs this macro
+ * to find out this cpu was already mapped (mapping from CPU hardware
+ * ID to CPU logical ID) or not.
+ */
+#define cpu_physical_id(cpu) cpuid_to_hartid_map(cpu)
+
+/*
+ * It's used from ACPI core in kdump to boot UP system with SMP kernel.
+ * Since MADT must provide at least one IMSIC structure for AIA
+ * initialization, CPU will be always available in MADT on RISC-V.
+ */
+static inline bool acpi_has_cpu_in_madt(void)
+{
+ return true;
+}
+
+static inline void arch_fix_phys_package_id(int num, u32 slot) { }
+#endif
+
+#endif /*_ASM_ACPI_H*/
@@ -90,3 +90,5 @@ obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_COMPAT) += compat_syscall_table.o
obj-$(CONFIG_COMPAT) += compat_signal.o
obj-$(CONFIG_COMPAT) += compat_vdso/
+
+obj-$(CONFIG_ACPI) += acpi.o
new file mode 100644
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RISC-V Specific Low-Level ACPI Boot Support
+ *
+ * Copyright (C) 2013-2014, Linaro Ltd.
+ * Author: Al Stone <al.stone@linaro.org>
+ * Author: Graeme Gregory <graeme.gregory@linaro.org>
+ * Author: Hanjun Guo <hanjun.guo@linaro.org>
+ * Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
+ * Author: Naresh Bhat <naresh.bhat@linaro.org>
+ *
+ * Copyright (C) 2021-2023, Ventana Micro Systems Inc.
+ * Author: Sunil V L <sunilvl@ventanamicro.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <linux/efi-bgrt.h>
+#include <linux/io.h>
+#include <linux/of_fdt.h>
+#include <linux/serial_core.h>
+
+int acpi_noirq = 1; /* skip ACPI IRQ initialization */
+int acpi_disabled = 1;
+EXPORT_SYMBOL(acpi_disabled);
+
+int acpi_pci_disabled = 1; /* skip ACPI PCI scan and IRQ initialization */
+EXPORT_SYMBOL(acpi_pci_disabled);
+
+static bool param_acpi_off __initdata;
+static bool param_acpi_on __initdata;
+static bool param_acpi_force __initdata;
+
+static int __init parse_acpi(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ /* "acpi=off" disables both ACPI table parsing and interpreter */
+ if (strcmp(arg, "off") == 0)
+ param_acpi_off = true;
+ else if (strcmp(arg, "on") == 0) /* prefer ACPI over DT */
+ param_acpi_on = true;
+ else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+ param_acpi_force = true;
+ else
+ return -EINVAL; /* Core will print when we return error */
+
+ return 0;
+}
+early_param("acpi", parse_acpi);
+
+/*
+ * __acpi_map_table() will be called before page_init(), so early_ioremap()
+ * or early_memremap() should be called here to for ACPI table mapping.
+ */
+void __init __iomem *__acpi_map_table(unsigned long phys, unsigned long size)
+{
+ if (!size)
+ return NULL;
+
+ return early_memremap(phys, size);
+}
+
+void __init __acpi_unmap_table(void __iomem *map, unsigned long size)
+{
+ if (!map || !size)
+ return;
+
+ early_memunmap(map, size);
+}
+
+void *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+{
+ return memremap(phys, size, MEMREMAP_WB);
+}
+
+/*
+ * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity
+ * checks on it
+ *
+ * Return 0 on success, <0 on failure
+ */
+static int __init acpi_fadt_sanity_check(void)
+{
+ struct acpi_table_header *table;
+ struct acpi_table_fadt *fadt;
+ acpi_status status;
+ int ret = 0;
+
+ /*
+ * FADT is required on riscv; retrieve it to check its presence
+ * and carry out revision and ACPI HW reduced compliancy tests
+ */
+ status = acpi_get_table(ACPI_SIG_FADT, 0, &table);
+ if (ACPI_FAILURE(status)) {
+ const char *msg = acpi_format_exception(status);
+
+ pr_err("Failed to get FADT table, %s\n", msg);
+ return -ENODEV;
+ }
+
+ fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * TODO: Should we add FADT version checks?
+ */
+
+ if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
+ pr_err("FADT not ACPI hardware reduced compliant\n");
+ ret = -EINVAL;
+ }
+
+ /*
+ * acpi_get_table() creates FADT table mapping that
+ * should be released after parsing and before resuming boot
+ */
+ acpi_put_table(table);
+ return ret;
+}
+
+/*
+ * acpi_boot_table_init() called from setup_arch(), always.
+ * 1. find RSDP and get its address, and then find XSDT
+ * 2. extract all tables and checksums them all
+ * 3. check ACPI FADT revision
+ * 4. check ACPI FADT HW reduced flag
+ *
+ * We can parse ACPI boot-time tables such as MADT after
+ * this function is called.
+ *
+ * On return ACPI is enabled if either:
+ *
+ * - ACPI tables are initialized and sanity checks passed
+ * - acpi=force was passed in the command line and ACPI was not disabled
+ * explicitly through acpi=off command line parameter
+ *
+ * ACPI is disabled on function return otherwise
+ */
+void __init acpi_boot_table_init(void)
+{
+ /*
+ * Enable ACPI instead of device tree unless
+ * - ACPI has been disabled explicitly (acpi=off), or
+ * - firmware has not populated ACPI ptr in EFI system table
+ */
+
+ if (param_acpi_off || (efi.acpi20 == EFI_INVALID_TABLE_ADDR))
+ goto done;
+ /*
+ * ACPI is disabled at this point. Enable it in order to parse
+ * the ACPI tables and carry out sanity checks
+ */
+ enable_acpi();
+
+ /*
+ * If ACPI tables are initialized and FADT sanity checks passed,
+ * leave ACPI enabled and carry on booting; otherwise disable ACPI
+ * on initialization error.
+ * If acpi=force was passed on the command line it forces ACPI
+ * to be enabled even if its initialization failed.
+ */
+ if (acpi_table_init() || acpi_fadt_sanity_check()) {
+ pr_err("Failed to init ACPI tables\n");
+ if (!param_acpi_force)
+ disable_acpi();
+ }
+
+done:
+ if (acpi_disabled) {
+ if (earlycon_acpi_spcr_enable)
+ early_init_dt_scan_chosen_stdout();
+ } else {
+ acpi_parse_spcr(earlycon_acpi_spcr_enable, true);
+ if (IS_ENABLED(CONFIG_ACPI_BGRT))
+ acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
+ }
+}