Discussion:
[PATCH v6 06/17] ARM64 / ACPI: If we chose to boot from acpi then disable FDT
(too old to reply)
Hanjun Guo
2015-01-04 10:55:07 UTC
Permalink
From: Graeme Gregory <***@linaro.org>

If the early boot methods of acpi are happy that we have valid ACPI
tables and acpi=force has been passed, then do not unflat devicetree
effectively disabling further hardware probing from DT.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/kernel/setup.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 22e6895..2534de3 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -410,7 +410,8 @@ void __init setup_arch(char **cmdline_p)

efi_idmap_init();

- unflatten_device_tree();
+ if (acpi_disabled)
+ unflatten_device_tree();

psci_init();
--
1.9.1
Hanjun Guo
2015-01-04 10:55:06 UTC
Permalink
From: Al Stone <***@linaro.org>

Introduce one early parameters "off" and "force" for "acpi", acpi=off
will be the default behavior for ARM64, so introduce acpi=force to
enable ACPI on ARM64.

Disable ACPI before early parameters parsed, and enable it to pass
"acpi=force" if people want use ACPI on ARM64. This ensures DT be
the prefer one if ACPI table and DT both are provided at this moment.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
Documentation/kernel-parameters.txt | 3 ++-
arch/arm64/include/asm/acpi.h | 9 +++++++++
arch/arm64/kernel/acpi.c | 17 +++++++++++++++++
arch/arm64/kernel/setup.c | 3 +++
4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4df73da..4adfd50 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -165,7 +165,7 @@ multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30
bytes respectively. Such letter suffixes can also be entirely omitted.


- acpi= [HW,ACPI,X86]
+ acpi= [HW,ACPI,X86,ARM64]
Advanced Configuration and Power Interface
Format: { force | off | strict | noirq | rsdt }
force -- enable ACPI if default was off
@@ -175,6 +175,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
strictly ACPI specification compliant.
rsdt -- prefer RSDT over (default) XSDT
copy_dsdt -- copy DSDT to memory
+ For ARM64, ONLY "acpi=off" or "acpi=force" are available

See also Documentation/power/runtime_pm.txt, pci=noacpi

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 8b837ab..496c33b 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -26,6 +26,13 @@ static inline void disable_acpi(void)
acpi_noirq = 1;
}

+static inline void enable_acpi(void)
+{
+ acpi_disabled = 0;
+ acpi_pci_disabled = 0;
+ acpi_noirq = 0;
+}
+
/*
* It's used from ACPI core in kdump to boot UP system with SMP kernel,
* with this check the ACPI core will not override the CPU index
@@ -40,6 +47,8 @@ static inline bool acpi_has_cpu_in_madt(void)

static inline void arch_fix_phys_package_id(int num, u32 slot) { }

+#else
+static inline void disable_acpi(void) { }
#endif /* CONFIG_ACPI */

#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 9252f72..39a1655 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -67,3 +67,20 @@ void __init acpi_boot_table_init(void)
if (acpi_table_init())
disable_acpi();
}
+
+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)
+ disable_acpi();
+ else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
+ enable_acpi();
+ else
+ return -EINVAL; /* Core will print when we return error */
+
+ return 0;
+}
+early_param("acpi", parse_acpi);
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 224a2e6..22e6895 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -62,6 +62,7 @@
#include <asm/memblock.h>
#include <asm/psci.h>
#include <asm/efi.h>
+#include <asm/acpi.h>

unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
@@ -388,6 +389,8 @@ void __init setup_arch(char **cmdline_p)
early_fixmap_init();
early_ioremap_init();

+ disable_acpi();
+
parse_early_param();

/*
--
1.9.1
Hanjun Guo
2015-01-04 10:55:05 UTC
Permalink
From: Graeme Gregory <***@linaro.org>

ACPI 5.1 does not currently support S states for ARM64 hardware but
ACPI code will call acpi_target_system_state() for device power
managment, so introduce sleep-arm.c to allow other drivers to function
until S states are defined.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
drivers/acpi/Makefile | 4 ++++
drivers/acpi/sleep-arm.c | 28 ++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
create mode 100644 drivers/acpi/sleep-arm.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index f74317c..39f3ec1 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -23,7 +23,11 @@ acpi-y += nvs.o

# Power management related files
acpi-y += wakeup.o
+ifeq ($(ARCH), arm64)
+acpi-y += sleep-arm.o
+else # X86, IA64
acpi-y += sleep.o
+endif
acpi-y += device_pm.o
acpi-$(CONFIG_ACPI_SLEEP) += proc.o

diff --git a/drivers/acpi/sleep-arm.c b/drivers/acpi/sleep-arm.c
new file mode 100644
index 0000000..54578ef
--- /dev/null
+++ b/drivers/acpi/sleep-arm.c
@@ -0,0 +1,28 @@
+/*
+ * ARM64 Specific Sleep Functionality
+ *
+ * Copyright (C) 2013-2014, Linaro Ltd.
+ * Author: Graeme Gregory <***@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+
+/*
+ * Currently the ACPI 5.1 standard does not define S states in a
+ * manner which is usable for ARM64. These two stubs are sufficient
+ * that system initialises and device PM works.
+ */
+u32 acpi_target_system_state(void)
+{
+ return ACPI_STATE_S0;
+}
+EXPORT_SYMBOL_GPL(acpi_target_system_state);
+
+int __init acpi_sleep_init(void)
+{
+ return -ENOSYS;
+}
--
1.9.1
Hanjun Guo
2015-01-04 10:55:03 UTC
Permalink
From: Hanjun Guo <***@linaro.com>

acpi_map_lsapic() will allocate a logical CPU number and map it to
physical CPU id (such as APIC id) for the hot-added CPU, it will also
do some mapping for NUMA node id and etc, acpi_unmap_lsapic() will
do the reverse.

We can see that the name of the function is a little bit confusing and
arch (IA64) dependent so rename them as acpi_(un)map_cpu() to make arch
agnostic and explicit.

Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/ia64/kernel/acpi.c | 9 ++++-----
arch/x86/kernel/acpi/boot.c | 9 ++++-----
drivers/acpi/acpi_processor.c | 6 +++---
include/linux/acpi.h | 4 ++--
4 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 615ef81..e795cb8 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -893,13 +893,13 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
}

/* wrapper to silence section mismatch warning */
-int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
+int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu)
{
return _acpi_map_lsapic(handle, physid, pcpu);
}
-EXPORT_SYMBOL(acpi_map_lsapic);
+EXPORT_SYMBOL(acpi_map_cpu);

-int acpi_unmap_lsapic(int cpu)
+int acpi_unmap_cpu(int cpu)
{
ia64_cpu_to_sapicid[cpu] = -1;
set_cpu_present(cpu, false);
@@ -910,8 +910,7 @@ int acpi_unmap_lsapic(int cpu)

return (0);
}
-
-EXPORT_SYMBOL(acpi_unmap_lsapic);
+EXPORT_SYMBOL(acpi_unmap_cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

#ifdef CONFIG_ACPI_NUMA
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 4433a4b..d162636 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -750,13 +750,13 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
}

/* wrapper to silence section mismatch warning */
-int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
+int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu)
{
return _acpi_map_lsapic(handle, physid, pcpu);
}
-EXPORT_SYMBOL(acpi_map_lsapic);
+EXPORT_SYMBOL(acpi_map_cpu);

-int acpi_unmap_lsapic(int cpu)
+int acpi_unmap_cpu(int cpu)
{
#ifdef CONFIG_ACPI_NUMA
set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE);
@@ -768,8 +768,7 @@ int acpi_unmap_lsapic(int cpu)

return (0);
}
-
-EXPORT_SYMBOL(acpi_unmap_lsapic);
+EXPORT_SYMBOL(acpi_unmap_cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index f02b29e..1020b1b 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -180,13 +180,13 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
cpu_maps_update_begin();
cpu_hotplug_begin();

- ret = acpi_map_lsapic(pr->handle, pr->phys_id, &pr->id);
+ ret = acpi_map_cpu(pr->handle, pr->phys_id, &pr->id);
if (ret)
goto out;

ret = arch_register_cpu(pr->id);
if (ret) {
- acpi_unmap_lsapic(pr->id);
+ acpi_unmap_cpu(pr->id);
goto out;
}

@@ -461,7 +461,7 @@ static void acpi_processor_remove(struct acpi_device *device)

/* Remove the CPU. */
arch_unregister_cpu(pr->id);
- acpi_unmap_lsapic(pr->id);
+ acpi_unmap_cpu(pr->id);

cpu_hotplug_done();
cpu_maps_update_done();
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 856d381..d459cd1 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -147,8 +147,8 @@ void acpi_numa_arch_fixup(void);

#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* Arch dependent functions for cpu hotplug support */
-int acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu);
-int acpi_unmap_lsapic(int cpu);
+int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu);
+int acpi_unmap_cpu(int cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */

int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
--
1.9.1
Hanjun Guo
2015-01-04 10:55:02 UTC
Permalink
From: Hanjun Guo <***@linaro.com>

apic_id in MADT table is the CPU hardware id which identify
it self in the system for x86 and ia64, OSPM will use it for
SMP init to map APIC ID to logical cpu number in the early
boot, when the DSDT/SSDT (ACPI namespace) is scanned later, the
ACPI processor driver is probed and the driver will use acpi_id
in DSDT to get the apic_id, then map to the logical cpu number
which is needed by the processor driver.

Before ACPI 5.0, only x86 and ia64 were supported in ACPI spec,
so apic_id is used both in arch code and ACPI core which is
pretty fine. Since ACPI 5.0, ARM is supported by ACPI and
APIC is not available on ARM, this will confuse people when
apic_id is both used by x86 and ARM in one function.

So convert apic_id to phys_id (which is the original meaning)
in ACPI processor dirver to make it arch agnostic, but leave the
arch dependent code unchanged, no functional change.

Signed-off-by: Hanjun Guo <***@linaro.org>
---
drivers/acpi/acpi_processor.c | 21 +++++++++-------
drivers/acpi/processor_core.c | 56 +++++++++++++++++++++----------------------
include/acpi/processor.h | 8 +++----
3 files changed, 44 insertions(+), 41 deletions(-)

diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 1fdf5e0..f02b29e 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
acpi_status status;
int ret;

- if (pr->apic_id == -1)
+ if (pr->phys_id == -1)
return -ENODEV;

status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
@@ -180,7 +180,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
cpu_maps_update_begin();
cpu_hotplug_begin();

- ret = acpi_map_lsapic(pr->handle, pr->apic_id, &pr->id);
+ ret = acpi_map_lsapic(pr->handle, pr->phys_id, &pr->id);
if (ret)
goto out;

@@ -215,7 +215,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
struct acpi_processor *pr = acpi_driver_data(device);
- int apic_id, cpu_index, device_declaration = 0;
+ int phys_id, cpu_index, device_declaration = 0;
acpi_status status = AE_OK;
static int cpu0_initialized;
unsigned long long value;
@@ -262,15 +262,18 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->acpi_id = value;
}

- apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
- if (apic_id < 0)
- acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
- pr->apic_id = apic_id;
+ phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id);
+ if (phys_id < 0)
+ acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n");
+ pr->phys_id = phys_id;

- cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
+ cpu_index = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
if (!cpu0_initialized && !acpi_has_cpu_in_madt()) {
cpu0_initialized = 1;
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ /*
+ * Handle UP system running SMP kernel, with no CPU
+ * entry in MADT
+ */
if ((cpu_index == -1) && (num_online_cpus() == 1))
cpu_index = 0;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 342942f..02e4839 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -69,7 +69,7 @@ static int map_madt_entry(int type, u32 acpi_id)
unsigned long madt_end, entry;
static struct acpi_table_madt *madt;
static int read_madt;
- int apic_id = -1;
+ int phys_id = -1; /* CPU hardware ID */

if (!read_madt) {
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
@@ -79,7 +79,7 @@ static int map_madt_entry(int type, u32 acpi_id)
}

if (!madt)
- return apic_id;
+ return phys_id;

entry = (unsigned long)madt;
madt_end = entry + madt->header.length;
@@ -91,18 +91,18 @@ static int map_madt_entry(int type, u32 acpi_id)
struct acpi_subtable_header *header =
(struct acpi_subtable_header *)entry;
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
- if (!map_lapic_id(header, acpi_id, &apic_id))
+ if (!map_lapic_id(header, acpi_id, &phys_id))
break;
} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
- if (!map_x2apic_id(header, type, acpi_id, &apic_id))
+ if (!map_x2apic_id(header, type, acpi_id, &phys_id))
break;
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
- if (!map_lsapic_id(header, type, acpi_id, &apic_id))
+ if (!map_lsapic_id(header, type, acpi_id, &phys_id))
break;
}
entry += header->length;
}
- return apic_id;
+ return phys_id;
}

static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
@@ -110,7 +110,7 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
struct acpi_subtable_header *header;
- int apic_id = -1;
+ int phys_id = -1;

if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
goto exit;
@@ -126,38 +126,38 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)

header = (struct acpi_subtable_header *)obj->buffer.pointer;
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
- map_lapic_id(header, acpi_id, &apic_id);
+ map_lapic_id(header, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
- map_lsapic_id(header, type, acpi_id, &apic_id);
+ map_lsapic_id(header, type, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
- map_x2apic_id(header, type, acpi_id, &apic_id);
+ map_x2apic_id(header, type, acpi_id, &phys_id);

exit:
kfree(buffer.pointer);
- return apic_id;
+ return phys_id;
}

-int acpi_get_apicid(acpi_handle handle, int type, u32 acpi_id)
+int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
{
- int apic_id;
+ int phys_id;

- apic_id = map_mat_entry(handle, type, acpi_id);
- if (apic_id == -1)
- apic_id = map_madt_entry(type, acpi_id);
+ phys_id = map_mat_entry(handle, type, acpi_id);
+ if (phys_id == -1)
+ phys_id = map_madt_entry(type, acpi_id);

- return apic_id;
+ return phys_id;
}

-int acpi_map_cpuid(int apic_id, u32 acpi_id)
+int acpi_map_cpuid(int phys_id, u32 acpi_id)
{
#ifdef CONFIG_SMP
int i;
#endif

- if (apic_id == -1) {
+ if (phys_id == -1) {
/*
* On UP processor, there is no _MAT or MADT table.
- * So above apic_id is always set to -1.
+ * So above phys_id is always set to -1.
*
* BIOS may define multiple CPU handles even for UP processor.
* For example,
@@ -170,7 +170,7 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
* Processor (CPU3, 0x03, 0x00000410, 0x06) {}
* }
*
- * Ignores apic_id and always returns 0 for the processor
+ * Ignores phys_id and always returns 0 for the processor
* handle with acpi id 0 if nr_cpu_ids is 1.
* This should be the case if SMP tables are not found.
* Return -1 for other CPU's handle.
@@ -178,28 +178,28 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
if (nr_cpu_ids <= 1 && acpi_id == 0)
return acpi_id;
else
- return apic_id;
+ return phys_id;
}

#ifdef CONFIG_SMP
for_each_possible_cpu(i) {
- if (cpu_physical_id(i) == apic_id)
+ if (cpu_physical_id(i) == phys_id)
return i;
}
#else
/* In UP kernel, only processor 0 is valid */
- if (apic_id == 0)
- return apic_id;
+ if (phys_id == 0)
+ return phys_id;
#endif
return -1;
}

int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
{
- int apic_id;
+ int phys_id;

- apic_id = acpi_get_apicid(handle, type, acpi_id);
+ phys_id = acpi_get_phys_id(handle, type, acpi_id);

- return acpi_map_cpuid(apic_id, acpi_id);
+ return acpi_map_cpuid(phys_id, acpi_id);
}
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 3ca9b75..b95dc32 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -196,8 +196,8 @@ struct acpi_processor_flags {
struct acpi_processor {
acpi_handle handle;
u32 acpi_id;
- u32 apic_id;
- u32 id;
+ u32 phys_id; /* CPU hardware ID such as APIC ID for x86 */
+ u32 id; /* CPU logical ID allocated by OS */
u32 pblk;
int performance_platform_limit;
int throttling_platform_limit;
@@ -310,8 +310,8 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
#endif /* CONFIG_CPU_FREQ */

/* in processor_core.c */
-int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
-int acpi_map_cpuid(int apic_id, u32 acpi_id);
+int acpi_get_phys_id(acpi_handle, int type, u32 acpi_id);
+int acpi_map_cpuid(int phys_id, u32 acpi_id);
int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);

/* in processor_pdc.c */
--
1.9.1
Rafael J. Wysocki
2015-01-07 01:50:17 UTC
Permalink
Post by Hanjun Guo
apic_id in MADT table is the CPU hardware id which identify
it self in the system for x86 and ia64, OSPM will use it for
SMP init to map APIC ID to logical cpu number in the early
boot, when the DSDT/SSDT (ACPI namespace) is scanned later, the
ACPI processor driver is probed and the driver will use acpi_id
in DSDT to get the apic_id, then map to the logical cpu number
which is needed by the processor driver.
Before ACPI 5.0, only x86 and ia64 were supported in ACPI spec,
so apic_id is used both in arch code and ACPI core which is
pretty fine. Since ACPI 5.0, ARM is supported by ACPI and
APIC is not available on ARM, this will confuse people when
apic_id is both used by x86 and ARM in one function.
So convert apic_id to phys_id (which is the original meaning)
in ACPI processor dirver to make it arch agnostic, but leave the
arch dependent code unchanged, no functional change.
I've queued up this one and [2/17] for 3.19-rc4 as I promised I'd push these
two for 3.19.
Post by Hanjun Guo
---
drivers/acpi/acpi_processor.c | 21 +++++++++-------
drivers/acpi/processor_core.c | 56 +++++++++++++++++++++----------------------
include/acpi/processor.h | 8 +++----
3 files changed, 44 insertions(+), 41 deletions(-)
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 1fdf5e0..f02b29e 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
acpi_status status;
int ret;
- if (pr->apic_id == -1)
+ if (pr->phys_id == -1)
return -ENODEV;
status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
@@ -180,7 +180,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
cpu_maps_update_begin();
cpu_hotplug_begin();
- ret = acpi_map_lsapic(pr->handle, pr->apic_id, &pr->id);
+ ret = acpi_map_lsapic(pr->handle, pr->phys_id, &pr->id);
if (ret)
goto out;
@@ -215,7 +215,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
struct acpi_processor *pr = acpi_driver_data(device);
- int apic_id, cpu_index, device_declaration = 0;
+ int phys_id, cpu_index, device_declaration = 0;
acpi_status status = AE_OK;
static int cpu0_initialized;
unsigned long long value;
@@ -262,15 +262,18 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->acpi_id = value;
}
- apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
- if (apic_id < 0)
- acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
- pr->apic_id = apic_id;
+ phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id);
+ if (phys_id < 0)
+ acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n");
+ pr->phys_id = phys_id;
- cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
+ cpu_index = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
if (!cpu0_initialized && !acpi_has_cpu_in_madt()) {
cpu0_initialized = 1;
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ /*
+ * Handle UP system running SMP kernel, with no CPU
+ * entry in MADT
+ */
if ((cpu_index == -1) && (num_online_cpus() == 1))
cpu_index = 0;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 342942f..02e4839 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -69,7 +69,7 @@ static int map_madt_entry(int type, u32 acpi_id)
unsigned long madt_end, entry;
static struct acpi_table_madt *madt;
static int read_madt;
- int apic_id = -1;
+ int phys_id = -1; /* CPU hardware ID */
if (!read_madt) {
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
@@ -79,7 +79,7 @@ static int map_madt_entry(int type, u32 acpi_id)
}
if (!madt)
- return apic_id;
+ return phys_id;
entry = (unsigned long)madt;
madt_end = entry + madt->header.length;
@@ -91,18 +91,18 @@ static int map_madt_entry(int type, u32 acpi_id)
struct acpi_subtable_header *header =
(struct acpi_subtable_header *)entry;
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
- if (!map_lapic_id(header, acpi_id, &apic_id))
+ if (!map_lapic_id(header, acpi_id, &phys_id))
break;
} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
- if (!map_x2apic_id(header, type, acpi_id, &apic_id))
+ if (!map_x2apic_id(header, type, acpi_id, &phys_id))
break;
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
- if (!map_lsapic_id(header, type, acpi_id, &apic_id))
+ if (!map_lsapic_id(header, type, acpi_id, &phys_id))
break;
}
entry += header->length;
}
- return apic_id;
+ return phys_id;
}
static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
@@ -110,7 +110,7 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
struct acpi_subtable_header *header;
- int apic_id = -1;
+ int phys_id = -1;
if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
goto exit;
@@ -126,38 +126,38 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
header = (struct acpi_subtable_header *)obj->buffer.pointer;
if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
- map_lapic_id(header, acpi_id, &apic_id);
+ map_lapic_id(header, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
- map_lsapic_id(header, type, acpi_id, &apic_id);
+ map_lsapic_id(header, type, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
- map_x2apic_id(header, type, acpi_id, &apic_id);
+ map_x2apic_id(header, type, acpi_id, &phys_id);
kfree(buffer.pointer);
- return apic_id;
+ return phys_id;
}
-int acpi_get_apicid(acpi_handle handle, int type, u32 acpi_id)
+int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
{
- int apic_id;
+ int phys_id;
- apic_id = map_mat_entry(handle, type, acpi_id);
- if (apic_id == -1)
- apic_id = map_madt_entry(type, acpi_id);
+ phys_id = map_mat_entry(handle, type, acpi_id);
+ if (phys_id == -1)
+ phys_id = map_madt_entry(type, acpi_id);
- return apic_id;
+ return phys_id;
}
-int acpi_map_cpuid(int apic_id, u32 acpi_id)
+int acpi_map_cpuid(int phys_id, u32 acpi_id)
{
#ifdef CONFIG_SMP
int i;
#endif
- if (apic_id == -1) {
+ if (phys_id == -1) {
/*
* On UP processor, there is no _MAT or MADT table.
- * So above apic_id is always set to -1.
+ * So above phys_id is always set to -1.
*
* BIOS may define multiple CPU handles even for UP processor.
* For example,
@@ -170,7 +170,7 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
* Processor (CPU3, 0x03, 0x00000410, 0x06) {}
* }
*
- * Ignores apic_id and always returns 0 for the processor
+ * Ignores phys_id and always returns 0 for the processor
* handle with acpi id 0 if nr_cpu_ids is 1.
* This should be the case if SMP tables are not found.
* Return -1 for other CPU's handle.
@@ -178,28 +178,28 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
if (nr_cpu_ids <= 1 && acpi_id == 0)
return acpi_id;
else
- return apic_id;
+ return phys_id;
}
#ifdef CONFIG_SMP
for_each_possible_cpu(i) {
- if (cpu_physical_id(i) == apic_id)
+ if (cpu_physical_id(i) == phys_id)
return i;
}
#else
/* In UP kernel, only processor 0 is valid */
- if (apic_id == 0)
- return apic_id;
+ if (phys_id == 0)
+ return phys_id;
#endif
return -1;
}
int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
{
- int apic_id;
+ int phys_id;
- apic_id = acpi_get_apicid(handle, type, acpi_id);
+ phys_id = acpi_get_phys_id(handle, type, acpi_id);
- return acpi_map_cpuid(apic_id, acpi_id);
+ return acpi_map_cpuid(phys_id, acpi_id);
}
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 3ca9b75..b95dc32 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -196,8 +196,8 @@ struct acpi_processor_flags {
struct acpi_processor {
acpi_handle handle;
u32 acpi_id;
- u32 apic_id;
- u32 id;
+ u32 phys_id; /* CPU hardware ID such as APIC ID for x86 */
+ u32 id; /* CPU logical ID allocated by OS */
u32 pblk;
int performance_platform_limit;
int throttling_platform_limit;
@@ -310,8 +310,8 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
#endif /* CONFIG_CPU_FREQ */
/* in processor_core.c */
-int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
-int acpi_map_cpuid(int apic_id, u32 acpi_id);
+int acpi_get_phys_id(acpi_handle, int type, u32 acpi_id);
+int acpi_map_cpuid(int phys_id, u32 acpi_id);
int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
/* in processor_pdc.c */
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Hanjun Guo
2015-01-07 09:49:25 UTC
Permalink
Post by Rafael J. Wysocki
Post by Hanjun Guo
apic_id in MADT table is the CPU hardware id which identify
it self in the system for x86 and ia64, OSPM will use it for
SMP init to map APIC ID to logical cpu number in the early
boot, when the DSDT/SSDT (ACPI namespace) is scanned later, the
ACPI processor driver is probed and the driver will use acpi_id
in DSDT to get the apic_id, then map to the logical cpu number
which is needed by the processor driver.
Before ACPI 5.0, only x86 and ia64 were supported in ACPI spec,
so apic_id is used both in arch code and ACPI core which is
pretty fine. Since ACPI 5.0, ARM is supported by ACPI and
APIC is not available on ARM, this will confuse people when
apic_id is both used by x86 and ARM in one function.
So convert apic_id to phys_id (which is the original meaning)
in ACPI processor dirver to make it arch agnostic, but leave the
arch dependent code unchanged, no functional change.
I've queued up this one and [2/17] for 3.19-rc4 as I promised I'd push these
two for 3.19.
Great, thanks a lot. I thought you will queued them for 3.20 :)

Regards
Hanjun
Hanjun Guo
2015-01-04 10:55:04 UTC
Permalink
From: Al Stone <***@linaro.org>

As we want to get ACPI tables to parse and then use the information
for system initialization, we should get the RSDP (Root System
Description Pointer) first, it then locates Extended Root Description
Table (XSDT) which contains all the 64-bit physical address that
pointer to other boot-time tables.

Introduce acpi.c and its related head file in this patch to provide
fundamental needs of extern variables and functions for ACPI core,
and then get boot-time tables as needed.
- asm/acenv.h for arch specific ACPICA environments and
implementation, It is needed unconditionally by ACPI core;
- asm/acpi.h for arch specific variables and functions needed by
ACPI driver core;
- acpi.c for ARM64 related ACPI implementation for ACPI driver
core;

acpi_boot_table_init() is introduced to get RSDP and boot-time tables,
it will be called in setup_arch() before paging_init(), so we should
use eary_memremap() mechanism here to get the RSDP and all the table
pointers.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/include/asm/acenv.h | 18 +++++++++++
arch/arm64/include/asm/acpi.h | 45 +++++++++++++++++++++++++++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/acpi.c | 69 ++++++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/setup.c | 4 +++
5 files changed, 137 insertions(+)
create mode 100644 arch/arm64/include/asm/acenv.h
create mode 100644 arch/arm64/include/asm/acpi.h
create mode 100644 arch/arm64/kernel/acpi.c

diff --git a/arch/arm64/include/asm/acenv.h b/arch/arm64/include/asm/acenv.h
new file mode 100644
index 0000000..b49166f
--- /dev/null
+++ b/arch/arm64/include/asm/acenv.h
@@ -0,0 +1,18 @@
+/*
+ * ARM64 specific ACPICA environments and implementation
+ *
+ * Copyright (C) 2014, Linaro Ltd.
+ * Author: Hanjun Guo <***@linaro.org>
+ * Author: Graeme Gregory <***@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_ACENV_H
+#define _ASM_ACENV_H
+
+/* It is required unconditionally by ACPI core, update it when needed. */
+
+#endif /* _ASM_ACENV_H */
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
new file mode 100644
index 0000000..8b837ab
--- /dev/null
+++ b/arch/arm64/include/asm/acpi.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013-2014, Linaro Ltd.
+ * Author: Al Stone <***@linaro.org>
+ * Author: Graeme Gregory <***@linaro.org>
+ * Author: Hanjun Guo <***@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ */
+
+#ifndef _ASM_ACPI_H
+#define _ASM_ACPI_H
+
+/* Basic configuration for ACPI */
+#ifdef CONFIG_ACPI
+#define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */
+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;
+}
+
+/*
+ * It's used from ACPI core in kdump to boot UP system with SMP kernel,
+ * with this check the ACPI core will not override the CPU index
+ * obtained from GICC with 0 and not print some error message as well.
+ * Since MADT must provide at least one GICC structure for GIC
+ * initialization, CPU will be always available in MADT on ARM64.
+ */
+static inline bool acpi_has_cpu_in_madt(void)
+{
+ return true;
+}
+
+static inline void arch_fix_phys_package_id(int num, u32 slot) { }
+
+#endif /* CONFIG_ACPI */
+
+#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index eaa77ed..8bdc6bd 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -34,6 +34,7 @@ arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
arm64-obj-$(CONFIG_PCI) += pci.o
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
+arm64-obj-$(CONFIG_ACPI) += acpi.o

obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
new file mode 100644
index 0000000..9252f72
--- /dev/null
+++ b/arch/arm64/kernel/acpi.c
@@ -0,0 +1,69 @@
+/*
+ * ARM64 Specific Low-Level ACPI Boot Support
+ *
+ * Copyright (C) 2013-2014, Linaro Ltd.
+ * Author: Al Stone <***@linaro.org>
+ * Author: Graeme Gregory <***@linaro.org>
+ * Author: Hanjun Guo <***@linaro.org>
+ * Author: Tomasz Nowicki <***@linaro.org>
+ * Author: Naresh Bhat <***@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/cpumask.h>
+#include <linux/memblock.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/bootmem.h>
+#include <linux/smp.h>
+
+int acpi_noirq; /* skip ACPI IRQ initialization */
+int acpi_disabled;
+EXPORT_SYMBOL(acpi_disabled);
+
+int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
+EXPORT_SYMBOL(acpi_pci_disabled);
+
+/*
+ * __acpi_map_table() will be called before page_init(), so early_ioremap()
+ * or early_memremap() should be called here to for ACPI table mapping.
+ */
+char *__init __acpi_map_table(unsigned long phys, unsigned long size)
+{
+ if (!phys || !size)
+ return NULL;
+
+ return early_memremap(phys, size);
+}
+
+void __init __acpi_unmap_table(char *map, unsigned long size)
+{
+ if (!map || !size)
+ return;
+
+ early_memunmap(map, size);
+}
+
+/*
+ * 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
+ *
+ * We can parse ACPI boot-time tables such as MADT after
+ * this function is called.
+ */
+void __init acpi_boot_table_init(void)
+{
+ /* If acpi_disabled, bail out */
+ if (acpi_disabled)
+ return;
+
+ /* Initialize the ACPI boot-time table parser. */
+ if (acpi_table_init())
+ disable_acpi();
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index b809911..224a2e6 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

+#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
@@ -398,6 +399,9 @@ void __init setup_arch(char **cmdline_p)
efi_init();
arm64_memblock_init();

+ /* Parse the ACPI tables for possible boot-time configuration */
+ acpi_boot_table_init();
+
paging_init();
request_standard_resources();
--
1.9.1
Hanjun Guo
2015-01-04 10:55:08 UTC
Permalink
Since PCI is not required in ACPI spec and ARM can run without
it, introduce some stub functions to make PCI optional for ACPI,
and make ACPI core run without CONFIG_PCI on ARM64.

When PCI is enabled on ARM64, ACPI core will need some PCI functions
to make it functional, so introduce some empty functions here and
implement it later.

Since ACPI on X86 and IA64 depends on PCI and this patch only makes
PCI optional for ARM64, it will not break anything on X86 and IA64.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/include/asm/pci.h | 6 ++++++
arch/arm64/kernel/pci.c | 28 ++++++++++++++++++++++++++++
drivers/acpi/Makefile | 2 +-
drivers/acpi/internal.h | 5 +++++
include/linux/pci.h | 37 +++++++++++++++++++++++++++----------
5 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
index 872ba93..fded096 100644
--- a/arch/arm64/include/asm/pci.h
+++ b/arch/arm64/include/asm/pci.h
@@ -24,6 +24,12 @@
*/
#define PCI_DMA_BUS_IS_PHYS (0)

+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+ /* no legacy IRQ on arm64 */
+ return -ENODEV;
+}
+
extern int isa_dma_bridge_buggy;

#ifdef CONFIG_PCI
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index ce5836c..42fb195 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -10,6 +10,7 @@
*
*/

+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -68,3 +69,30 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
bus->domain_nr = domain;
}
#endif
+
+/*
+ * raw_pci_read/write - Platform-specific PCI config space access.
+ *
+ * Default empty implementation. Replace with an architecture-specific setup
+ * routine, if necessary.
+ */
+int raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
+{
+ return -EINVAL;
+}
+
+int raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
+{
+ return -EINVAL;
+}
+
+#ifdef CONFIG_ACPI
+/* Root bridge scanning */
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
+{
+ /* TODO: Should be revisited when implementing PCI on ACPI */
+ return NULL;
+}
+#endif
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 39f3ec1..c346011 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -43,7 +43,7 @@ acpi-y += processor_core.o
acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
-acpi-y += pci_root.o pci_link.o pci_irq.o
+acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o
acpi-y += acpi_lpss.o
acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 163e82f..c5ff8ba 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -26,8 +26,13 @@
acpi_status acpi_os_initialize1(void);
int init_acpi_device_notify(void);
int acpi_scan_init(void);
+#ifdef CONFIG_PCI
void acpi_pci_root_init(void);
void acpi_pci_link_init(void);
+#else
+static inline void acpi_pci_root_init(void) {}
+static inline void acpi_pci_link_init(void) {}
+#endif
void acpi_processor_init(void);
void acpi_platform_init(void);
void acpi_pnp_init(void);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 360a966..1476a66 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -564,15 +564,6 @@ struct pci_ops {
int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
};

-/*
- * ACPI needs to be able to access PCI config space before we've done a
- * PCI bus scan and created pci_bus structures.
- */
-int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
- int reg, int len, u32 *val);
-int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
- int reg, int len, u32 val);
-
struct pci_bus_region {
dma_addr_t start;
dma_addr_t end;
@@ -1329,6 +1320,16 @@ typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
unsigned int command_bits, u32 flags);
void pci_register_set_vga_state(arch_set_vga_state_t func);

+/*
+ * ACPI needs to be able to access PCI config space before we've done a
+ * PCI bus scan and created pci_bus structures.
+ */
+int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 *val);
+int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 val);
+void pcibios_penalize_isa_irq(int irq, int active);
+
#else /* CONFIG_PCI is not enabled */

/*
@@ -1430,6 +1431,23 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
unsigned int devfn)
{ return NULL; }

+static inline struct pci_bus *pci_find_bus(int domain, int busnr)
+{ return NULL; }
+
+static inline int pci_bus_write_config_byte(struct pci_bus *bus,
+ unsigned int devfn, int where, u8 val)
+{ return -ENOSYS; }
+
+static inline int raw_pci_read(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 *val)
+{ return -ENOSYS; }
+
+static inline int raw_pci_write(unsigned int domain, unsigned int bus,
+ unsigned int devfn, int reg, int len, u32 val)
+{ return -ENOSYS; }
+
+static inline void pcibios_penalize_isa_irq(int irq, int active) { }
+
static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
@@ -1639,7 +1657,6 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev,
enum pcie_reset_state state);
int pcibios_add_device(struct pci_dev *dev);
void pcibios_release_device(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq, int active);

#ifdef CONFIG_HIBERNATE_CALLBACKS
extern struct dev_pm_ops pcibios_pm_ops;
--
1.9.1
Hanjun Guo
2015-01-04 10:55:09 UTC
Permalink
There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set,
the former signals to the OS that the firmware is PSCI compliant.
The latter selects the appropriate conduit for PSCI calls by
toggling between Hypervisor Calls (HVC) and Secure Monitor Calls
(SMC).

FADT table contains such information, parse FADT to get the flags
for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI
function IDs, which means that only PSCI 0.2+ is supported in ACPI.

At the same time, only ACPI 5.1 or higher verison supports PSCI,
and FADT Major.Minor version was introduced in ACPI 5.1, so we
will check the version and only parse FADT table with version >= 5.1.

If firmware provides ACPI tables with ACPI version less than 5.1,
OS will be messed up with those information and have no way to init
smp and GIC, so disable ACPI if we get an FADT table with version
less that 5.1.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
---
arch/arm64/include/asm/acpi.h | 14 ++++++++
arch/arm64/include/asm/psci.h | 3 +-
arch/arm64/kernel/acpi.c | 31 ++++++++++++++++-
arch/arm64/kernel/psci.c | 78 ++++++++++++++++++++++++++++++-------------
arch/arm64/kernel/setup.c | 8 +++--
5 files changed, 105 insertions(+), 29 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 496c33b..221ff15 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -19,6 +19,18 @@ extern int acpi_disabled;
extern int acpi_noirq;
extern int acpi_pci_disabled;

+/* 1 to indicate PSCI 0.2+ is implemented */
+static inline bool acpi_psci_present(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
+}
+
+/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
+static inline bool acpi_psci_use_hvc(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
+}
+
static inline void disable_acpi(void)
{
acpi_disabled = 1;
@@ -49,6 +61,8 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }

#else
static inline void disable_acpi(void) { }
+static inline bool acpi_psci_present(void) { return false; }
+static inline bool acpi_psci_use_hvc(void) { return false; }
#endif /* CONFIG_ACPI */

#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea..2454bc5 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,7 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H

-int psci_init(void);
+int psci_dt_init(void);
+int psci_acpi_init(void);

#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 39a1655..e713236 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -13,6 +13,8 @@
* published by the Free Software Foundation.
*/

+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/cpumask.h>
@@ -49,10 +51,32 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_memunmap(map, size);
}

+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * Revision in table header is the FADT Major revision,
+ * and there is a minor revision of FADT which was introduced
+ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
+ * to get arm boot flags, or we will disable ACPI.
+ */
+ if (table->revision > 5 ||
+ (table->revision == 5 && fadt->minor_revision >= 1))
+ return 0;
+
+ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
+ table->revision, fadt->minor_revision);
+ disable_acpi();
+
+ return -EINVAL;
+}
+
/*
* 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 revisoin
*
* We can parse ACPI boot-time tables such as MADT after
* this function is called.
@@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void)
return;

/* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
+ if (acpi_table_init()) {
disable_acpi();
+ return;
+ }
+
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
+ pr_err("Can't find FADT or error happened during parsing FADT\n");
}

static int __init parse_acpi(char *arg)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f1dbca7..dbb3945 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@

#define pr_fmt(fmt) "psci: " fmt

+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -24,6 +25,7 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>

+#include <asm/acpi.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}

+static void psci_0_2_set_functions(void)
+{
+ pr_info("Using standard PSCI v0.2 function IDs\n");
+ psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+
+ psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
+ psci_ops.cpu_off = psci_cpu_off;
+
+ psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
+ psci_ops.cpu_on = psci_cpu_on;
+
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
+ psci_ops.migrate = psci_migrate;
+
+ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
+ psci_ops.affinity_info = psci_affinity_info;
+
+ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
+ PSCI_0_2_FN_MIGRATE_INFO_TYPE;
+ psci_ops.migrate_info_type = psci_migrate_info_type;
+
+ arm_pm_restart = psci_sys_reset;
+
+ pm_power_off = psci_sys_poweroff;
+}
+
/*
* PSCI Function IDs for v0.2+ are well defined so use
* standard values.
@@ -337,29 +366,7 @@ static int __init psci_0_2_init(struct device_node *np)
}
}

- pr_info("Using standard PSCI v0.2 function IDs\n");
- psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
- psci_ops.cpu_suspend = psci_cpu_suspend;
-
- psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
- psci_ops.cpu_off = psci_cpu_off;
-
- psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
- psci_ops.cpu_on = psci_cpu_on;
-
- psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
- psci_ops.migrate = psci_migrate;
-
- psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
- psci_ops.affinity_info = psci_affinity_info;
-
- psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
- PSCI_0_2_FN_MIGRATE_INFO_TYPE;
- psci_ops.migrate_info_type = psci_migrate_info_type;
-
- arm_pm_restart = psci_sys_reset;
-
- pm_power_off = psci_sys_poweroff;
+ psci_0_2_set_functions();

out_put_node:
of_node_put(np);
@@ -412,7 +419,7 @@ static const struct of_device_id psci_of_match[] __initconst = {
{},
};

-int __init psci_init(void)
+int __init psci_dt_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
@@ -427,6 +434,29 @@ int __init psci_init(void)
return init_fn(np);
}

+/*
+ * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
+ * explicitly clarified in SBBR
+ */
+int __init psci_acpi_init(void)
+{
+ if (!acpi_psci_present()) {
+ pr_info("is not implemented in ACPI.\n");
+ return -EOPNOTSUPP;
+ }
+
+ pr_info("probing for conduit method from ACPI.\n");
+
+ if (acpi_psci_use_hvc())
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ else
+ invoke_psci_fn = __invoke_psci_fn_smc;
+
+ psci_0_2_set_functions();
+
+ return 0;
+}
+
#ifdef CONFIG_SMP

static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 2534de3..4322be2 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -410,10 +410,12 @@ void __init setup_arch(char **cmdline_p)

efi_idmap_init();

- if (acpi_disabled)
+ if (acpi_disabled) {
unflatten_device_tree();
-
- psci_init();
+ psci_dt_init();
+ } else {
+ psci_acpi_init();
+ }

cpu_read_bootcpu_ops();
#ifdef CONFIG_SMP
--
1.9.1
Lorenzo Pieralisi
2015-01-09 19:04:00 UTC
Permalink
Post by Hanjun Guo
There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set,
the former signals to the OS that the firmware is PSCI compliant.
The latter selects the appropriate conduit for PSCI calls by
toggling between Hypervisor Calls (HVC) and Secure Monitor Calls
(SMC).
FADT table contains such information, parse FADT to get the flags
for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI
function IDs, which means that only PSCI 0.2+ is supported in ACPI.
At the same time, only ACPI 5.1 or higher verison supports PSCI,
and FADT Major.Minor version was introduced in ACPI 5.1, so we
will check the version and only parse FADT table with version >= 5.1.
If firmware provides ACPI tables with ACPI version less than 5.1,
OS will be messed up with those information and have no way to init
smp and GIC, so disable ACPI if we get an FADT table with version
less that 5.1.
I am a bit confused by this log. I understand the problem is that,
for versions predating 5.1, PSCI information is missing. So, I would
say:

"OS will not be able to boot properly owing to missing PSCI bindings
data in the ACPI tables".

Is that the message you want to get across ?
Post by Hanjun Guo
---
arch/arm64/include/asm/acpi.h | 14 ++++++++
arch/arm64/include/asm/psci.h | 3 +-
arch/arm64/kernel/acpi.c | 31 ++++++++++++++++-
arch/arm64/kernel/psci.c | 78 ++++++++++++++++++++++++++++++-------------
arch/arm64/kernel/setup.c | 8 +++--
5 files changed, 105 insertions(+), 29 deletions(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 496c33b..221ff15 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -19,6 +19,18 @@ extern int acpi_disabled;
extern int acpi_noirq;
extern int acpi_pci_disabled;
+/* 1 to indicate PSCI 0.2+ is implemented */
+static inline bool acpi_psci_present(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
+}
+
+/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
+static inline bool acpi_psci_use_hvc(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
+}
+
static inline void disable_acpi(void)
{
acpi_disabled = 1;
@@ -49,6 +61,8 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }
#else
static inline void disable_acpi(void) { }
+static inline bool acpi_psci_present(void) { return false; }
+static inline bool acpi_psci_use_hvc(void) { return false; }
#endif /* CONFIG_ACPI */
#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea..2454bc5 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,7 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
-int psci_init(void);
+int psci_dt_init(void);
+int psci_acpi_init(void);
Is not there a better way to avoid this function dt/acpi duplication ?
Post by Hanjun Guo
#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 39a1655..e713236 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -13,6 +13,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/cpumask.h>
@@ -49,10 +51,32 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_memunmap(map, size);
}
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * Revision in table header is the FADT Major revision,
+ * and there is a minor revision of FADT which was introduced
+ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
+ * to get arm boot flags, or we will disable ACPI.
+ */
+ if (table->revision > 5 ||
+ (table->revision == 5 && fadt->minor_revision >= 1))
+ return 0;
+
+ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
+ table->revision, fadt->minor_revision);
+ disable_acpi();
I would rename this function, function is checking the FADT
revision, make that clear. I think that disable_acpi() should be
called on function return, if it fails.

To make the "acpi disabling" clearer, why not call this function in

psci_acpi_init()

something like:

int __init psci_acpi_init(void)
{

if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) {
pr_err("Can't find FADT or error happened during parsing FADT\n");
disable_acpi();
}
...
}

After all you disable ACPI because you can't retrieve PSCI information,
am I right ?
Post by Hanjun Guo
+
+ return -EINVAL;
+}
+
/*
* 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 revisoin
s/revisoin/revision
Post by Hanjun Guo
*
* We can parse ACPI boot-time tables such as MADT after
* this function is called.
@@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void)
return;
/* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
+ if (acpi_table_init()) {
disable_acpi();
+ return;
+ }
+
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
+ pr_err("Can't find FADT or error happened during parsing FADT\n");
As I said above this is a bit sneaky. It is not clear you are disabling
ACPI when the acpi_table_parse() call fails. Is it not better to move
the revision check in the PSCI ACPI init call ?
Post by Hanjun Guo
}
static int __init parse_acpi(char *arg)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f1dbca7..dbb3945 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -24,6 +25,7 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>
+#include <asm/acpi.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+static void psci_0_2_set_functions(void)
__init ?
Post by Hanjun Guo
+{
+ pr_info("Using standard PSCI v0.2 function IDs\n");
+ psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+
+ psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
+ psci_ops.cpu_off = psci_cpu_off;
+
+ psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
+ psci_ops.cpu_on = psci_cpu_on;
+
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
+ psci_ops.migrate = psci_migrate;
+
+ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
+ psci_ops.affinity_info = psci_affinity_info;
+
+ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
+ PSCI_0_2_FN_MIGRATE_INFO_TYPE;
+ psci_ops.migrate_info_type = psci_migrate_info_type;
+
+ arm_pm_restart = psci_sys_reset;
+
+ pm_power_off = psci_sys_poweroff;
+}
+
/*
* PSCI Function IDs for v0.2+ are well defined so use
* standard values.
@@ -337,29 +366,7 @@ static int __init psci_0_2_init(struct device_node *np)
}
}
- pr_info("Using standard PSCI v0.2 function IDs\n");
- psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
- psci_ops.cpu_suspend = psci_cpu_suspend;
-
- psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
- psci_ops.cpu_off = psci_cpu_off;
-
- psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
- psci_ops.cpu_on = psci_cpu_on;
-
- psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
- psci_ops.migrate = psci_migrate;
-
- psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
- psci_ops.affinity_info = psci_affinity_info;
-
- psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
- PSCI_0_2_FN_MIGRATE_INFO_TYPE;
- psci_ops.migrate_info_type = psci_migrate_info_type;
-
- arm_pm_restart = psci_sys_reset;
-
- pm_power_off = psci_sys_poweroff;
+ psci_0_2_set_functions();
of_node_put(np);
@@ -412,7 +419,7 @@ static const struct of_device_id psci_of_match[] __initconst = {
{},
};
-int __init psci_init(void)
+int __init psci_dt_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
@@ -427,6 +434,29 @@ int __init psci_init(void)
return init_fn(np);
}
+/*
+ * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
+ * explicitly clarified in SBBR
+ */
+int __init psci_acpi_init(void)
+{
+ if (!acpi_psci_present()) {
+ pr_info("is not implemented in ACPI.\n");
+ return -EOPNOTSUPP;
+ }
+
+ pr_info("probing for conduit method from ACPI.\n");
+
+ if (acpi_psci_use_hvc())
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ else
+ invoke_psci_fn = __invoke_psci_fn_smc;
+
+ psci_0_2_set_functions();
+
+ return 0;
As I asked above, is not there a better way to have a common init
function and factor out the acpi/dt paths in it instead of adding
multiple calls in setup_arch() ?

Thanks,
Lorenzo
Post by Hanjun Guo
+}
+
#ifdef CONFIG_SMP
static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 2534de3..4322be2 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -410,10 +410,12 @@ void __init setup_arch(char **cmdline_p)
efi_idmap_init();
- if (acpi_disabled)
+ if (acpi_disabled) {
unflatten_device_tree();
-
- psci_init();
+ psci_dt_init();
+ } else {
+ psci_acpi_init();
+ }
cpu_read_bootcpu_ops();
#ifdef CONFIG_SMP
--
1.9.1
Hanjun Guo
2015-01-12 04:26:41 UTC
Permalink
Post by Lorenzo Pieralisi
Post by Hanjun Guo
There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set,
the former signals to the OS that the firmware is PSCI compliant.
The latter selects the appropriate conduit for PSCI calls by
toggling between Hypervisor Calls (HVC) and Secure Monitor Calls
(SMC).
FADT table contains such information, parse FADT to get the flags
for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI
function IDs, which means that only PSCI 0.2+ is supported in ACPI.
At the same time, only ACPI 5.1 or higher verison supports PSCI,
and FADT Major.Minor version was introduced in ACPI 5.1, so we
will check the version and only parse FADT table with version >= 5.1.
If firmware provides ACPI tables with ACPI version less than 5.1,
OS will be messed up with those information and have no way to init
smp and GIC, so disable ACPI if we get an FADT table with version
less that 5.1.
I am a bit confused by this log. I understand the problem is that,
for versions predating 5.1, PSCI information is missing. So, I would
"OS will not be able to boot properly owing to missing PSCI bindings
data in the ACPI tables".
Is that the message you want to get across ?
Not exactly. PSCI is part of the updates for ACPI 5.1, and more updates
are for GIC (MADT table), without those updates in GIC (MADT table), we
can not get the MPIDR for SMP init, and can not get the right GICC
base_address for GICv2 init too (GICC base_address was there in ACPI 5.0
, but the offset to the start of the structure was changed in ACPI 5.1)
so if we use the ACPI 5.1 OS code to parse ACPI 5.0 firmware table, it
will messed up teh OS boot, not only because of PSCI.

Should I update the Change log here?
Post by Lorenzo Pieralisi
Post by Hanjun Guo
---
arch/arm64/include/asm/acpi.h | 14 ++++++++
arch/arm64/include/asm/psci.h | 3 +-
arch/arm64/kernel/acpi.c | 31 ++++++++++++++++-
arch/arm64/kernel/psci.c | 78 ++++++++++++++++++++++++++++++-------------
arch/arm64/kernel/setup.c | 8 +++--
5 files changed, 105 insertions(+), 29 deletions(-)
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 496c33b..221ff15 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -19,6 +19,18 @@ extern int acpi_disabled;
extern int acpi_noirq;
extern int acpi_pci_disabled;
+/* 1 to indicate PSCI 0.2+ is implemented */
+static inline bool acpi_psci_present(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
+}
+
+/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */
+static inline bool acpi_psci_use_hvc(void)
+{
+ return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
+}
+
static inline void disable_acpi(void)
{
acpi_disabled = 1;
@@ -49,6 +61,8 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }
#else
static inline void disable_acpi(void) { }
+static inline bool acpi_psci_present(void) { return false; }
+static inline bool acpi_psci_use_hvc(void) { return false; }
#endif /* CONFIG_ACPI */
#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
index e5312ea..2454bc5 100644
--- a/arch/arm64/include/asm/psci.h
+++ b/arch/arm64/include/asm/psci.h
@@ -14,6 +14,7 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
-int psci_init(void);
+int psci_dt_init(void);
+int psci_acpi_init(void);
Is not there a better way to avoid this function dt/acpi duplication ?
Post by Hanjun Guo
#endif /* __ASM_PSCI_H */
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 39a1655..e713236 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -13,6 +13,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) "ACPI: " fmt
+
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/cpumask.h>
@@ -49,10 +51,32 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_memunmap(map, size);
}
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * Revision in table header is the FADT Major revision,
+ * and there is a minor revision of FADT which was introduced
+ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
+ * to get arm boot flags, or we will disable ACPI.
+ */
+ if (table->revision > 5 ||
+ (table->revision == 5 && fadt->minor_revision >= 1))
+ return 0;
+
+ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
+ table->revision, fadt->minor_revision);
+ disable_acpi();
I would rename this function, function is checking the FADT
revision, make that clear. I think that disable_acpi() should be
called on function return, if it fails.
To make the "acpi disabling" clearer, why not call this function in
psci_acpi_init()
int __init psci_acpi_init(void)
{
if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) {
pr_err("Can't find FADT or error happened during parsing FADT\n");
disable_acpi();
}
...
}
After all you disable ACPI because you can't retrieve PSCI information,
am I right ?
I think we need to consider two scenes:

- ACPI version less than 5.1, it definitely needs to disable ACPI
because of OS doesn't support that and we don't need to do it;

- if ACPI version is 5.1 or later, and PSCI flags are missing in
FADT table, I think we still can boot the OS with single core (
if Parking Protocol is still missing) and print some warning message
instead (you can refer to patch 10/17). just disable ACPI may lead
to boot failure.

Does it make sense?
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+
+ return -EINVAL;
+}
+
/*
* 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 revisoin
s/revisoin/revision
Good catch, will update it.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
*
* We can parse ACPI boot-time tables such as MADT after
* this function is called.
@@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void)
return;
/* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
+ if (acpi_table_init()) {
disable_acpi();
+ return;
+ }
+
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
+ pr_err("Can't find FADT or error happened during parsing FADT\n");
As I said above this is a bit sneaky. It is not clear you are disabling
ACPI when the acpi_table_parse() call fails. Is it not better to move
the revision check in the PSCI ACPI init call ?
please refer to the comments above.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
}
static int __init parse_acpi(char *arg)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f1dbca7..dbb3945 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -24,6 +25,7 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>
+#include <asm/acpi.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+static void psci_0_2_set_functions(void)
__init ?
Yes, it only called by __init function, can be defined as
__init too.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+{
+ pr_info("Using standard PSCI v0.2 function IDs\n");
+ psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
+ psci_ops.cpu_suspend = psci_cpu_suspend;
+
+ psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
+ psci_ops.cpu_off = psci_cpu_off;
+
+ psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
+ psci_ops.cpu_on = psci_cpu_on;
+
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
+ psci_ops.migrate = psci_migrate;
+
+ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
+ psci_ops.affinity_info = psci_affinity_info;
+
+ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
+ PSCI_0_2_FN_MIGRATE_INFO_TYPE;
+ psci_ops.migrate_info_type = psci_migrate_info_type;
+
+ arm_pm_restart = psci_sys_reset;
+
+ pm_power_off = psci_sys_poweroff;
+}
+
/*
* PSCI Function IDs for v0.2+ are well defined so use
* standard values.
@@ -337,29 +366,7 @@ static int __init psci_0_2_init(struct device_node *np)
}
}
- pr_info("Using standard PSCI v0.2 function IDs\n");
- psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
- psci_ops.cpu_suspend = psci_cpu_suspend;
-
- psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
- psci_ops.cpu_off = psci_cpu_off;
-
- psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
- psci_ops.cpu_on = psci_cpu_on;
-
- psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
- psci_ops.migrate = psci_migrate;
-
- psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
- psci_ops.affinity_info = psci_affinity_info;
-
- psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
- PSCI_0_2_FN_MIGRATE_INFO_TYPE;
- psci_ops.migrate_info_type = psci_migrate_info_type;
-
- arm_pm_restart = psci_sys_reset;
-
- pm_power_off = psci_sys_poweroff;
+ psci_0_2_set_functions();
of_node_put(np);
@@ -412,7 +419,7 @@ static const struct of_device_id psci_of_match[] __initconst = {
{},
};
-int __init psci_init(void)
+int __init psci_dt_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
@@ -427,6 +434,29 @@ int __init psci_init(void)
return init_fn(np);
}
+/*
+ * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
+ * explicitly clarified in SBBR
+ */
+int __init psci_acpi_init(void)
+{
+ if (!acpi_psci_present()) {
+ pr_info("is not implemented in ACPI.\n");
+ return -EOPNOTSUPP;
+ }
+
+ pr_info("probing for conduit method from ACPI.\n");
+
+ if (acpi_psci_use_hvc())
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ else
+ invoke_psci_fn = __invoke_psci_fn_smc;
+
+ psci_0_2_set_functions();
+
+ return 0;
As I asked above, is not there a better way to have a common init
function and factor out the acpi/dt paths in it instead of adding
multiple calls in setup_arch() ?
We tried, but it introduced more complexity, so Catalin suggested
that adding multiple calls in setup_arch (which the way he preferred).

Thanks
Hanjun
Lorenzo Pieralisi
2015-01-12 11:41:41 UTC
Permalink
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set,
the former signals to the OS that the firmware is PSCI compliant.
The latter selects the appropriate conduit for PSCI calls by
toggling between Hypervisor Calls (HVC) and Secure Monitor Calls
(SMC).
FADT table contains such information, parse FADT to get the flags
for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI
function IDs, which means that only PSCI 0.2+ is supported in ACPI.
At the same time, only ACPI 5.1 or higher verison supports PSCI,
and FADT Major.Minor version was introduced in ACPI 5.1, so we
will check the version and only parse FADT table with version >= 5.1.
If firmware provides ACPI tables with ACPI version less than 5.1,
OS will be messed up with those information and have no way to init
smp and GIC, so disable ACPI if we get an FADT table with version
less that 5.1.
I am a bit confused by this log. I understand the problem is that,
for versions predating 5.1, PSCI information is missing. So, I would
"OS will not be able to boot properly owing to missing PSCI bindings
data in the ACPI tables".
Is that the message you want to get across ?
Not exactly. PSCI is part of the updates for ACPI 5.1, and more updates
are for GIC (MADT table), without those updates in GIC (MADT table), we
can not get the MPIDR for SMP init, and can not get the right GICC
base_address for GICv2 init too (GICC base_address was there in ACPI 5.0
, but the offset to the start of the structure was changed in ACPI 5.1)
so if we use the ACPI 5.1 OS code to parse ACPI 5.0 firmware table, it
will messed up teh OS boot, not only because of PSCI.
Should I update the Change log here?
Thanks for the explanation.

So basically this means you can't boot arm64 ACPI with table versions
predating 5.1, right ? Or (version >= 5.1) is a requirement only if
PSCI is the enable method ?

It is what I thought, basically IIUC you are merging two patches in one.
This patch is supposed to get PSCI flags from ACPI tables (ie init PSCI from
ACPI tables), checking the version (which of course is a prerequisite
for parsing PSCI flags too) should have been done in a separate patch,
possibly squashed with the ACPI tables initialization.

I think you should split the patch and be done with that.

[...]
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * Revision in table header is the FADT Major revision,
+ * and there is a minor revision of FADT which was introduced
+ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
+ * to get arm boot flags, or we will disable ACPI.
+ */
+ if (table->revision > 5 ||
+ (table->revision == 5 && fadt->minor_revision >= 1))
+ return 0;
+
+ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
+ table->revision, fadt->minor_revision);
+ disable_acpi();
I would rename this function, function is checking the FADT
revision, make that clear. I think that disable_acpi() should be
called on function return, if it fails.
To make the "acpi disabling" clearer, why not call this function in
psci_acpi_init()
int __init psci_acpi_init(void)
{
if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) {
pr_err("Can't find FADT or error happened during parsing FADT\n");
disable_acpi();
}
...
}
After all you disable ACPI because you can't retrieve PSCI information,
am I right ?
- ACPI version less than 5.1, it definitely needs to disable ACPI
because of OS doesn't support that and we don't need to do it;
Patch 1. Actually, why can't you carry out the check at acpi tables
init instead of executing the check when PSCI is initialized ?

Is version >5.1 a requirement only if booting with PSCI ? It does not
seem so from what you said above.
Post by Hanjun Guo
- if ACPI version is 5.1 or later, and PSCI flags are missing in
FADT table, I think we still can boot the OS with single core (
if Parking Protocol is still missing) and print some warning message
instead (you can refer to patch 10/17). just disable ACPI may lead
to boot failure.
And patch 2, which is what this patch was devised for, to initialize
PSCI from ACPI tables.
Post by Hanjun Guo
Does it make sense?
Yes, that's why this patch should be split, because it is implementing two
pieces of functionality at once.

Put it differently, checking the version is a requirement that goes beyond
PSCI, as you described above, I do not see why you want to merge the
version check and PSCI init together, it obfuscates.
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+
+ return -EINVAL;
+}
+
/*
* 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 revisoin
s/revisoin/revision
Good catch, will update it.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
*
* We can parse ACPI boot-time tables such as MADT after
* this function is called.
@@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void)
return;
/* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
+ if (acpi_table_init()) {
disable_acpi();
+ return;
+ }
+
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
+ pr_err("Can't find FADT or error happened during parsing FADT\n");
As I said above this is a bit sneaky. It is not clear you are disabling
ACPI when the acpi_table_parse() call fails. Is it not better to move
the revision check in the PSCI ACPI init call ?
please refer to the comments above.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
}
static int __init parse_acpi(char *arg)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f1dbca7..dbb3945 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -24,6 +25,7 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>
+#include <asm/acpi.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+static void psci_0_2_set_functions(void)
__init ?
Yes, it only called by __init function, can be defined as
__init too.
It can and should :)

[...]
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
-int __init psci_init(void)
+int __init psci_dt_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
@@ -427,6 +434,29 @@ int __init psci_init(void)
return init_fn(np);
}
+/*
+ * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
+ * explicitly clarified in SBBR
+ */
+int __init psci_acpi_init(void)
+{
+ if (!acpi_psci_present()) {
+ pr_info("is not implemented in ACPI.\n");
+ return -EOPNOTSUPP;
+ }
+
+ pr_info("probing for conduit method from ACPI.\n");
+
+ if (acpi_psci_use_hvc())
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ else
+ invoke_psci_fn = __invoke_psci_fn_smc;
+
+ psci_0_2_set_functions();
+
+ return 0;
As I asked above, is not there a better way to have a common init
function and factor out the acpi/dt paths in it instead of adding
multiple calls in setup_arch() ?
We tried, but it introduced more complexity, so Catalin suggested
that adding multiple calls in setup_arch (which the way he preferred).
I missed that sorry, I will go back to previous threads and check.

Thanks,
Lorenzo
Hanjun Guo
2015-01-13 06:54:19 UTC
Permalink
Post by Lorenzo Pieralisi
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
There are two flags: PSCI_COMPLIANT and PSCI_USE_HVC. When set,
the former signals to the OS that the firmware is PSCI compliant.
The latter selects the appropriate conduit for PSCI calls by
toggling between Hypervisor Calls (HVC) and Secure Monitor Calls
(SMC).
FADT table contains such information, parse FADT to get the flags
for PSCI init. Since ACPI 5.1 doesn't support self defined PSCI
function IDs, which means that only PSCI 0.2+ is supported in ACPI.
At the same time, only ACPI 5.1 or higher verison supports PSCI,
and FADT Major.Minor version was introduced in ACPI 5.1, so we
will check the version and only parse FADT table with version >= 5.1.
If firmware provides ACPI tables with ACPI version less than 5.1,
OS will be messed up with those information and have no way to init
smp and GIC, so disable ACPI if we get an FADT table with version
less that 5.1.
I am a bit confused by this log. I understand the problem is that,
for versions predating 5.1, PSCI information is missing. So, I would
"OS will not be able to boot properly owing to missing PSCI bindings
data in the ACPI tables".
Is that the message you want to get across ?
Not exactly. PSCI is part of the updates for ACPI 5.1, and more updates
are for GIC (MADT table), without those updates in GIC (MADT table), we
can not get the MPIDR for SMP init, and can not get the right GICC
base_address for GICv2 init too (GICC base_address was there in ACPI 5.0
, but the offset to the start of the structure was changed in ACPI 5.1)
so if we use the ACPI 5.1 OS code to parse ACPI 5.0 firmware table, it
will messed up teh OS boot, not only because of PSCI.
Should I update the Change log here?
Thanks for the explanation.
So basically this means you can't boot arm64 ACPI with table versions
predating 5.1, right ?
Yes, it is, sorry I didn't describe it clearly in the change log.
Post by Lorenzo Pieralisi
Or (version >= 5.1) is a requirement only if
PSCI is the enable method ?
It is what I thought, basically IIUC you are merging two patches in one.
This patch is supposed to get PSCI flags from ACPI tables (ie init PSCI from
ACPI tables), checking the version (which of course is a prerequisite
for parsing PSCI flags too) should have been done in a separate patch,
possibly squashed with the ACPI tables initialization.
I think you should split the patch and be done with that.
[...]
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
+{
+ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
+
+ /*
+ * Revision in table header is the FADT Major revision,
+ * and there is a minor revision of FADT which was introduced
+ * by ACPI 5.1, we only deal with ACPI 5.1 or newer revision
+ * to get arm boot flags, or we will disable ACPI.
+ */
+ if (table->revision > 5 ||
+ (table->revision == 5 && fadt->minor_revision >= 1))
+ return 0;
+
+ pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
+ table->revision, fadt->minor_revision);
+ disable_acpi();
I would rename this function, function is checking the FADT
revision, make that clear. I think that disable_acpi() should be
called on function return, if it fails.
To make the "acpi disabling" clearer, why not call this function in
psci_acpi_init()
int __init psci_acpi_init(void)
{
if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) {
pr_err("Can't find FADT or error happened during parsing FADT\n");
disable_acpi();
}
...
}
After all you disable ACPI because you can't retrieve PSCI information,
am I right ?
- ACPI version less than 5.1, it definitely needs to disable ACPI
because of OS doesn't support that and we don't need to do it;
Patch 1. Actually, why can't you carry out the check at acpi tables
init instead of executing the check when PSCI is initialized ?
Is version >5.1 a requirement only if booting with PSCI ? It does not
seem so from what you said above.
Post by Hanjun Guo
- if ACPI version is 5.1 or later, and PSCI flags are missing in
FADT table, I think we still can boot the OS with single core (
if Parking Protocol is still missing) and print some warning message
instead (you can refer to patch 10/17). just disable ACPI may lead
to boot failure.
And patch 2, which is what this patch was devised for, to initialize
PSCI from ACPI tables.
Post by Hanjun Guo
Does it make sense?
Yes, that's why this patch should be split, because it is implementing two
pieces of functionality at once.
Put it differently, checking the version is a requirement that goes beyond
PSCI, as you described above, I do not see why you want to merge the
version check and PSCI init together, it obfuscates.
ok, make sense to me, I will split this patch into two, and update
the comments/change log to make it explicit.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
Post by Lorenzo Pieralisi
Post by Hanjun Guo
+
+ return -EINVAL;
+}
+
/*
* 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 revisoin
s/revisoin/revision
Good catch, will update it.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
*
* We can parse ACPI boot-time tables such as MADT after
* this function is called.
@@ -64,8 +88,13 @@ void __init acpi_boot_table_init(void)
return;
/* Initialize the ACPI boot-time table parser. */
- if (acpi_table_init())
+ if (acpi_table_init()) {
disable_acpi();
+ return;
+ }
+
+ if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt))
+ pr_err("Can't find FADT or error happened during parsing FADT\n");
As I said above this is a bit sneaky. It is not clear you are disabling
ACPI when the acpi_table_parse() call fails. Is it not better to move
the revision check in the PSCI ACPI init call ?
please refer to the comments above.
Post by Lorenzo Pieralisi
Post by Hanjun Guo
}
static int __init parse_acpi(char *arg)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index f1dbca7..dbb3945 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -15,6 +15,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
@@ -24,6 +25,7 @@
#include <linux/slab.h>
#include <uapi/linux/psci.h>
+#include <asm/acpi.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
#include <asm/errno.h>
@@ -304,6 +306,33 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+static void psci_0_2_set_functions(void)
__init ?
Yes, it only called by __init function, can be defined as
__init too.
It can and should :)
I will update in next version :)

Thanks
Hanjun
Hanjun Guo
2015-01-04 10:55:10 UTC
Permalink
When MADT is parsed, print GIC information to make the boot
log look pretty:

ACPI: GICC (acpi_id[0x0000] address[00000000e112f000] MPIDR[0x0] enabled)
ACPI: GICC (acpi_id[0x0001] address[00000000e112f000] MPIDR[0x1] enabled)
...
ACPI: GICC (acpi_id[0x0201] address[00000000e112f000] MPIDR[0x201] enabled)

These information will be very helpful to bring up early systems to
see if acpi_id and MPIDR are matched or not as spec defined.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
---
drivers/acpi/tables.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)

diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 93b8152..42d314f 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -183,6 +183,49 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
break;

+ case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
+ {
+ struct acpi_madt_generic_interrupt *p =
+ (struct acpi_madt_generic_interrupt *)header;
+ pr_info("GICC (acpi_id[0x%04x] address[%p] MPIDR[0x%llx] %s)\n",
+ p->uid, (void *)(unsigned long)p->base_address,
+ p->arm_mpidr,
+ (p->flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
+
+ }
+ break;
+
+ case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
+ {
+ struct acpi_madt_generic_distributor *p =
+ (struct acpi_madt_generic_distributor *)header;
+ pr_info("GIC Distributor (gic_id[0x%04x] address[%p] gsi_base[%d])\n",
+ p->gic_id,
+ (void *)(unsigned long)p->base_address,
+ p->global_irq_base);
+ }
+ break;
+
+ case ACPI_MADT_TYPE_GENERIC_MSI_FRAME:
+ {
+ struct acpi_madt_generic_msi_frame *p =
+ (struct acpi_madt_generic_msi_frame *)header;
+ pr_info("GIC MSI Frame (msi_fame_id[%d] address[%p])\n",
+ p->msi_frame_id,
+ (void *)(unsigned long)p->base_address);
+ }
+ break;
+
+ case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR:
+ {
+ struct acpi_madt_generic_redistributor *p =
+ (struct acpi_madt_generic_redistributor *)header;
+ pr_info("GIC Redistributor (address[%p] region_size[0x%x])\n",
+ (void *)(unsigned long)p->base_address,
+ p->length);
+ }
+ break;
+
default:
pr_warn("Found unsupported MADT entry (type = 0x%x)\n",
header->type);
--
1.9.1
Hanjun Guo
2015-01-04 10:55:11 UTC
Permalink
MADT contains the information for MPIDR which is essential for
SMP initialization, parse the GIC cpu interface structures to
get the MPIDR value and map it to cpu_logical_map(), and add
enabled cpu with valid MPIDR into cpu_possible_map.

ACPI 5.1 only has two explicit methods to boot up SMP, PSCI and
Parking protocol, but the Parking protocol is only specified for
ARMv7 now, so make PSCI as the only way for the SMP boot protocol
before some updates for the ACPI spec or the Parking protocol spec.

Parking protocol patches for SMP boot will be sent to upstream when
the new version of Parking protocol is ready.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
---
arch/arm64/include/asm/acpi.h | 2 +
arch/arm64/include/asm/cpu_ops.h | 1 +
arch/arm64/include/asm/smp.h | 5 +-
arch/arm64/kernel/acpi.c | 150 ++++++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/cpu_ops.c | 7 +-
arch/arm64/kernel/setup.c | 7 +-
arch/arm64/kernel/smp.c | 2 +-
7 files changed, 165 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index 221ff15..c82d4a1 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -58,11 +58,13 @@ static inline bool acpi_has_cpu_in_madt(void)
}

static inline void arch_fix_phys_package_id(int num, u32 slot) { }
+void __init acpi_smp_init_cpus(void);

#else
static inline void disable_acpi(void) { }
static inline bool acpi_psci_present(void) { return false; }
static inline bool acpi_psci_use_hvc(void) { return false; }
+static inline void acpi_smp_init_cpus(void) { }
#endif /* CONFIG_ACPI */

#endif /*_ASM_ACPI_H*/
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h
index 6f8e2ef..5615970 100644
--- a/arch/arm64/include/asm/cpu_ops.h
+++ b/arch/arm64/include/asm/cpu_ops.h
@@ -66,5 +66,6 @@ struct cpu_operations {
extern const struct cpu_operations *cpu_ops[NR_CPUS];
int __init cpu_read_ops(struct device_node *dn, int cpu);
void __init cpu_read_bootcpu_ops(void);
+const struct cpu_operations *cpu_get_ops(const char *name);

#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 780f82c..bf22650 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -39,9 +39,10 @@ extern void show_ipi_list(struct seq_file *p, int prec);
extern void handle_IPI(int ipinr, struct pt_regs *regs);

/*
- * Setup the set of possible CPUs (via set_cpu_possible)
+ * Discover the set of possible CPUs and determine their
+ * SMP operations.
*/
-extern void smp_init_cpus(void);
+extern void of_smp_init_cpus(void);

/*
* Provide a function to raise an IPI cross call on CPUs in callmap.
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index e713236..c01bf7f 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -24,6 +24,10 @@
#include <linux/bootmem.h>
#include <linux/smp.h>

+#include <asm/smp_plat.h>
+#include <asm/cputype.h>
+#include <asm/cpu_ops.h>
+
int acpi_noirq; /* skip ACPI IRQ initialization */
int acpi_disabled;
EXPORT_SYMBOL(acpi_disabled);
@@ -31,6 +35,8 @@ EXPORT_SYMBOL(acpi_disabled);
int acpi_pci_disabled; /* skip ACPI PCI scan and IRQ initialization */
EXPORT_SYMBOL(acpi_pci_disabled);

+static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */
+
/*
* __acpi_map_table() will be called before page_init(), so early_ioremap()
* or early_memremap() should be called here to for ACPI table mapping.
@@ -51,6 +57,134 @@ void __init __acpi_unmap_table(char *map, unsigned long size)
early_memunmap(map, size);
}

+/**
+ * acpi_map_gic_cpu_interface - generates a logical cpu number
+ * and map to MPIDR represented by GICC structure
+ * @mpidr: CPU's hardware id to register, MPIDR represented in MADT
+ * @enabled: this cpu is enabled or not
+ *
+ * Returns the logical cpu number which maps to MPIDR
+ */
+static int acpi_map_gic_cpu_interface(u64 mpidr, u8 enabled)
+{
+ int cpu;
+
+ if (mpidr == INVALID_HWID) {
+ pr_info("Skip MADT cpu entry with invalid MPIDR\n");
+ return -EINVAL;
+ }
+
+ total_cpus++;
+ if (!enabled)
+ return -EINVAL;
+
+ if (enabled_cpus >= NR_CPUS) {
+ pr_warn("NR_CPUS limit of %d reached, Processor %d/0x%llx ignored.\n",
+ NR_CPUS, total_cpus, mpidr);
+ return -EINVAL;
+ }
+
+ /* No need to check duplicate MPIDRs for the first CPU */
+ if (enabled_cpus) {
+ /*
+ * Duplicate MPIDRs are a recipe for disaster. Scan
+ * all initialized entries and check for
+ * duplicates. If any is found just ignore the CPU.
+ */
+ for_each_possible_cpu(cpu) {
+ if (cpu_logical_map(cpu) == mpidr) {
+ pr_err("Firmware bug, duplicate CPU MPIDR: 0x%llx in MADT\n",
+ mpidr);
+ return -EINVAL;
+ }
+ }
+
+ /* allocate a logical cpu id for the new comer */
+ cpu = cpumask_next_zero(-1, cpu_possible_mask);
+ } else {
+ /*
+ * First GICC entry must be BSP as ACPI spec said
+ * in section 5.2.12.15
+ */
+ if (cpu_logical_map(0) != mpidr) {
+ pr_err("First GICC entry with MPIDR 0x%llx is not BSP\n",
+ mpidr);
+ return -EINVAL;
+ }
+
+ /*
+ * boot_cpu_init() already hold bit 0 in cpu_present_mask
+ * for BSP, no need to allocate again.
+ */
+ cpu = 0;
+ }
+
+ /* CPU 0 was already initialized */
+ if (cpu) {
+ cpu_ops[cpu] = cpu_get_ops(acpi_psci_present() ? "psci" : NULL);
+ if (!cpu_ops[cpu])
+ return -EINVAL;
+
+ if (cpu_ops[cpu]->cpu_init(NULL, cpu))
+ return -EOPNOTSUPP;
+
+ /* map the logical cpu id to cpu MPIDR */
+ cpu_logical_map(cpu) = mpidr;
+
+ set_cpu_possible(cpu, true);
+ } else {
+ /* get cpu0's ops, no need to return if ops is null */
+ cpu_ops[0] = cpu_get_ops(acpi_psci_present() ? "psci" : NULL);
+ }
+
+ enabled_cpus++;
+ return cpu;
+}
+
+static int __init
+acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *processor;
+
+ processor = (struct acpi_madt_generic_interrupt *)header;
+
+ if (BAD_MADT_ENTRY(processor, end))
+ return -EINVAL;
+
+ acpi_table_print_madt_entry(header);
+
+ acpi_map_gic_cpu_interface(processor->arm_mpidr & MPIDR_HWID_BITMASK,
+ processor->flags & ACPI_MADT_ENABLED);
+
+ return 0;
+}
+
+/* Parse GIC cpu interface entries in MADT for SMP init */
+void __init acpi_smp_init_cpus(void)
+{
+ int count;
+
+ /*
+ * do a partial walk of MADT to determine how many CPUs
+ * we have including disabled CPUs, and get information
+ * we need for SMP init
+ */
+ count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
+ acpi_parse_gic_cpu_interface, 0);
+
+ if (!count) {
+ pr_err("No GIC CPU interface entries present\n");
+ return;
+ } else if (count < 0) {
+ pr_err("Error parsing GIC CPU interface entry\n");
+ return;
+ }
+
+ /* Make boot-up look pretty */
+ pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
+}
+
static int __init acpi_parse_fadt(struct acpi_table_header *table)
{
struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
@@ -62,8 +196,20 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
* to get arm boot flags, or we will disable ACPI.
*/
if (table->revision > 5 ||
- (table->revision == 5 && fadt->minor_revision >= 1))
- return 0;
+ (table->revision == 5 && fadt->minor_revision >= 1)) {
+ /*
+ * ACPI 5.1 only has two explicit methods to boot up SMP,
+ * PSCI and Parking protocol, but the Parking protocol is
+ * only specified for ARMv7 now, so make PSCI as the only
+ * way for the SMP boot protocol before some updates for
+ * the ACPI spec or the Parking protocol spec.
+ */
+ if (acpi_psci_present())
+ return 0;
+
+ pr_warn("No PSCI support, will not bring up secondary CPUs\n");
+ return -EOPNOTSUPP;
+ }

pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n",
table->revision, fadt->minor_revision);
diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c
index cce9524..1ea7b9f 100644
--- a/arch/arm64/kernel/cpu_ops.c
+++ b/arch/arm64/kernel/cpu_ops.c
@@ -27,7 +27,7 @@ extern const struct cpu_operations cpu_psci_ops;

const struct cpu_operations *cpu_ops[NR_CPUS];

-static const struct cpu_operations *supported_cpu_ops[] __initconst = {
+static const struct cpu_operations *supported_cpu_ops[] = {
#ifdef CONFIG_SMP
&smp_spin_table_ops,
#endif
@@ -35,10 +35,13 @@ static const struct cpu_operations *supported_cpu_ops[] __initconst = {
NULL,
};

-static const struct cpu_operations * __init cpu_get_ops(const char *name)
+const struct cpu_operations *cpu_get_ops(const char *name)
{
const struct cpu_operations **ops = supported_cpu_ops;

+ if (!name)
+ return NULL;
+
while (*ops) {
if (!strcmp(name, (*ops)->name))
return *ops;
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 4322be2..2328467 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -413,13 +413,16 @@ void __init setup_arch(char **cmdline_p)
if (acpi_disabled) {
unflatten_device_tree();
psci_dt_init();
+ cpu_read_bootcpu_ops();
+#ifdef CONFIG_SMP
+ of_smp_init_cpus();
+#endif
} else {
psci_acpi_init();
+ acpi_smp_init_cpus();
}

- cpu_read_bootcpu_ops();
#ifdef CONFIG_SMP
- smp_init_cpus();
smp_build_mpidr_hash();
#endif

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 7ae6ee0..5aaf5a4 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -323,7 +323,7 @@ void __init smp_prepare_boot_cpu(void)
* cpu logical map array containing MPIDR values related to logical
* cpus. Assumes that cpu_logical_map(0) has already been initialized.
*/
-void __init smp_init_cpus(void)
+void __init of_smp_init_cpus(void)
{
struct device_node *dn = NULL;
unsigned int i, cpu = 1;
--
1.9.1
Hanjun Guo
2015-01-04 10:55:12 UTC
Permalink
Introduce a new function map_gicc_mpidr() to allow MPIDRs to be obtained
from the GICC Structure introduced by ACPI 5.1.

MPIDR is the CPU hardware ID as local APIC ID on x86 platform, so we use
MPIDR not the GIC CPU interface ID to identify CPUs.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/include/asm/acpi.h | 29 +++++++++++++++++++++++++++++
arch/arm64/kernel/acpi.c | 1 -
drivers/acpi/processor_core.c | 37 +++++++++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index c82d4a1..639bb2a 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -12,6 +12,8 @@
#ifndef _ASM_ACPI_H
#define _ASM_ACPI_H

+#include <asm/smp_plat.h>
+
/* Basic configuration for ACPI */
#ifdef CONFIG_ACPI
#define acpi_strict 1 /* No out-of-spec workarounds on ARM64 */
@@ -45,6 +47,33 @@ static inline void enable_acpi(void)
acpi_noirq = 0;
}

+/* MPIDR value provided in GICC structure is 64 bits, but the
+ * existing apic_id (CPU hardware ID) using in acpi processor
+ * driver is 32-bit, to conform to the same datatype we need
+ * to repack the GICC structure MPIDR.
+ *
+ * Only 32 bits of MPIDR are used:
+ *
+ * Bits [0:7] Aff0;
+ * Bits [8:15] Aff1;
+ * Bits [16:23] Aff2;
+ * Bits [32:39] Aff3;
+ */
+static inline u32 pack_mpidr(u64 mpidr)
+{
+ return (u32) ((mpidr & 0xff00000000) >> 8) | mpidr;
+}
+
+/*
+ * 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.
+ *
+ * cpu_logical_map(cpu) is the mapping of MPIDR and the logical cpu,
+ * and MPIDR is the cpu hardware ID we needed to pack.
+ */
+#define cpu_physical_id(cpu) pack_mpidr(cpu_logical_map(cpu))
+
/*
* It's used from ACPI core in kdump to boot UP system with SMP kernel,
* with this check the ACPI core will not override the CPU index
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index c01bf7f..e8bb9eb 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -24,7 +24,6 @@
#include <linux/bootmem.h>
#include <linux/smp.h>

-#include <asm/smp_plat.h>
#include <asm/cputype.h>
#include <asm/cpu_ops.h>

diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 02e4839..e634b14 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -64,6 +64,38 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
return 0;
}

+/*
+ * On ARM platform, MPIDR value is the hardware ID as apic ID
+ * on Intel platforms
+ */
+static int map_gicc_mpidr(struct acpi_subtable_header *entry,
+ int device_declaration, u32 acpi_id, int *mpidr)
+{
+ struct acpi_madt_generic_interrupt *gicc =
+ container_of(entry, struct acpi_madt_generic_interrupt, header);
+
+ if (!(gicc->flags & ACPI_MADT_ENABLED))
+ return -ENODEV;
+
+ /* In the GIC interrupt model, logical processors are
+ * required to have a Processor Device object in the DSDT,
+ * so we should check device_declaration here
+ */
+ if (device_declaration && (gicc->uid == acpi_id)) {
+ /*
+ * Only bits [0:7] Aff0, bits [8:15] Aff1, bits [16:23] Aff2
+ * and bits [32:39] Aff3 are meaningful, so pack the Affx
+ * fields into a single 32 bit identifier to accommodate the
+ * acpi processor drivers.
+ */
+ *mpidr = ((gicc->arm_mpidr & 0xff00000000) >> 8)
+ | gicc->arm_mpidr;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int map_madt_entry(int type, u32 acpi_id)
{
unsigned long madt_end, entry;
@@ -99,6 +131,9 @@ static int map_madt_entry(int type, u32 acpi_id)
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
if (!map_lsapic_id(header, type, acpi_id, &phys_id))
break;
+ } else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
+ if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
+ break;
}
entry += header->length;
}
@@ -131,6 +166,8 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
map_lsapic_id(header, type, acpi_id, &phys_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
map_x2apic_id(header, type, acpi_id, &phys_id);
+ else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
+ map_gicc_mpidr(header, type, acpi_id, &phys_id);

exit:
kfree(buffer.pointer);
--
1.9.1
Hanjun Guo
2015-01-04 10:55:13 UTC
Permalink
Introduce ACPI_IRQ_MODEL_GIC which is needed for ARM64 as GIC is
used, and then register device's gsi with the core IRQ subsystem.

acpi_register_gsi() is similar to DT based irq_of_parse_and_map(),
since gsi is unique in the system, so use hwirq number directly
for the mapping.

Originally-by: Amit Daniel Kachhap <***@samsung.com>
Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/kernel/acpi.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/bus.c | 3 ++
include/linux/acpi.h | 1 +
3 files changed, 77 insertions(+)

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index e8bb9eb..d6d83ea 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -37,6 +37,12 @@ EXPORT_SYMBOL(acpi_pci_disabled);
static int enabled_cpus; /* Processors (GICC) with enabled flag in MADT */

/*
+ * Since we're on ARM, the default interrupt routing model
+ * clearly has to be GIC.
+ */
+enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_GIC;
+
+/*
* __acpi_map_table() will be called before page_init(), so early_ioremap()
* or early_memremap() should be called here to for ACPI table mapping.
*/
@@ -184,6 +190,73 @@ void __init acpi_smp_init_cpus(void)
pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus);
}

+int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
+{
+ *irq = irq_find_mapping(NULL, gsi);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
+
+/*
+ * success: return IRQ number (>0)
+ * failure: return =< 0
+ */
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+{
+ unsigned int irq;
+ unsigned int irq_type;
+
+ /*
+ * ACPI have no bindings to indicate SPI or PPI, so we
+ * use different mappings from DT in ACPI.
+ *
+ * For FDT
+ * PPI interrupt: in the range [0, 15];
+ * SPI interrupt: in the range [0, 987];
+ *
+ * For ACPI, GSI should be unique so using
+ * the hwirq directly for the mapping:
+ * PPI interrupt: in the range [16, 31];
+ * SPI interrupt: in the range [32, 1019];
+ */
+
+ if (trigger == ACPI_EDGE_SENSITIVE &&
+ polarity == ACPI_ACTIVE_LOW)
+ irq_type = IRQ_TYPE_EDGE_FALLING;
+ else if (trigger == ACPI_EDGE_SENSITIVE &&
+ polarity == ACPI_ACTIVE_HIGH)
+ irq_type = IRQ_TYPE_EDGE_RISING;
+ else if (trigger == ACPI_LEVEL_SENSITIVE &&
+ polarity == ACPI_ACTIVE_LOW)
+ irq_type = IRQ_TYPE_LEVEL_LOW;
+ else if (trigger == ACPI_LEVEL_SENSITIVE &&
+ polarity == ACPI_ACTIVE_HIGH)
+ irq_type = IRQ_TYPE_LEVEL_HIGH;
+ else
+ irq_type = IRQ_TYPE_NONE;
+
+ /*
+ * Since only one GIC is supported in ACPI 5.0, we can
+ * create mapping refer to the default domain
+ */
+ irq = irq_create_mapping(NULL, gsi);
+ if (!irq)
+ return irq;
+
+ /* Set irq type if specified and different than the current one */
+ if (irq_type != IRQ_TYPE_NONE &&
+ irq_type != irq_get_trigger_type(irq))
+ irq_set_irq_type(irq, irq_type);
+ return irq;
+}
+EXPORT_SYMBOL_GPL(acpi_register_gsi);
+
+void acpi_unregister_gsi(u32 gsi)
+{
+}
+EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
+
static int __init acpi_parse_fadt(struct acpi_table_header *table)
{
struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 8b67bd0..c412fdb 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -448,6 +448,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_IOSAPIC:
message = "IOSAPIC";
break;
+ case ACPI_IRQ_MODEL_GIC:
+ message = "GIC";
+ break;
case ACPI_IRQ_MODEL_PLATFORM:
message = "platform specific model";
break;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d459cd1..87f365e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -72,6 +72,7 @@ enum acpi_irq_model_id {
ACPI_IRQ_MODEL_IOAPIC,
ACPI_IRQ_MODEL_IOSAPIC,
ACPI_IRQ_MODEL_PLATFORM,
+ ACPI_IRQ_MODEL_GIC,
ACPI_IRQ_MODEL_COUNT
};
--
1.9.1
Hanjun Guo
2015-01-04 10:55:14 UTC
Permalink
From: Tomasz Nowicki <***@linaro.org>

ACPI kernel uses MADT table for proper GIC initialization. It needs to
parse GIC related subtables, collect CPU interface and distributor
addresses and call driver initialization function (which is hardware
abstraction agnostic). In a similar way, FDT initialize GICv1/2.

NOTE: This commit allow to initialize GICv1/2 basic functionality.
GICv2 vitalization extension, GICv3/4 and ITS are considered as next
steps.

Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Tomasz Nowicki <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/kernel/acpi.c | 26 +++++++++
drivers/irqchip/irq-gic.c | 108 +++++++++++++++++++++++++++++++++++
drivers/irqchip/irqchip.c | 3 +
include/linux/irqchip/arm-gic-acpi.h | 31 ++++++++++
4 files changed, 168 insertions(+)
create mode 100644 include/linux/irqchip/arm-gic-acpi.h

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index d6d83ea..bf4efe4 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -23,6 +23,7 @@
#include <linux/irqdomain.h>
#include <linux/bootmem.h>
#include <linux/smp.h>
+#include <linux/irqchip/arm-gic-acpi.h>

#include <asm/cputype.h>
#include <asm/cpu_ops.h>
@@ -315,6 +316,31 @@ void __init acpi_boot_table_init(void)
pr_err("Can't find FADT or error happened during parsing FADT\n");
}

+void __init acpi_gic_init(void)
+{
+ struct acpi_table_header *table;
+ acpi_status status;
+ acpi_size tbl_size;
+ int err;
+
+ if (acpi_disabled)
+ return;
+
+ status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
+ if (ACPI_FAILURE(status)) {
+ const char *msg = acpi_format_exception(status);
+
+ pr_err("Failed to get MADT table, %s\n", msg);
+ return;
+ }
+
+ err = gic_v2_acpi_init(table);
+ if (err)
+ pr_err("Failed to initialize GIC IRQ controller");
+
+ early_acpi_os_unmap_memory((char *)table, tbl_size);
+}
+
static int __init parse_acpi(char *arg)
{
if (!arg)
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d617ee5..89a8120 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -33,12 +33,14 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/acpi.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/arm-gic-acpi.h>

#include <asm/cputype.h>
#include <asm/irq.h>
@@ -1083,3 +1085,109 @@ IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);

#endif
+
+#ifdef CONFIG_ACPI
+static phys_addr_t dist_phy_base, cpu_phy_base;
+static int cpu_base_assigned;
+
+static int __init
+gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_interrupt *processor;
+ phys_addr_t gic_cpu_base;
+
+ processor = (struct acpi_madt_generic_interrupt *)header;
+
+ if (BAD_MADT_ENTRY(processor, end))
+ return -EINVAL;
+
+ /*
+ * There is no support for non-banked GICv1/2 register in ACPI spec.
+ * All CPU interface addresses have to be the same.
+ */
+ gic_cpu_base = processor->base_address;
+ if (cpu_base_assigned && gic_cpu_base != cpu_phy_base)
+ return -EFAULT;
+
+ cpu_phy_base = gic_cpu_base;
+ cpu_base_assigned = 1;
+ return 0;
+}
+
+static int __init
+gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_madt_generic_distributor *dist;
+
+ dist = (struct acpi_madt_generic_distributor *)header;
+
+ if (BAD_MADT_ENTRY(dist, end))
+ return -EINVAL;
+
+ dist_phy_base = dist->base_address;
+ return 0;
+}
+
+int __init
+gic_v2_acpi_init(struct acpi_table_header *table)
+{
+ void __iomem *cpu_base, *dist_base;
+ int count;
+
+ /* Collect CPU base addresses */
+ count = acpi_parse_entries(ACPI_SIG_MADT,
+ sizeof(struct acpi_table_madt),
+ gic_acpi_parse_madt_cpu, table,
+ ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0);
+ if (count < 0) {
+ pr_err("Error during GICC entries parsing\n");
+ return -EFAULT;
+ } else if (!count) {
+ pr_err("No valid GICC entries exist\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Find distributor base address. We expect one distributor entry since
+ * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade.
+ */
+ count = acpi_parse_entries(ACPI_SIG_MADT,
+ sizeof(struct acpi_table_madt),
+ gic_acpi_parse_madt_distributor, table,
+ ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0);
+ if (count <= 0) {
+ pr_err("Error during GICD entries parsing\n");
+ return -EFAULT;
+ } else if (!count) {
+ pr_err("No valid GICD entries exist\n");
+ return -EINVAL;
+ } else if (count > 1) {
+ pr_err("More than one GICD entry detected\n");
+ return -EINVAL;
+ }
+
+ cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
+ if (!cpu_base) {
+ pr_err("Unable to map GICC registers\n");
+ return -ENOMEM;
+ }
+
+ dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE);
+ if (!dist_base) {
+ pr_err("Unable to map GICD registers\n");
+ iounmap(cpu_base);
+ return -ENOMEM;
+ }
+
+ /*
+ * Initialize zero GIC instance (no multi-GIC support). Also, set GIC
+ * as default IRQ domain to allow for GSI registration and GSI to IRQ
+ * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()).
+ */
+ gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL);
+ irq_set_default_host(gic_data[0].domain);
+ return 0;
+}
+#endif
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index 0fe2f71..9106c6d 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/of_irq.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic-acpi.h>

/*
* This special of_device_id is the sentinel at the end of the
@@ -26,4 +27,6 @@ extern struct of_device_id __irqchip_of_table[];
void __init irqchip_init(void)
{
of_irq_init(__irqchip_of_table);
+
+ acpi_gic_init();
}
diff --git a/include/linux/irqchip/arm-gic-acpi.h b/include/linux/irqchip/arm-gic-acpi.h
new file mode 100644
index 0000000..ad5b577
--- /dev/null
+++ b/include/linux/irqchip/arm-gic-acpi.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014, Linaro Ltd.
+ * Author: Tomasz Nowicki <***@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARM_GIC_ACPI_H_
+#define ARM_GIC_ACPI_H_
+
+#ifdef CONFIG_ACPI
+
+/*
+ * Hard code here, we can not get memory size from MADT (but FDT does),
+ * Actually no need to do that, because this size can be inferred
+ * from GIC spec.
+ */
+#define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K)
+#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K)
+
+struct acpi_table_header;
+
+void acpi_gic_init(void);
+int gic_v2_acpi_init(struct acpi_table_header *table);
+#else
+static inline void acpi_gic_init(void) { }
+#endif
+
+#endif /* ARM_GIC_ACPI_H_ */
--
1.9.1
Hanjun Guo
2015-01-04 10:55:15 UTC
Permalink
Using the information presented by GTDT to initialize the arch
timer (not memory-mapped).

Originally-by: Amit Daniel Kachhap <***@samsung.com>
Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/kernel/time.c | 7 ++
drivers/clocksource/arm_arch_timer.c | 132 ++++++++++++++++++++++++++++-------
include/linux/clocksource.h | 6 ++
3 files changed, 118 insertions(+), 27 deletions(-)

diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 1a7125c..42f9195 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/clk-provider.h>
+#include <linux/acpi.h>

#include <clocksource/arm_arch_timer.h>

@@ -72,6 +73,12 @@ void __init time_init(void)

tick_setup_hrtimer_broadcast();

+ /*
+ * Since ACPI or FDT will only one be available in the system,
+ * we can use acpi_generic_timer_init() here safely
+ */
+ acpi_generic_timer_init();
+
arch_timer_rate = arch_timer_get_rate();
if (!arch_timer_rate)
panic("Unable to initialise architected timer.\n");
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 6a79fc4..612f2a0 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/sched_clock.h>
+#include <linux/acpi.h>

#include <asm/arch_timer.h>
#include <asm/virt.h>
@@ -370,8 +371,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
if (arch_timer_rate)
return;

- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
+ /*
+ * Try to determine the frequency from the device tree or CNTFRQ,
+ * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+ */
+ if (!acpi_disabled ||
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
if (cntbase)
arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
else
@@ -690,28 +695,8 @@ static void __init arch_timer_common_init(void)
arch_timer_arch_init();
}

-static void __init arch_timer_init(struct device_node *np)
+static void __init arch_timer_init(void)
{
- int i;
-
- if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: multiple nodes in dt, skipping\n");
- return;
- }
-
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
- arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
-
- /*
- * If we cannot rely on firmware initializing the timer registers then
- * we should use the physical timers instead.
- */
- if (IS_ENABLED(CONFIG_ARM) &&
- of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
- arch_timer_use_virtual = false;
-
/*
* If HYP mode is available, we know that the physical timer
* has been configured to be accessible from PL1. Use it, so
@@ -730,13 +715,39 @@ static void __init arch_timer_init(struct device_node *np)
}
}

- arch_timer_c3stop = !of_property_read_bool(np, "always-on");
-
arch_timer_register();
arch_timer_common_init();
}
-CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init);
-CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
+
+static void __init arch_timer_of_init(struct device_node *np)
+{
+ int i;
+
+ if (arch_timers_present & ARCH_CP15_TIMER) {
+ pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+ return;
+ }
+
+ arch_timers_present |= ARCH_CP15_TIMER;
+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+ arch_timer_detect_rate(NULL, np);
+
+ arch_timer_c3stop = !of_property_read_bool(np, "always-on");
+
+ /*
+ * If we cannot rely on firmware initializing the timer registers then
+ * we should use the physical timers instead.
+ */
+ if (IS_ENABLED(CONFIG_ARM) &&
+ of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
+ arch_timer_use_virtual = false;
+
+ arch_timer_init();
+}
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init);
+CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init);

static void __init arch_timer_mem_init(struct device_node *np)
{
@@ -803,3 +814,70 @@ static void __init arch_timer_mem_init(struct device_node *np)
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_init);
+
+#ifdef CONFIG_ACPI
+static int __init map_generic_timer_interrupt(u32 interrupt, u32 flags)
+{
+ int trigger, polarity;
+
+ if (!interrupt)
+ return 0;
+
+ trigger = (flags & ACPI_GTDT_INTERRUPT_MODE) ? ACPI_EDGE_SENSITIVE
+ : ACPI_LEVEL_SENSITIVE;
+
+ polarity = (flags & ACPI_GTDT_INTERRUPT_POLARITY) ? ACPI_ACTIVE_LOW
+ : ACPI_ACTIVE_HIGH;
+
+ return acpi_register_gsi(NULL, interrupt, trigger, polarity);
+}
+
+/* Initialize per-processor generic timer */
+static int __init arch_timer_acpi_init(struct acpi_table_header *table)
+{
+ struct acpi_table_gtdt *gtdt;
+
+ if (arch_timers_present & ARCH_CP15_TIMER) {
+ pr_warn("arch_timer: already initialized, skipping\n");
+ return -EINVAL;
+ }
+
+ gtdt = container_of(table, struct acpi_table_gtdt, header);
+
+ arch_timers_present |= ARCH_CP15_TIMER;
+
+ arch_timer_ppi[PHYS_SECURE_PPI] =
+ map_generic_timer_interrupt(gtdt->secure_el1_interrupt,
+ gtdt->secure_el1_flags);
+
+ arch_timer_ppi[PHYS_NONSECURE_PPI] =
+ map_generic_timer_interrupt(gtdt->non_secure_el1_interrupt,
+ gtdt->non_secure_el1_flags);
+
+ arch_timer_ppi[VIRT_PPI] =
+ map_generic_timer_interrupt(gtdt->virtual_timer_interrupt,
+ gtdt->virtual_timer_flags);
+
+ arch_timer_ppi[HYP_PPI] =
+ map_generic_timer_interrupt(gtdt->non_secure_el2_interrupt,
+ gtdt->non_secure_el2_flags);
+
+ /* Get the frequency from CNTFRQ */
+ arch_timer_detect_rate(NULL, NULL);
+
+ /* Always-on capability */
+ arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);
+
+ arch_timer_init();
+ return 0;
+}
+
+/* Initialize all the generic timers presented in GTDT */
+void __init acpi_generic_timer_init(void)
+{
+ if (acpi_disabled)
+ return;
+
+ acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_init);
+}
+#endif
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index abcafaa..af6155a 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -346,4 +346,10 @@ extern void clocksource_of_init(void);
static inline void clocksource_of_init(void) {}
#endif

+#ifdef CONFIG_ACPI
+void acpi_generic_timer_init(void);
+#else
+static inline void acpi_generic_timer_init(void) { }
+#endif
+
#endif /* _LINUX_CLOCKSOURCE_H */
--
1.9.1
Hanjun Guo
2015-01-04 10:55:16 UTC
Permalink
From: Al Stone <***@linaro.org>

ACPI reduced hardware mode is disabled by default, but ARM64
can only run properly in ACPI hardware reduced mode, so select
ACPI_REDUCED_HARDWARE_ONLY if ACPI is enabled on ARM64.

Reviewed-by: Grant Likely <***@linaro.org>
Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/Kconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..c19ae5d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1,5 +1,6 @@
config ARM64
def_bool y
+ select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_GCOV_PROFILE_ALL
--
1.9.1
Hanjun Guo
2015-01-04 10:55:17 UTC
Permalink
From: Graeme Gregory <***@linaro.org>

Add Kconfigs to build ACPI on ARM64, and make ACPI available on ARM64.

acpi_idle driver is x86/IA64 dependent now, so make CONFIG_ACPI_PROCESSOR
depend on X86 || IA64, and implement it on ARM64 in the future.

Reviewed-by: Grant Likely <***@linaro.org>
Tested-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
arch/arm64/Kconfig | 2 ++
drivers/acpi/Kconfig | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index c19ae5d..915aa16 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -647,6 +647,8 @@ source "drivers/Kconfig"

source "drivers/firmware/Kconfig"

+source "drivers/acpi/Kconfig"
+
source "fs/Kconfig"

source "arch/arm64/kvm/Kconfig"
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 8951cef..3e3bd35 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -5,8 +5,7 @@
menuconfig ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support"
depends on !IA64_HP_SIM
- depends on IA64 || X86
- depends on PCI
+ depends on ((IA64 || X86) && PCI) || (ARM64 && EXPERT)
select PNP
default y
help
@@ -163,6 +162,7 @@ config ACPI_PROCESSOR
tristate "Processor"
select THERMAL
select CPU_IDLE
+ depends on X86 || IA64
default y
help
This driver installs ACPI as the idle handler for Linux and uses
@@ -263,7 +263,7 @@ config ACPI_DEBUG

config ACPI_PCI_SLOT
bool "PCI slot detection driver"
- depends on SYSFS
+ depends on SYSFS && PCI
default n
help
This driver creates entries in /sys/bus/pci/slots/ for all PCI
--
1.9.1
Hanjun Guo
2015-01-04 10:55:18 UTC
Permalink
From: Graeme Gregory <***@linaro.org>

Add documentation for the guidelines of how to use ACPI
on ARM64.

Reviewed-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
Documentation/arm64/arm-acpi.txt | 327 +++++++++++++++++++++++++++++++++++++++
1 file changed, 327 insertions(+)
create mode 100644 Documentation/arm64/arm-acpi.txt

diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt
new file mode 100644
index 0000000..21e7020
--- /dev/null
+++ b/Documentation/arm64/arm-acpi.txt
@@ -0,0 +1,327 @@
+ACPI on ARMv8 Servers
+---------------------
+ACPI can be used for ARMv8 general purpose servers designed to follow
+the ARM SBSA (Server Base System Architecture) and SBBR (Server Base
+Boot Requirements) specifications, currently available to those with
+an ARM login at http://silver.arm.com.
+
+The ARMv8 kernel implements the reduced hardware model of ACPI version
+5.1 and later. Links to the specification and all external documents
+it refers to are managed by the UEFI Forum. The specification is
+available at http://www.uefi.org/specifications and external documents
+can be found via http://www.uefi.org/acpi.
+
+If an ARMv8 system does not meet the requirements of the SBSA, or cannot
+be described using the mechanisms defined in the required ACPI specifications,
+then it is likely that Device Tree (DT) is more suitable than ACPI for the
+hardware.
+
+
+Relationship with Device Tree
+-----------------------------
+ACPI support in drivers and subsystems for ARMv8 should never be mutually
+exclusive with DT support at compile time.
+
+At boot time the kernel will only use one description method depending on
+parameters passed from the bootloader (including kernel bootargs).
+
+Regardless of whether DT or ACPI is used, the kernel must always be capable
+of booting with either scheme (in kernels with both schemes enabled at compile
+time).
+
+
+Booting using ACPI tables
+-------------------------
+The only defined method for passing ACPI tables to the kernel on ARMv8
+is via the UEFI system configuration table.
+
+Processing of ACPI tables may be disabled by passing acpi=off on the kernel
+command line; this is the default behavior if both ACPI and DT tables are
+present. If acpi=force is used, the kernel will ONLY use device configuration
+information contained in the ACPI tables if those tables are available.
+
+In order for the kernel to load and use ACPI tables, the UEFI implementation
+MUST set the ACPI_20_TABLE_GUID to point to the RSDP table (the table with
+the ACPI signature "RSD PTR "). If this pointer is incorrect and acpi=force
+is used, the kernel will disable ACPI and try to use DT to boot instead.
+
+If the pointer to the RSDP table is correct, the table will be mapped into
+the kernel by the ACPI core, using the address provided by UEFI.
+
+The ACPI core will then locate and map in all other ACPI tables provided by
+using the addresses in the RSDP table to find the XSDT (eXtended System
+Description Table). The XSDT in turn provides the addresses to all other
+ACPI tables provided by the system firmware; the ACPI core will then traverse
+this table and map in the tables listed.
+
+The ACPI core will ignore any provided RSDT (Root System Description Table).
+RSDTs have been deprecated and are ignored on arm64 since they only allow
+for 32-bit addresses.
+
+Further, the ACPI core will only use the 64-bit address fields in the FADT
+(Fixed ACPI Description Table). Any 32-bit address fields in the FADT will
+be ignored on arm64.
+
+Hardware reduced mode (see Section 4.1 of the ACPI 5.1 specification) will
+be enforced by the ACPI core on arm64. Doing so allows the ACPI core to
+run less complex code since it no longer has to provide support for legacy
+hardware from other architectures.
+
+For the ACPI core to operate properly, and in turn provide the information
+the kernel needs to configure devices, it expects to find the following
+tables (all section numbers refer to the ACPI 5.1 specfication):
+
+ -- RSDP (Root System Description Pointer), section 5.2.5
+
+ -- XSDT (eXtended System Description Table), section 5.2.8
+
+ -- FADT (Fixed ACPI Description Table), section 5.2.9
+
+ -- DSDT (Differentiated System Description Table), section
+ 5.2.11.1
+
+ -- MADT (Multiple APIC Description Table), section 5.2.12
+
+ -- GTDT (Generic Timer Description Table), section 5.2.24
+
+ -- If PCI is supported, the MCFG (Memory mapped ConFiGuration
+ Table), section 5.2.6, specifically Table 5-31.
+
+If the above tables are not all present, the kernel may or may not be
+able to boot properly since it may not be able to configure all of the
+devices available.
+
+
+ACPI Detection
+--------------
+Drivers should determine their probe() type by checking for a null
+value for ACPI_HANDLE, or checking .of_node, or other information in
+the device structure. This is detailed further in the "Driver
+Recommendations" section.
+
+In non-driver code, if the presence of ACPI needs to be detected at
+runtime, then check the value of acpi_disabled. If CONFIG_ACPI is not
+set, acpi_disabled will always be 1.
+
+
+Device Enumeration
+------------------
+Device descriptions in ACPI should use standard recognized ACPI interfaces.
+These may contain less information than is typically provided via a Device
+Tree description for the same device. This is also one of the reasons that
+ACPI can be useful -- the driver takes into account that it may have less
+detailed information about the device and uses sensible defaults instead.
+If done properly in the driver, the hardware can change and improve over
+time without the driver having to change at all.
+
+Clocks provide an excellent example. In DT, clocks need to be specified
+and the drivers need to take them into account. In ACPI, the assumption
+is that UEFI will leave the device in a reasonable default state, including
+any clock settings. If for some reason the driver needs to change a clock
+value, this can be done in an ACPI method; all the driver needs to do is
+invoke the method and not concern itself with what the method needs to do
+to change the clock. Changing the hardware can then take place over time
+by changing what the ACPI method does, and not the driver.
+
+ACPI drivers should only look at one specific ASL object -- the _DSD object
+-- for device driver parameters (known in DT as "bindings", or "Device
+Properties" in ACPI). DT bindings also will be reviewed before used. The UEFI
+Forum provides a mechanism for registering such bindings [URL TBD by ASWG]
+so that they may be used on any operating system supporting ACPI. Device
+properties that have not been registered with the UEFI Forum should not be
+used.
+
+Drivers should look for device properties in the _DSD object ONLY; the _DSD
+object is described in the ACPI specification section 6.2.5, but more
+specifically, use the _DSD Device Properties UUID:
+
+ -- UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301
+
+ -- http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+
+The kernel has an interface for looking up device properties in a manner
+independent of whether DT or ACPI is being used and that interface should
+be used; it can eliminate some duplication of code paths in driver probing
+functions and discourage divergence between DT bindings and ACPI device
+properties.
+
+ACPI tables are described with a formal language called ASL, the ACPI
+Source Language (section 19 of the specification). This means that there
+are always multiple ways to describe the same thing -- including device
+properties. For example, device properties could use an ASL construct
+that looks like this: Name(KEY0, "value0"). An ACPI device driver would
+then retrieve the value of the property by evaluating the KEY0 object.
+However, using Name() this way has multiple problems: (1) ACPI limits
+names ("KEY0") to four characters unlike DT; (2) there is no industry
+wide registry that maintains a list of names, minimzing re-use; (3)
+there is also no registry for the definition of property values ("value0"),
+again making re-use difficult; and (4) how does one maintain backward
+compatibility as new hardware comes out? The _DSD method was created
+to solve precisely these sorts of problems; Linux drivers should ALWAYS
+use the _DSD method for device properties and nothing else.
+
+The _DSM object (ACPI Section 9.14.1) could also be used for conveying
+device properties to a driver. Linux drivers should only expect it to
+be used if _DSD cannot represent the data required, and there is no way
+to create a new UUID for the _DSD object. Note that there is even less
+regulation of the use of _DSM than there is of _DSD. Drivers that depend
+on the contents of _DSM objects will be more difficult to maintain over
+time because of this.
+
+The _DSD object is a very flexible mechanism in ACPI, as are the registered
+Device Properties. This flexibility allows _DSD to cover more than just the
+generic server case and care should be taken in device drivers not to expect
+it to replicate highly specific embedded behaviour from DT.
+
+Both DT bindings and ACPI device properties for device drivers have review
+processes. Use them. And, before creating new device properties, check to
+be sure that they have not been defined before and either registered in the
+Linux kernel documentation or the UEFI Forum. If the device drivers supports
+ACPI and DT, please make sure the device properties are consistent in both
+places.
+
+
+Programmable Power Control Resources
+------------------------------------
+Programmable power control resources include such resources as voltage/current
+providers (regulators) and clock sources.
+
+The kernel assumes that power control of these resources is represented with
+Power Resource Objects (ACPI section 7.1). The ACPI core will then handle
+correctly enabling and disabling resources as they are needed. In order to
+get that to work, ACPI assumes each device has defined D-states and that these
+can be controlled through the optional ACPI methods _PS0, _PS1, _PS2, and _PS3;
+in ACPI, _PS0 is the method to invoke to turn a device full on, and _PS3 is for
+turning a device full off.
+
+There are two options for using those Power Resources.
+ -- be managed in _PSx routine which gets called on entry to Dx.
+
+ -- be declared separately as power resources with their own _ON and _OFF
+ methods. They are then tied back to D-states for a particular device
+ via _PRx which specifies which power resources a device needs to be on
+ while in Dx. Kernel then tracks number of devices using a power resource
+ and calls _ON/_OFF as needed.
+
+The kernel ACPI code will also assume that the _PSx methods follow the normal
+ACPI rules for such methods:
+
+ -- If either _PS0 or _PS3 is implemented, then the other method must also
+ be implemented.
+
+ -- If a device requires usage or setup of a power resource when on, the ASL
+ should organize that it is allocated/enabled using the _PS0 method.
+
+ -- Resources allocated or enabled in the _PS0 method should be disabled
+ or de-allocated in the _PS3 method.
+
+ -- Firmware will leave the resources in a reasonable state before handing
+ over control to the kernel.
+
+Such code in _PSx methods will of course be very platform specific. But,
+this allows the driver to abstract out the interface for operating the device
+and avoid having to read special non-standard values from ACPI tables. Further,
+abstracting the use of these resources allows the hardware to change over time
+without requiring updates to the driver.
+
+
+Clocks
+------
+ACPI makes the assumption that clocks are initialized by the firmware --
+UEFI, in this case -- to some working value before control is handed over
+to the kernel. This has implications for devices such as UARTs, or SoC-driven
+LCD displays, for example.
+
+When the kernel boots, the clock is assumed to be set to a reasonable
+working value. If for some reason the frequency needs to change -- e.g.,
+throttling for power management -- the device driver should expect that
+process to be abstracted out into some ACPI method that can be invoked
+(please see the ACPI specification for further recommendations on standard
+methods to be expected) except CPU clocks where CPPC provides a much richer
+interface instead of some method. If it is not, there is no direct way for
+ACPI to control the clocks.
+
+
+Driver Recommendations
+----------------------
+DO NOT remove any DT handling when adding ACPI support for a driver. The
+same device may be used on many different systems.
+
+DO try to structure the driver so that it is data-driven. That is, set up
+a struct containing internal per-device state based on defaults and whatever
+else must be discovered by the driver probe function. Then, have the rest
+of the driver operate off of the contents of that struct. Doing so should
+allow most divergence between ACPI and DT functionality to be kept local to
+the probe function instead of being scattered throughout the driver. For
+example:
+
+static int device_probe_dt(struct platform_device *pdev)
+{
+ /* DT specific functionality */
+ ...
+}
+
+static int device_probe_acpi(struct platform_device *pdev)
+{
+ /* ACPI specific functionality */
+ ...
+}
+
+static int device_probe(stuct platform_device *pdev)
+{
+ ...
+ struct device_node node = pdev->dev.of_node;
+ ...
+
+ if (node)
+ ret = device_probe_dt(pdev);
+ else if (ACPI_HANDLE(&pdev->dev))
+ ret = device_probe_acpi(pdev);
+ else
+ /* other initialization */
+ ...
+ /* Continue with any generic probe operations */
+ ...
+}
+
+DO keep the MODULE_DEVICE_TABLE entries together in the driver to make it
+clear the different names the driver is probed for, both from DT and from
+ACPI:
+
+static struct of_device_id virtio_mmio_match[] = {
+ { .compatible = "virtio,mmio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, virtio_mmio_match);
+
+static const struct acpi_device_id virtio_mmio_acpi_match[] = {
+ { "LNRO0005", },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match);
+
+
+ASWG
+----
+The following areas are not yet fully defined for ARM in the 5.1 version
+of the ACPI specification and are expected to be worked through in the
+UEFI ACPI Specification Working Group (ASWG):
+
+ -- ACPI based CPU topology
+ -- ACPI based CPU idle control
+ -- ACPI based SMMU and its IO topology
+ -- ITS support for GIC in MADT
+
+Participation in this group is open to all UEFI members. Please see
+http://www.uefi.org/workinggroup for details on group membership.
+
+It is the intent of the ARMv8 ACPI kernel code to follow the ACPI specification
+as closely as possible, and to only implement functionality that complies with
+the released standards from UEFI ASWG. As a practical matter, there will be
+vendors that provide bad ACPI tables or violate the standards in some way.
+If this is because of errors, quirks and fixups may be necessary, but will
+be avoided if possible. If there are features missing from ACPI that preclude
+it from being used on a platform, ECRs (Engineering Change Requests) should be
+submitted to ASWG and go through the normal approval process; for those that
+are not UEFI members, many other members of the Linux community are and would
+likely be willing to assist in submitting ECRs.
--
1.9.1
liyi 00215672
2015-01-06 09:52:05 UTC
Permalink
In traditional telecom market, what confused us(Huawei) was our software and hardware coupling together oftentimes. So if we change some hardware then we MUST modify our software, which was not our customer’s expectation. In x86 world, we have UEFI and ACPI technologies, they are suitable to solve this problem very well, we just upgrade our hardware and don’t need to upgrade their software, in the meantime ACPI provides many methods on power management.

In ARM64 world, we are aiming the same thing. Following the SBBR,SBSA specs to implement our UEFI and ACPI code, we think the patch set and arm-acpi documentation are fine , and consider it is going on the right direction, so

Reviewed-by: Yi Li <***@huawei.com>



-----邮件原件-----
发件人: Hanjun Guo [mailto:***@linaro.org]
发送时间: 2015年1月4日 18:55
收件人: Catalin Marinas; Rafael J. Wysocki; Olof Johansson; Arnd Bergmann; Mark Rutland; Grant Likely; Will Deacon
抄送: Lorenzo Pieralisi; Graeme Gregory; Sudeep Holla; Jon Masters; Jason Cooper; Marc Zyngier; Bjorn Helgaas; Mark Brown; Rob Herring; Robert Richter; Randy Dunlap; Charles.Garcia-***@arm.com; liyi 00215672; Timur Tabi; ***@amd.com; linux-***@vger.kernel.org; linux-arm-***@lists.infradead.org; linux-***@vger.kernel.org; linaro-***@lists.linaro.org; Al Stone; Hanjun Guo
主题: [PATCH v6 17/17] Documentation: ACPI for ARM64

From: Graeme Gregory <***@linaro.org>

Add documentation for the guidelines of how to use ACPI on ARM64.

Reviewed-by: Suravee Suthikulpanit <***@amd.com>
Signed-off-by: Graeme Gregory <***@linaro.org>
Signed-off-by: Al Stone <***@linaro.org>
Signed-off-by: Hanjun Guo <***@linaro.org>
---
Documentation/arm64/arm-acpi.txt | 327 +++++++++++++++++++++++++++++++++++++++
1 file changed, 327 insertions(+)
create mode 100644 Documentation/arm64/arm-acpi.txt

diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt
new file mode 100644
index 0000000..21e7020
--- /dev/null
+++ b/Documentation/arm64/arm-acpi.txt
@@ -0,0 +1,327 @@
+ACPI on ARMv8 Servers
+---------------------
+ACPI can be used for ARMv8 general purpose servers designed to follow
+the ARM SBSA (Server Base System Architecture) and SBBR (Server Base
+Boot Requirements) specifications, currently available to those with an
+ARM login at http://silver.arm.com.
+
+The ARMv8 kernel implements the reduced hardware model of ACPI version
+5.1 and later. Links to the specification and all external documents
+it refers to are managed by the UEFI Forum. The specification is
+available at http://www.uefi.org/specifications and external documents
+can be found via http://www.uefi.org/acpi.
+
+If an ARMv8 system does not meet the requirements of the SBSA, or
+cannot be described using the mechanisms defined in the required ACPI
+specifications, then it is likely that Device Tree (DT) is more
+suitable than ACPI for the hardware.
+
+
+Relationship with Device Tree
+-----------------------------
+ACPI support in drivers and subsystems for ARMv8 should never be
+mutually exclusive with DT support at compile time.
+
+At boot time the kernel will only use one description method depending
+on parameters passed from the bootloader (including kernel bootargs).
+
+Regardless of whether DT or ACPI is used, the kernel must always be
+capable of booting with either scheme (in kernels with both schemes
+enabled at compile time).
+
+
+Booting using ACPI tables
+-------------------------
+The only defined method for passing ACPI tables to the kernel on ARMv8
+is via the UEFI system configuration table.
+
+Processing of ACPI tables may be disabled by passing acpi=off on the
+kernel command line; this is the default behavior if both ACPI and DT
+tables are present. If acpi=force is used, the kernel will ONLY use
+device configuration information contained in the ACPI tables if those tables are available.
+
+In order for the kernel to load and use ACPI tables, the UEFI
+implementation MUST set the ACPI_20_TABLE_GUID to point to the RSDP
+table (the table with the ACPI signature "RSD PTR "). If this pointer
+is incorrect and acpi=force is used, the kernel will disable ACPI and try to use DT to boot instead.
+
+If the pointer to the RSDP table is correct, the table will be mapped
+into the kernel by the ACPI core, using the address provided by UEFI.
+
+The ACPI core will then locate and map in all other ACPI tables
+provided by using the addresses in the RSDP table to find the XSDT
+(eXtended System Description Table). The XSDT in turn provides the
+addresses to all other ACPI tables provided by the system firmware; the
+ACPI core will then traverse this table and map in the tables listed.
+
+The ACPI core will ignore any provided RSDT (Root System Description Table).
+RSDTs have been deprecated and are ignored on arm64 since they only
+allow for 32-bit addresses.
+
+Further, the ACPI core will only use the 64-bit address fields in the
+FADT (Fixed ACPI Description Table). Any 32-bit address fields in the
+FADT will be ignored on arm64.
+
+Hardware reduced mode (see Section 4.1 of the ACPI 5.1 specification)
+will be enforced by the ACPI core on arm64. Doing so allows the ACPI
+core to run less complex code since it no longer has to provide support
+for legacy hardware from other architectures.
+
+For the ACPI core to operate properly, and in turn provide the
+information the kernel needs to configure devices, it expects to find
+the following tables (all section numbers refer to the ACPI 5.1 specfication):
+
+ -- RSDP (Root System Description Pointer), section 5.2.5
+
+ -- XSDT (eXtended System Description Table), section 5.2.8
+
+ -- FADT (Fixed ACPI Description Table), section 5.2.9
+
+ -- DSDT (Differentiated System Description Table), section
+ 5.2.11.1
+
+ -- MADT (Multiple APIC Description Table), section 5.2.12
+
+ -- GTDT (Generic Timer Description Table), section 5.2.24
+
+ -- If PCI is supported, the MCFG (Memory mapped ConFiGuration
+ Table), section 5.2.6, specifically Table 5-31.
+
+If the above tables are not all present, the kernel may or may not be
+able to boot properly since it may not be able to configure all of the
+devices available.
+
+
+ACPI Detection
+--------------
+Drivers should determine their probe() type by checking for a null
+value for ACPI_HANDLE, or checking .of_node, or other information in
+the device structure. This is detailed further in the "Driver
+Recommendations" section.
+
+In non-driver code, if the presence of ACPI needs to be detected at
+runtime, then check the value of acpi_disabled. If CONFIG_ACPI is not
+set, acpi_disabled will always be 1.
+
+
+Device Enumeration
+------------------
+Device descriptions in ACPI should use standard recognized ACPI interfaces.
+These may contain less information than is typically provided via a
+Device Tree description for the same device. This is also one of the
+reasons that ACPI can be useful -- the driver takes into account that
+it may have less detailed information about the device and uses sensible defaults instead.
+If done properly in the driver, the hardware can change and improve
+over time without the driver having to change at all.
+
+Clocks provide an excellent example. In DT, clocks need to be
+specified and the drivers need to take them into account. In ACPI, the
+assumption is that UEFI will leave the device in a reasonable default
+state, including any clock settings. If for some reason the driver
+needs to change a clock value, this can be done in an ACPI method; all
+the driver needs to do is invoke the method and not concern itself with
+what the method needs to do to change the clock. Changing the hardware
+can then take place over time by changing what the ACPI method does, and not the driver.
+
+ACPI drivers should only look at one specific ASL object -- the _DSD
+object
+-- for device driver parameters (known in DT as "bindings", or "Device
+Properties" in ACPI). DT bindings also will be reviewed before used.
+The UEFI Forum provides a mechanism for registering such bindings [URL
+TBD by ASWG] so that they may be used on any operating system
+supporting ACPI. Device properties that have not been registered with
+the UEFI Forum should not be used.
+
+Drivers should look for device properties in the _DSD object ONLY; the
+_DSD object is described in the ACPI specification section 6.2.5, but
+more specifically, use the _DSD Device Properties UUID:
+
+ -- UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301
+
+ --
+ http://www.uefi.org/sites/default/files/resources/_DSD-device-properti
+ es-UUID.pdf
+
+The kernel has an interface for looking up device properties in a
+manner independent of whether DT or ACPI is being used and that
+interface should be used; it can eliminate some duplication of code
+paths in driver probing functions and discourage divergence between DT
+bindings and ACPI device properties.
+
+ACPI tables are described with a formal language called ASL, the ACPI
+Source Language (section 19 of the specification). This means that
+there are always multiple ways to describe the same thing -- including
+device properties. For example, device properties could use an ASL
+construct that looks like this: Name(KEY0, "value0"). An ACPI device
+driver would then retrieve the value of the property by evaluating the KEY0 object.
+However, using Name() this way has multiple problems: (1) ACPI limits
+names ("KEY0") to four characters unlike DT; (2) there is no industry
+wide registry that maintains a list of names, minimzing re-use; (3)
+there is also no registry for the definition of property values
+("value0"), again making re-use difficult; and (4) how does one
+maintain backward compatibility as new hardware comes out? The _DSD
+method was created to solve precisely these sorts of problems; Linux
+drivers should ALWAYS use the _DSD method for device properties and nothing else.
+
+The _DSM object (ACPI Section 9.14.1) could also be used for conveying
+device properties to a driver. Linux drivers should only expect it to
+be used if _DSD cannot represent the data required, and there is no way
+to create a new UUID for the _DSD object. Note that there is even less
+regulation of the use of _DSM than there is of _DSD. Drivers that
+depend on the contents of _DSM objects will be more difficult to
+maintain over time because of this.
+
+The _DSD object is a very flexible mechanism in ACPI, as are the
+registered Device Properties. This flexibility allows _DSD to cover
+more than just the generic server case and care should be taken in
+device drivers not to expect it to replicate highly specific embedded behaviour from DT.
+
+Both DT bindings and ACPI device properties for device drivers have
+review processes. Use them. And, before creating new device
+properties, check to be sure that they have not been defined before and
+either registered in the Linux kernel documentation or the UEFI Forum.
+If the device drivers supports ACPI and DT, please make sure the device
+properties are consistent in both places.
+
+
+Programmable Power Control Resources
+------------------------------------
+Programmable power control resources include such resources as
+voltage/current providers (regulators) and clock sources.
+
+The kernel assumes that power control of these resources is represented
+with Power Resource Objects (ACPI section 7.1). The ACPI core will
+then handle correctly enabling and disabling resources as they are
+needed. In order to get that to work, ACPI assumes each device has
+defined D-states and that these can be controlled through the optional
+ACPI methods _PS0, _PS1, _PS2, and _PS3; in ACPI, _PS0 is the method to
+invoke to turn a device full on, and _PS3 is for turning a device full off.
+
+There are two options for using those Power Resources.
+ -- be managed in _PSx routine which gets called on entry to Dx.
+
+ -- be declared separately as power resources with their own _ON and _OFF
+ methods. They are then tied back to D-states for a particular device
+ via _PRx which specifies which power resources a device needs to be on
+ while in Dx. Kernel then tracks number of devices using a power resource
+ and calls _ON/_OFF as needed.
+
+The kernel ACPI code will also assume that the _PSx methods follow the
+normal ACPI rules for such methods:
+
+ -- If either _PS0 or _PS3 is implemented, then the other method must also
+ be implemented.
+
+ -- If a device requires usage or setup of a power resource when on, the ASL
+ should organize that it is allocated/enabled using the _PS0 method.
+
+ -- Resources allocated or enabled in the _PS0 method should be disabled
+ or de-allocated in the _PS3 method.
+
+ -- Firmware will leave the resources in a reasonable state before handing
+ over control to the kernel.
+
+Such code in _PSx methods will of course be very platform specific.
+But, this allows the driver to abstract out the interface for operating
+the device and avoid having to read special non-standard values from
+ACPI tables. Further, abstracting the use of these resources allows the
+hardware to change over time without requiring updates to the driver.
+
+
+Clocks
+------
+ACPI makes the assumption that clocks are initialized by the firmware
+-- UEFI, in this case -- to some working value before control is handed
+over to the kernel. This has implications for devices such as UARTs,
+or SoC-driven LCD displays, for example.
+
+When the kernel boots, the clock is assumed to be set to a reasonable
+working value. If for some reason the frequency needs to change --
+e.g., throttling for power management -- the device driver should
+expect that process to be abstracted out into some ACPI method that can
+be invoked (please see the ACPI specification for further
+recommendations on standard methods to be expected) except CPU clocks
+where CPPC provides a much richer interface instead of some method. If
+it is not, there is no direct way for ACPI to control the clocks.
+
+
+Driver Recommendations
+----------------------
+DO NOT remove any DT handling when adding ACPI support for a driver.
+The same device may be used on many different systems.
+
+DO try to structure the driver so that it is data-driven. That is, set
+up a struct containing internal per-device state based on defaults and
+whatever else must be discovered by the driver probe function. Then,
+have the rest of the driver operate off of the contents of that struct.
+Doing so should allow most divergence between ACPI and DT functionality
+to be kept local to the probe function instead of being scattered
+throughout the driver. For
+example:
+
+static int device_probe_dt(struct platform_device *pdev) {
+ /* DT specific functionality */
+ ...
+}
+
+static int device_probe_acpi(struct platform_device *pdev) {
+ /* ACPI specific functionality */
+ ...
+}
+
+static int device_probe(stuct platform_device *pdev) {
+ ...
+ struct device_node node = pdev->dev.of_node;
+ ...
+
+ if (node)
+ ret = device_probe_dt(pdev);
+ else if (ACPI_HANDLE(&pdev->dev))
+ ret = device_probe_acpi(pdev);
+ else
+ /* other initialization */
+ ...
+ /* Continue with any generic probe operations */
+ ...
+}
+
+DO keep the MODULE_DEVICE_TABLE entries together in the driver to make
+it clear the different names the driver is probed for, both from DT and
+from
+ACPI:
+
+static struct of_device_id virtio_mmio_match[] = {
+ { .compatible = "virtio,mmio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, virtio_mmio_match);
+
+static const struct acpi_device_id virtio_mmio_acpi_match[] = {
+ { "LNRO0005", },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match);
+
+
+ASWG
+----
+The following areas are not yet fully defined for ARM in the 5.1
+version of the ACPI specification and are expected to be worked through
+in the UEFI ACPI Specification Working Group (ASWG):
+
+ -- ACPI based CPU topology
+ -- ACPI based CPU idle control
+ -- ACPI based SMMU and its IO topology
+ -- ITS support for GIC in MADT
+
+Participation in this group is open to all UEFI members. Please see
+http://www.uefi.org/workinggroup for details on group membership.
+
+It is the intent of the ARMv8 ACPI kernel code to follow the ACPI
+specification as closely as possible, and to only implement
+functionality that complies with the released standards from UEFI ASWG.
+As a practical matter, there will be vendors that provide bad ACPI tables or violate the standards in some way.
+If this is because of errors, quirks and fixups may be necessary, but
+will be avoided if possible. If there are features missing from ACPI
+that preclude it from being used on a platform, ECRs (Engineering
+Change Requests) should be submitted to ASWG and go through the normal
+approval process; for those that are not UEFI members, many other
+members of the Linux community are and would likely be willing to assist in submitting ECRs.
--
1.9.1
Hanjun Guo
2015-01-06 11:21:53 UTC
Permalink
Hi Yi,
Post by liyi 00215672
In traditional telecom market, what confused us(Huawei) was our software and
hardware coupling together oftentimes. So if we change some hardware then we
MUST modify our software, which was not our customer’s expectation. In x86 world,
we have UEFI and ACPI technologies, they are suitable to solve this problem very
well, we just upgrade our hardware and don’t need to upgrade their software,
in the meantime ACPI provides many methods on power management.
In ARM64 world, we are aiming the same thing. Following the SBBR,SBSA specs
to implement our UEFI and ACPI code, we think the patch set and arm-acpi
documentation are fine , and consider it is going on the right direction, so
Thanks a lot!

Regards,
Hanjun
Arnd Bergmann
2015-01-06 20:49:21 UTC
Permalink
Post by liyi 00215672
In traditional telecom market, what confused us(Huawei) was our software
and hardware coupling together oftentimes. So if we change some hardware
then we MUST modify our software, which was not our customer’s
expectation. In x86 world, we have UEFI and ACPI technologies, they are
suitable to solve this problem very well, we just upgrade our hardware
and don’t need to upgrade their software, in the meantime ACPI provides
many methods on power management.
Can you give an example of how ACPI solves the problem of supporting a
particular piece of new hardware?

I assume that for a completely new SoC, it won't help because you
still need device drivers for all the major parts of the hardware
that have changed, so this is about parts of the system that can
be abstracted in AML but not fully described in DT without the need
for new device drivers. Which are the main ones you are interested in
here?

Arnd
Christoffer Dall
2015-01-19 20:33:28 UTC
Permalink
Hi,
Post by Hanjun Guo
Add documentation for the guidelines of how to use ACPI
on ARM64.
---
Documentation/arm64/arm-acpi.txt | 327 +++++++++++++++++++++++++++++++++++++++
1 file changed, 327 insertions(+)
create mode 100644 Documentation/arm64/arm-acpi.txt
diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt
new file mode 100644
index 0000000..21e7020
--- /dev/null
+++ b/Documentation/arm64/arm-acpi.txt
@@ -0,0 +1,327 @@
+ACPI on ARMv8 Servers
+---------------------
+ACPI can be used for ARMv8 general purpose servers designed to follow
+the ARM SBSA (Server Base System Architecture) and SBBR (Server Base
+Boot Requirements) specifications, currently available to those with
+an ARM login at http://silver.arm.com.
+
+The ARMv8 kernel implements the reduced hardware model of ACPI version
+5.1 and later. Links to the specification and all external documents
+it refers to are managed by the UEFI Forum. The specification is
+available at http://www.uefi.org/specifications and external documents
+can be found via http://www.uefi.org/acpi.
+
+If an ARMv8 system does not meet the requirements of the SBSA, or cannot
+be described using the mechanisms defined in the required ACPI specifications,
+then it is likely that Device Tree (DT) is more suitable than ACPI for the
+hardware.
+
+
+Relationship with Device Tree
+-----------------------------
+ACPI support in drivers and subsystems for ARMv8 should never be mutually
+exclusive with DT support at compile time.
+
+At boot time the kernel will only use one description method depending on
+parameters passed from the bootloader (including kernel bootargs).
+
+Regardless of whether DT or ACPI is used, the kernel must always be capable
+of booting with either scheme (in kernels with both schemes enabled at compile
+time).
+
+
+Booting using ACPI tables
+-------------------------
+The only defined method for passing ACPI tables to the kernel on ARMv8
+is via the UEFI system configuration table.
+
This is a bit concerning for the approach we are currently taking to
support ACPI on Xen [1].

Background: Xen is a tiny hypervisor which cannot parse the DSDT or any
other non-static table. Xen relies on Linux in Dom0 to manage most
(basically everything except the GIC, serial port, SMMU, and timers)
hardware resources and relies on Dom0 to parse the ACPI tables.

While Xen itself is typically booted by UEFI and finds RSDP through the
UEFI system table, Xen does NOT run another UEFI instance to boot Dom0
nor does it pass through the presence of UEFI to Dom0 in any way.
Instead, it just created a DT (with modifications concerning the
hardware mentioned above) and boots Linux in Dom0 directly (on x86 any
required UEFI call is performed through paravirtualized hypercalls).

In the case of ACPI, Xen adds a property to the chosen node and
populates it with the RDSP in Dom0's address space. Patches have not
been posted yet, but we do have a working prototype of the
implementation and the Linux changes are minimal to support this
approach. Parth Dixit (cc'ed) can provide more details on this if
needed/wanted.

With the current wording in this patch, it seems Xen is forced to
emulate EFI or run a full UEFI instance for Dom0 which results in a
really heavy boot sequnce for Xen. Should we be concerned about this
use case at this point and does anyone have suggestions on how to solve
this?

[1]: https://wiki.linaro.org/LEG/Engineering/Virtualization/ACPI_on_Xen

Thanks,
-Christoffer
Hanjun Guo
2015-01-21 12:37:00 UTC
Permalink
Hi Christoffer,

Sorry for the late reply, I got no answer yet but
with one question below.
Post by Christoffer Dall
Hi,
Post by Hanjun Guo
Add documentation for the guidelines of how to use ACPI
on ARM64.
---
Documentation/arm64/arm-acpi.txt | 327 +++++++++++++++++++++++++++++++++++++++
1 file changed, 327 insertions(+)
create mode 100644 Documentation/arm64/arm-acpi.txt
diff --git a/Documentation/arm64/arm-acpi.txt b/Documentation/arm64/arm-acpi.txt
new file mode 100644
index 0000000..21e7020
--- /dev/null
+++ b/Documentation/arm64/arm-acpi.txt
@@ -0,0 +1,327 @@
+ACPI on ARMv8 Servers
+---------------------
+ACPI can be used for ARMv8 general purpose servers designed to follow
+the ARM SBSA (Server Base System Architecture) and SBBR (Server Base
+Boot Requirements) specifications, currently available to those with
+an ARM login at http://silver.arm.com.
+
+The ARMv8 kernel implements the reduced hardware model of ACPI version
+5.1 and later. Links to the specification and all external documents
+it refers to are managed by the UEFI Forum. The specification is
+available at http://www.uefi.org/specifications and external documents
+can be found via http://www.uefi.org/acpi.
+
+If an ARMv8 system does not meet the requirements of the SBSA, or cannot
+be described using the mechanisms defined in the required ACPI specifications,
+then it is likely that Device Tree (DT) is more suitable than ACPI for the
+hardware.
+
+
+Relationship with Device Tree
+-----------------------------
+ACPI support in drivers and subsystems for ARMv8 should never be mutually
+exclusive with DT support at compile time.
+
+At boot time the kernel will only use one description method depending on
+parameters passed from the bootloader (including kernel bootargs).
+
+Regardless of whether DT or ACPI is used, the kernel must always be capable
+of booting with either scheme (in kernels with both schemes enabled at compile
+time).
+
+
+Booting using ACPI tables
+-------------------------
+The only defined method for passing ACPI tables to the kernel on ARMv8
+is via the UEFI system configuration table.
+
This is a bit concerning for the approach we are currently taking to
support ACPI on Xen [1].
Background: Xen is a tiny hypervisor which cannot parse the DSDT or any
other non-static table. Xen relies on Linux in Dom0 to manage most
(basically everything except the GIC, serial port, SMMU, and timers)
hardware resources and relies on Dom0 to parse the ACPI tables.
While Xen itself is typically booted by UEFI and finds RSDP through the
UEFI system table, Xen does NOT run another UEFI instance to boot Dom0
nor does it pass through the presence of UEFI to Dom0 in any way.
Instead, it just created a DT (with modifications concerning the
hardware mentioned above) and boots Linux in Dom0 directly (on x86 any
required UEFI call is performed through paravirtualized hypercalls).
In the case of ACPI, Xen adds a property to the chosen node and
populates it with the RDSP in Dom0's address space. Patches have not
Sorry I'm not familiar with hypervisor, I have question here about
x86 on xen, how ACPI works on XEN for x86?

Thanks
Hanjun
Stefano Stabellini
2015-01-21 13:03:04 UTC
Permalink
Post by Hanjun Guo
Hi Christoffer,
Sorry for the late reply, I got no answer yet but
with one question below.
Post by Christoffer Dall
Hi,
Post by Hanjun Guo
Add documentation for the guidelines of how to use ACPI
on ARM64.
---
Documentation/arm64/arm-acpi.txt | 327
+++++++++++++++++++++++++++++++++++++++
1 file changed, 327 insertions(+)
create mode 100644 Documentation/arm64/arm-acpi.txt
diff --git a/Documentation/arm64/arm-acpi.txt
b/Documentation/arm64/arm-acpi.txt
new file mode 100644
index 0000000..21e7020
--- /dev/null
+++ b/Documentation/arm64/arm-acpi.txt
@@ -0,0 +1,327 @@
+ACPI on ARMv8 Servers
+---------------------
+ACPI can be used for ARMv8 general purpose servers designed to follow
+the ARM SBSA (Server Base System Architecture) and SBBR (Server Base
+Boot Requirements) specifications, currently available to those with
+an ARM login at http://silver.arm.com.
+
+The ARMv8 kernel implements the reduced hardware model of ACPI version
+5.1 and later. Links to the specification and all external documents
+it refers to are managed by the UEFI Forum. The specification is
+available at http://www.uefi.org/specifications and external documents
+can be found via http://www.uefi.org/acpi.
+
+If an ARMv8 system does not meet the requirements of the SBSA, or cannot
+be described using the mechanisms defined in the required ACPI specifications,
+then it is likely that Device Tree (DT) is more suitable than ACPI for the
+hardware.
+
+
+Relationship with Device Tree
+-----------------------------
+ACPI support in drivers and subsystems for ARMv8 should never be mutually
+exclusive with DT support at compile time.
+
+At boot time the kernel will only use one description method depending on
+parameters passed from the bootloader (including kernel bootargs).
+
+Regardless of whether DT or ACPI is used, the kernel must always be capable
+of booting with either scheme (in kernels with both schemes enabled at compile
+time).
+
+
+Booting using ACPI tables
+-------------------------
+The only defined method for passing ACPI tables to the kernel on ARMv8
+is via the UEFI system configuration table.
+
This is a bit concerning for the approach we are currently taking to
support ACPI on Xen [1].
Background: Xen is a tiny hypervisor which cannot parse the DSDT or any
other non-static table. Xen relies on Linux in Dom0 to manage most
(basically everything except the GIC, serial port, SMMU, and timers)
hardware resources and relies on Dom0 to parse the ACPI tables.
While Xen itself is typically booted by UEFI and finds RSDP through the
UEFI system table, Xen does NOT run another UEFI instance to boot Dom0
nor does it pass through the presence of UEFI to Dom0 in any way.
Instead, it just created a DT (with modifications concerning the
hardware mentioned above) and boots Linux in Dom0 directly (on x86 any
required UEFI call is performed through paravirtualized hypercalls).
In the case of ACPI, Xen adds a property to the chosen node and
populates it with the RDSP in Dom0's address space. Patches have not
Sorry I'm not familiar with hypervisor, I have question here about
x86 on xen, how ACPI works on XEN for x86?
The whole thing works differently on x86: on native x86 the OS finds the
RDSP by scanning a couple of memory regions looking for the string "RSD
PTR".

Xen and Dom0 both do that independently (Dom0 can map that memory
region).
Christoffer Dall
2015-01-21 16:04:40 UTC
Permalink
Post by Hanjun Guo
Hi Christoffer,
Sorry for the late reply, I got no answer yet but
with one question below.
no worries, I think the discussion has moved to Stefano's e-mail:
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-January/318335.html

-Christoffer

Suthikulpanit, Suravee
2015-01-05 07:55:30 UTC
Permalink
Post by Hanjun Guo
Using the information presented by GTDT to initialize the arch
timer (not memory-mapped).
---
arch/arm64/kernel/time.c | 7 ++
drivers/clocksource/arm_arch_timer.c | 132
++++++++++++++++++++++++++++-------
include/linux/clocksource.h | 6 ++
3 files changed, 118 insertions(+), 27 deletions(-)
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 1a7125c..42f9195 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/clk-provider.h>
+#include <linux/acpi.h>
#include <clocksource/arm_arch_timer.h>
@@ -72,6 +73,12 @@ void __init time_init(void)
tick_setup_hrtimer_broadcast();
+ /*
+ * Since ACPI or FDT will only one be available in the system,
+ * we can use acpi_generic_timer_init() here safely
+ */
+ acpi_generic_timer_init();
+
arch_timer_rate = arch_timer_get_rate();
if (!arch_timer_rate)
panic("Unable to initialise architected timer.\n");
diff --git a/drivers/clocksource/arm_arch_timer.c
b/drivers/clocksource/arm_arch_timer.c
index 6a79fc4..612f2a0 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/sched_clock.h>
+#include <linux/acpi.h>
#include <asm/arch_timer.h>
#include <asm/virt.h>
@@ -370,8 +371,12 @@ arch_timer_detect_rate(void __iomem *cntbase, struct
device_node *np)
if (arch_timer_rate)
return;
- /* Try to determine the frequency from the device tree or CNTFRQ */
- if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
+ /*
+ * Try to determine the frequency from the device tree or CNTFRQ,
+ * if ACPI is enabled, get the frequency from CNTFRQ ONLY.
+ */
+ if (!acpi_disabled ||
+ of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
if (cntbase)
arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
else
@@ -690,28 +695,8 @@ static void __init arch_timer_common_init(void)
arch_timer_arch_init();
}
-static void __init arch_timer_init(struct device_node *np)
+static void __init arch_timer_init(void)
{
- int i;
-
- if (arch_timers_present & ARCH_CP15_TIMER) {
- pr_warn("arch_timer: multiple nodes in dt, skipping\n");
- return;
- }
-
- arch_timers_present |= ARCH_CP15_TIMER;
- for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
- arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
- arch_timer_detect_rate(NULL, np);
-
- /*
- * If we cannot rely on firmware initializing the timer registers then
- * we should use the physical timers instead.
- */
- if (IS_ENABLED(CONFIG_ARM) &&
- of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
- arch_timer_use_virtual = false;
-
/*
* If HYP mode is available, we know that the physical timer
* has been configured to be accessible from PL1. Use it, so
@@ -730,13 +715,39 @@ static void __init arch_timer_init(struct
device_node *np)
}
}
- arch_timer_c3stop = !of_property_read_bool(np, "always-on");
-
arch_timer_register();
arch_timer_common_init();
}
-CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer",
arch_timer_init);
-CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer",
arch_timer_init);
+
+static void __init arch_timer_of_init(struct device_node *np)
+{
+ int i;
+
+ if (arch_timers_present & ARCH_CP15_TIMER) {
+ pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+ return;
+ }
+
+ arch_timers_present |= ARCH_CP15_TIMER;
+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+ arch_timer_detect_rate(NULL, np);
+
+ arch_timer_c3stop = !of_property_read_bool(np, "always-on");
+
+ /*
+ * If we cannot rely on firmware initializing the timer registers then
+ * we should use the physical timers instead.
+ */
+ if (IS_ENABLED(CONFIG_ARM) &&
+ of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
+ arch_timer_use_virtual = false;
+
+ arch_timer_init();
+}
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer",
arch_timer_of_init);
+CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer",
arch_timer_of_init);
Hanjun,

FYI, it seems that the tree that you have rebased the patch series has an
issue determining clocksource in ARM64 introduced by this commit.

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0
b46b8a718c6e90910a1b1b0fe797be3c167e186

Here is the fix from Catalin that already went upstream:

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drive
rs/clocksource/arm_arch_timer.c?id=d6ad36913083d683aad4e02e53580c995f1a6ede

Thanks,

Suravee
Hanjun Guo
2015-01-05 08:59:44 UTC
Permalink
Post by Suthikulpanit, Suravee
Post by Hanjun Guo
Using the information presented by GTDT to initialize the arch
timer (not memory-mapped).
---
arch/arm64/kernel/time.c | 7 ++
drivers/clocksource/arm_arch_timer.c | 132
++++++++++++++++++++++++++++-------
include/linux/clocksource.h | 6 ++
3 files changed, 118 insertions(+), 27 deletions(-)
[...]
Post by Suthikulpanit, Suravee
Post by Hanjun Guo
+static void __init arch_timer_of_init(struct device_node *np)
+{
+ int i;
+
+ if (arch_timers_present & ARCH_CP15_TIMER) {
+ pr_warn("arch_timer: multiple nodes in dt, skipping\n");
+ return;
+ }
+
+ arch_timers_present |= ARCH_CP15_TIMER;
+ for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
+ arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
+
+ arch_timer_detect_rate(NULL, np);
+
+ arch_timer_c3stop = !of_property_read_bool(np, "always-on");
+
+ /*
+ * If we cannot rely on firmware initializing the timer registers then
+ * we should use the physical timers instead.
+ */
+ if (IS_ENABLED(CONFIG_ARM) &&
+ of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
+ arch_timer_use_virtual = false;
+
+ arch_timer_init();
+}
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer",
arch_timer_of_init);
+CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer",
arch_timer_of_init);
Hanjun,
FYI, it seems that the tree that you have rebased the patch series has an
issue determining clocksource in ARM64 introduced by this commit.
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0
b46b8a718c6e90910a1b1b0fe797be3c167e186
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drive
rs/clocksource/arm_arch_timer.c?id=d6ad36913083d683aad4e02e53580c995f1a6ede
This bug fix patch was merged in Dec 30 by Linus, which is the date
after 3.19-rc2 released :)

Thanks
Hanjun
Yijing Wang
2015-01-06 07:05:48 UTC
Permalink
Hi,
Hello Hanjun,

We tested your v5 patch set (and added some GICv3 patches) on Hisilicon ARM64 SoC hardware,
from your change log for v6, there is only one functional change to fix the NULL pointer, I think
the test result is still valid for v6, please refer to the test result below [1].

We can boot the system successfully using PSCI on our ARM64 hardware using this patch set, of course
we need to add some more patches (GICv3), but with this patch set:

You could add my Tested-by: Yijing Wang <***@huawei.com> if you want.

if you want me to test the new version of patch set, please let me know, thanks.

[1]:
fs0:\>start Image "initrd=fs.cpio.gz console=ttyS0,115200 acpi=force earlycon=uart8250,mmio32,0x60300000"
Loading driver at 0x0003652F000 EntryPoint=0x00036BF1760
EFI stub: Booting Linux Kernel...
Initializing cgroup subsys cpu
Linux version 3.18.0+ (***@linux) (gcc version 4.8.3 20140401 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.04 - Linaro GCC
4.8-2014.04) ) #126 SMP PREEMPT Mon Dec 15 20:33:16 CST 2014
CPU: AArch64 Processor [411fd071] revision 1
Detected PIPT I-cache on CPU0
Early serial console at MMIO32 0x60300000 (options '')
bootconsole [uart0] enabled
efi: Getting EFI parameters from FDT:
EFI v2.40 by ARM Versatile Express EFI Dec 17 2014 10:32:11
efi: SMBIOS=0x3bce8000 ACPI=0x36d08000 ACPI 2.0=0x36d08014
Ignoring memory block 0x0 - 0x1000
Ignoring memory block 0x1000 - 0x2000
Ignoring memory range 0x2000 - 0x200000
cma: Reserved 16 MiB at 0x0000000038400000
ACPI: Early table checksum verification disabled
ACPI: RSDP 0x0000000036D08014 000024 (v02 ARMLTD)
ACPI: XSDT 0x0000000036D070E8 00005C (v01 ARMLTD ARMPV660 20140727 01000013)
ACPI: FACP 0x0000000036D05000 00010C (v05 ARMLTD ARMPV660 20140727 HISI 00000099)
ACPI: DSDT 0x0000000036CFE000 000298 (v01 ARMLTD ARM-JUNO 20140727 INTL 20140828)
ACPI: GTDT 0x0000000036D04000 000060 (v01 ARMLTD ARMPV660 20140727 HISI 00000099)
ACPI: APIC 0x0000000036D02000 0005C0 (v01 ARMLTD ARMPV660 20140727 HISI 00000099)
ACPI: MCFG 0x0000000036D01000 00003C (v01 ARMLTD ARMPV660 20140727 HISI 00000099)
psci: probing for conduit method from ACPI.
psci: Using standard PSCI v0.2 function IDs
ACPI: GICC (acpi_id[0x0000] address[00000000fe000000] MPDIR[0x20000] enabled)
ACPI: GICC (acpi_id[0x0001] address[00000000fe000000] MPDIR[0x20001] enabled)
ACPI: GICC (acpi_id[0x0002] address[00000000fe000000] MPDIR[0x20002] enabled)
ACPI: GICC (acpi_id[0x0003] address[00000000fe000000] MPDIR[0x20003] enabled)
ACPI: GICC (acpi_id[0x0004] address[00000000fe000000] MPDIR[0x20100] enabled)
ACPI: GICC (acpi_id[0x0005] address[00000000fe000000] MPDIR[0x20101] enabled)
ACPI: GICC (acpi_id[0x0006] address[00000000fe000000] MPDIR[0x20102] enabled)
ACPI: GICC (acpi_id[0x0007] address[00000000fe000000] MPDIR[0x20103] enabled)
ACPI: GICC (acpi_id[0x0008] address[00000000fe000000] MPDIR[0x20200] enabled)
ACPI: GICC (acpi_id[0x0009] address[00000000fe000000] MPDIR[0x20201] enabled)
ACPI: GICC (acpi_id[0x000a] address[00000000fe000000] MPDIR[0x20202] enabled)
ACPI: GICC (acpi_id[0x000b] address[00000000fe000000] MPDIR[0x20203] enabled)
ACPI: GICC (acpi_id[0x000c] address[00000000fe000000] MPDIR[0x20300] enabled)
ACPI: GICC (acpi_id[0x000d] address[00000000fe000000] MPDIR[0x20301] enabled)
ACPI: GICC (acpi_id[0x000e] address[00000000fe000000] MPDIR[0x20302] enabled)
ACPI: GICC (acpi_id[0x000f] address[00000000fe000000] MPDIR[0x20303] enabled)
ACPI: 16 CPUs enabled, 16 CPUs total
PERCPU: Embedded 13 pages/cpu @ffffffc038130000 s14208 r8192 d30848 u53248
Built 1 zonelists in Node order, mobility grouping on. Total pages: 241895
Policy zone: DMA
Kernel command line: initrd=hulk-image-fat.cpio.gz console=ttyS0,115200 acpi=force earlycon=uart8250,mmio32,0x60300000
log_buf_len individual max cpu contribution: 4096 bytes
log_buf_len total cpu_extra contributions: 61440 bytes
log_buf_len min size: 16384 bytes
log_buf_len: 131072 bytes
early log buf free: 9968(60%)
PID hash table entries: 4096 (order: 3, 32768 bytes)
Memory: 889320K/980992K available (5006K kernel code, 358K rwdata, 1892K rodata, 268K init, 236K bss, 91672K reserved)
Virtual kernel memory layout:
vmalloc : 0xffffff8000000000 - 0xffffffbdffff0000 ( 247 GB)
vmemmap : 0xffffffbe00000000 - 0xffffffbfc0000000 ( 7 GB maximum)
0xffffffbe00007000 - 0xffffffbe00d20000 ( 13 MB actual)
PCI I/O : 0xffffffbffa000000 - 0xffffffbffb000000 ( 16 MB)
fixed : 0xffffffbffbdfe000 - 0xffffffbffbdff000 ( 4 KB)
modules : 0xffffffbffc000000 - 0xffffffc000000000 ( 64 MB)
memory : 0xffffffc000000000 - 0xffffffc03be00000 ( 958 MB)
.init : 0xffffffc00073e000 - 0xffffffc000781000 ( 268 KB)
.text : 0xffffffc000080000 - 0xffffffc00073d0b4 ( 6901 KB)
.data : 0xffffffc000781000 - 0xffffffc0007daa00 ( 359 KB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=16, Nodes=1
Preemptible hierarchical RCU implementation.
RCU restricting CPUs from NR_CPUS=32 to nr_cpu_ids=16.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=16
NR_IRQS:64 nr_irqs:64 0
ITS: ID: 0x0
ITS: allocated 512 Devices @3700e000 (psz 4K, shr 1)
ITS: allocated 512 Virtual CPUs @3700f000 (psz 4K, shr 1)
ITS: allocated 512 Interrupt Collections @37020000 (psz 4K, shr 1)
ITS: ID: 0x1
ITS: allocated 512 Devices @37021000 (psz 4K, shr 1)
ITS: allocated 512 Virtual CPUs @37022000 (psz 4K, shr 1)
ITS: allocated 512 Interrupt Collections @37023000 (psz 4K, shr 1)
ITS: ID: 0x2
ITS: allocated 512 Devices @37024000 (psz 4K, shr 1)
ITS: allocated 512 Virtual CPUs @37025000 (psz 4K, shr 1)
ITS: allocated 512 Interrupt Collections @37026000 (psz 4K, shr 1)
ITS: ID: 0x3
ITS: allocated 512 Devices @37028000 (psz 4K, shr 1)
ITS: allocated 512 Virtual CPUs @37029000 (psz 4K, shr 1)
ITS: allocated 512 Interrupt Collections @3702a000 (psz 4K, shr 1)
ITS: ID: 0x4
ITS: allocated 512 Devices @3702b000 (psz 4K, shr 1)
ITS: allocated 512 Virtual CPUs @3702c000 (psz 4K, shr 1)
ITS: allocated 512 Interrupt Collections @3702d000 (psz 4K, shr 1)
GIC: using LPI property table @37070000
ITS: Allocated 1792 chunks for LPIs
CPU0: found redistributor 20000 region 0:6d100000
CPU0: using LPI pending table @37080000
ACPI: 1 GICD entry detected
clocksource_of_init: no matching clocksources found
Architected cp15 timer(s) running at 50.00MHz (phys).
sched_clock: 56 bits at 50MHz, resolution 20ns, wraps every 2748779069440ns
Console: colour dummy device 80x25
allocated 4194304 bytes of page_cgroup
please try 'cgroup_disable=memory' option if you don't want memory cgroups
Calibrating delay loop (skipped), value calculated using timer frequency.. 100.00 BogoMIPS (lpj=500000)
pid_max: default: 32768 minimum: 301
ACPI: Core revision 20140926
ACPI: All ACPI Tables successfully acquired
Security Framework initialized
Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
Initializing cgroup subsys memory
Initializing cgroup subsys hugetlb
No CPU information found in DT
hw perfevents: enabled with arm/armv8-pmuv3 PMU driver, 7 counters available
Remapping and enabling EFI services.
Freed 0x2a8f000 bytes of EFI boot services memory
CPU1: Booted secondary processor
Detected PIPT I-cache on CPU1
CPU1: found redistributor 20001 region 0:6d130000
CPU1: using LPI pending table @37360000
CPU2: Booted secondary processor
Detected PIPT I-cache on CPU2
CPU2: found redistributor 20002 region 0:6d160000
CPU2: using LPI pending table @373a0000
CPU3: Booted secondary processor
Detected PIPT I-cache on CPU3
CPU3: found redistributor 20003 region 0:6d190000
CPU3: using LPI pending table @373d0000
CPU4: Booted secondary processor
Detected PIPT I-cache on CPU4
CPU4: found redistributor 20100 region 0:6d1c0000
CPU4: using LPI pending table @3b410000
CPU5: Booted secondary processor
Detected PIPT I-cache on CPU5
CPU5: found redistributor 20101 region 0:6d1f0000
CPU5: using LPI pending table @3b440000
CPU6: Booted secondary processor
Detected PIPT I-cache on CPU6
CPU6: found redistributor 20102 region 0:6d220000
CPU6: using LPI pending table @3b470000
CPU7: Booted secondary processor
Detected PIPT I-cache on CPU7
CPU7: found redistributor 20103 region 0:6d250000
CPU7: using LPI pending table @3b4b0000
CPU8: Booted secondary processor
Detected PIPT I-cache on CPU8
CPU8: found redistributor 20200 region 0:6d280000
CPU8: using LPI pending table @3b4e0000
CPU9: Booted secondary processor
Detected PIPT I-cache on CPU9
CPU9: found redistributor 20201 region 0:6d2b0000
CPU9: using LPI pending table @3b520000
CPU10: Booted secondary processor
Detected PIPT I-cache on CPU10
CPU10: found redistributor 20202 region 0:6d2e0000
CPU10: using LPI pending table @3b550000
CPU11: Booted secondary processor
Detected PIPT I-cache on CPU11
CPU11: found redistributor 20203 region 0:6d310000
CPU11: using LPI pending table @3b590000
CPU12: Booted secondary processor
Detected PIPT I-cache on CPU12
CPU12: found redistributor 20300 region 0:6d340000
CPU12: using LPI pending table @3b5c0000
CPU13: Booted secondary processor
Detected PIPT I-cache on CPU13
CPU13: found redistributor 20301 region 0:6d370000
CPU13: using LPI pending table @3b600000
CPU14: Booted secondary processor
Detected PIPT I-cache on CPU14
CPU14: found redistributor 20302 region 0:6d3a0000
CPU14: using LPI pending table @3b630000
CPU15: Booted secondary processor
Detected PIPT I-cache on CPU15
CPU15: found redistributor 20303 region 0:6d3d0000
CPU15: using LPI pending table @3b670000
Brought up 16 CPUs
SMP: Total of 16 processors activated.
devtmpfs: initialized
regulator-dummy: no parameters
NET: Registered protocol family 16
cpuidle: using governor ladder
cpuidle: using governor menu
vdso: 2 pages (1 code @ ffffffc000789000, 1 data @ ffffffc000788000)
hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
software IO TLB [mem 0x3b000000-0x3b400000] (4MB) mapped at [ffffffc03ae00000-ffffffc03b1fffff]
DMA: preallocated 256 KiB pool for atomic allocations
ACPI: bus type PCI registered
Serial: AMBA PL011 UART driver
ACPI: Added _OSI(Module Device)
ACPI: Added _OSI(Processor Device)
ACPI: Added _OSI(3.0 _SCP Extensions)
ACPI: Added _OSI(Processor Aggregator Device)
ACPI: Interpreter enabled
ACPI: Using GIC for interrupt routing
PCI: no memory for MCFG
entries
vgaarb: loaded
SCSI subsystem initialized
ACPI: bus type USB registered
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Switched to clocksource arch_sys_counter
pnp: PnP ACPI init
pnp: PnP ACPI: found 0 devices
NET: Registered protocol family 2
TCP established hash table entries: 8192 (order: 4, 65536 bytes)
TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP: reno registered
UDP hash table entries: 512 (order: 2, 16384 bytes)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
Unpacking initramfs...
Freeing initrd memory: 8212K (ffffffc01f5fb000 - ffffffc01fe00000)
futex hash table entries: 4096 (order: 6, 262144 bytes)
audit: initializing netlink subsys (disabled)
audit: type=2000 audit(1.150:1): initialized
HugeTLB registered 2 MB page size, pre-allocated 0 pages
fuse init (API version 7.23)
9p: Installing v9fs 9p2000 file system support
msgmni has been set to 1870
io scheduler noop registered
io scheduler cfq registered (default)
Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
console [ttyS0] disabled
dw-apb-uart ARMH0011:00: ttyS0 at MMIO 0x60300000 (irq = 3, base_baud = 12500000) is a 16550A
console [ttyS0] enabled
console [ttyS0] enabled
bootconsole [uart0] disabled
bootconsole [uart0] disabled
loop: module loaded
tun: Universal TUN/TAP device driver, 1.6
tun: (C) 1999-2004 Max Krasnyansky <***@qualcomm.com>
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
ehci-pci: EHCI PCI platform driver
ehci-platform: EHCI generic platform driver
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
ohci-pci: OHCI PCI platform driver
ohci-platform: OHCI generic platform driver
usbcore: registered new interface driver usb-storage
mousedev: PS/2 mouse device common for all mice
rtc_efi: EFI year < 1998, invalid date
rtc-efi rtc-efi: rtc core: registered rtc-efi as rtc0
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
sdhci-pltfm: SDHCI platform and OF driver helper
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
TCP: cubic registered
NET: Registered protocol family 17
9pnet: Installing 9P2000 support
registered taskstats version
1
rtc_efi: EFI year < 1998, invalid date
rtc-efi rtc-efi: hctosys: unable to read the hardware clock
ttyS0 - failed to request DMA
Freeing unused kernel memory: 268K (ffffffc00073e000 - ffffffc000781000)
root@(none)$

Thanks!
Yijing.
This is the sixth version of ACPI core patches for ARM64 based on ACPI
5.1.
- fix the NULL pointer reference in cpu_get_ops() if PSCI is absent
and NULL will passed, which found by Suravee when he was testing
those patches on Seattle platform. I added his Tested-by for all
those ACPI patches.
- Rebased on 3.19-rc2 which ACPI table related patches already merged
into 3.19 by Rafael, and remove the first patch in v5 which is not needed
any more.
- Add two cleanup patches to convert ACPI ID to physical ID to make the
ACPI core looks more ARCH agnostic, those two patches were expected going
into 3.19 but conflicted with IOAPIC hotplug patches so Rafael left them
for 3.20.
- updates to the doc about ACPI on ARM to address comments from Catalin,
Timur, Ashwin. continue discussion will bw needed about this doc.
- we did lots of work as Al pointed out in the "[RFC] ACPI on arm64 TODO List"
thread [1], and we already make FWTS running on ARM64, thanks FuWei for doing
Test report for leg-20141215.0 (Revision: d37eefeb160cc9cc1db997031793723e317be7b7)
This test Image comes from https://ci.linaro.org/job/linux-leg-fuwei
The CI job Link: https://ci.linaro.org/job/linux-leg-fuwei/37/
Notes : All the tests ran on FVP base model in LAVA server : http://validation.linaro.org/
The startup.nsh boot test Link :https://validation.linaro.org/scheduler/job/222779
The ACPI test Link : https://validation.linaro.org/scheduler/job/222781
The results.log file Link : https://validation.linaro.org/dashboard/attachment/1267957/view
The grub-install test Link : https://validation.linaro.org/scheduler/job/222780
summary -SUM:77 passed, 6 failed, 2 warnings, 5 aborted, 186 skipped, 8 info only.
summary -SUM:Test Failure Summary
summary -SEP:===========================================================================================
summary -SUM:Critical failures: NONE
summary -SUM:High failures: 2
summary -SUM: uefirttime: Failed to get wakeup time with UEFI runtime service.
summary -SUM: uefirttime: Failed to set wakeup time with UEFI runtime service.
summary -SUM:Medium failures: 5
summary -SUM: wakealarm: Could not find an RTC with an alarm ioctl() interface.
summary -SUM: method: \_SB_.COM0._CID returned a string 'PL011' but it was not a valid PNP ID or a valid ACPI ID.
summary -SUM: method: Object _PRS did not exist.
summary -SUM: method: Object _PTS did not exist.
summary -SUM: method: Object _WAK did not exist.
summary -SUM:Low failures: NONE
summary -SUM:Other failures: NONE
summary -SUM:Test |Pass |Fail |Abort|Warn |Skip |Info |
summary -SUM:---------------+-----+-----+-----+-----+-----+-----+
summary -SUM:acpidump | | | | | | 1|
summary -SUM:acpiinfo | | | | | | 3|
summary -SUM:acpitables | 11| | | 1| | |
summary -SUM:aspm | | | | | 1| |
summary -SUM:checksum | 8| | | | | |
summary -SUM:cpufreq | | | | 1| | |
summary -SUM:crsdump | | | | | | |
summary -SUM:gpedump | | | | | | |
summary -SUM:hda_audio | | | | | 1| |
summary -SUM:klog | 1| | | | | |
summary -SUM:maxreadreq | | | | | | |
summary -SUM:method | 29| 4| | | 173| |
summary -SUM:oops | 2| | | | | |
summary -SUM:plddump | | | | | | |
summary -SUM:prsdump | | | | | | |
summary -SUM:securebootcert | | | 1| | | |
summary -SUM:syntaxcheck | 1| | | | | |
summary -SUM:uefibootpath | 1| | | | | |
summary -SUM:uefidump | | | | | | |
summary -SUM:uefirtmisc | 2| | | | 10| |
summary -SUM:uefirttime | 2| 2| | | | |
summary -SUM:uefirtvariable | 20| | | | | |
summary -SUM:uefivarinfo | | | | | | |
summary -SUM:version | | | | | 1| 4|
summary -SUM:wakealarm | | | 4| | | |
summary -SUM:---------------+-----+-----+-----+-----+-----+-----+
summary -SUM:Total: | 77| 6| 5| 2| 186| 8|
summary -SUM:---------------+-----+-----+-----+-----+-----+-----+
[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-December/310921.html
Thanks
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
.
--
Thanks!
Yijing
Hanjun Guo
2015-01-06 11:17:23 UTC
Permalink
Post by Yijing Wang
Hi,
Hello Hanjun,
We tested your v5 patch set (and added some GICv3 patches) on Hisilicon ARM64 SoC hardware,
from your change log for v6, there is only one functional change to fix the NULL pointer, I think
the test result is still valid for v6, please refer to the test result below [1].
We can boot the system successfully using PSCI on our ARM64 hardware using this patch set, of course
Great, thanks a lot!
Post by Yijing Wang
if you want me to test the new version of patch set, please let me know, thanks.
if you have some free time, please help me to do that :)

Thanks
Hanjun
Continue reading on narkive:
Loading...