Hi,
This is the sixth version of ACPI core patches for ARM64 based on ACPI 5.1.
updates from v5: - 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 that. Here is the test results for linaro leg kernel release test results:
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
and here is the *summary*:
summary -SUM:77 passed, 6 failed, 2 warnings, 5 aborted, 186 skipped, 8 info only. summary -NLN: summary -SUM:Test Failure Summary summary -SEP:=========================================================================================== summary -NLN: summary -SUM:Critical failures: NONE summary -NLN: 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 -NLN: 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 -NLN: summary -SUM:Low failures: NONE summary -NLN: summary -SUM:Other failures: NONE summary -NLN: 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.h...
Thanks
From: Hanjun Guo 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 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 */
On Sunday, January 04, 2015 06:55:02 PM Hanjun Guo wrote:
From: Hanjun Guo 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 hanjun.guo@linaro.org
I've queued up this one and [2/17] for 3.19-rc4 as I promised I'd push these two for 3.19.
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))
} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {if (!map_lapic_id(header, acpi_id, &phys_id)) break;
if (!map_x2apic_id(header, type, acpi_id, &apic_id))
} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {if (!map_x2apic_id(header, type, acpi_id, &phys_id)) break;
if (!map_lsapic_id(header, type, acpi_id, &apic_id))
} entry += header->length; }if (!map_lsapic_id(header, type, acpi_id, &phys_id)) break;
- 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);
else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)map_lapic_id(header, acpi_id, &phys_id);
map_lsapic_id(header, type, acpi_id, &apic_id);
else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)map_lsapic_id(header, type, acpi_id, &phys_id);
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 */
On 2015年01月07日 09:50, Rafael J. Wysocki wrote:
On Sunday, January 04, 2015 06:55:02 PM Hanjun Guo wrote:
From: Hanjun Guo 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 hanjun.guo@linaro.org
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
From: Hanjun Guo 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 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);
From: Al Stone 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 Suravee.Suthikulpanit@amd.com Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo 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 hanjun.guo@linaro.org + * Author: Graeme Gregory 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 al.stone@linaro.org + * Author: Graeme Gregory graeme.gregory@linaro.org + * Author: Hanjun Guo 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 al.stone@linaro.org + * Author: Graeme Gregory graeme.gregory@linaro.org + * Author: Hanjun Guo hanjun.guo@linaro.org + * Author: Tomasz Nowicki tomasz.nowicki@linaro.org + * Author: Naresh Bhat naresh.bhat@linaro.org + * + * 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();
From: Graeme Gregory 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 Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo 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 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; +}
From: Al Stone 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 Suravee.Suthikulpanit@amd.com Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo 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();
/*
From: Graeme Gregory 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 Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Hanjun Guo 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();
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 Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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;
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 Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki 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
On Sun, Jan 04, 2015 at 10:55:09AM +0000, Hanjun Guo wrote:
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 ?
Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki 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);
Is not there a better way to avoid this function dt/acpi duplication ?
#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 ?
- return -EINVAL;
+}
/*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- check ACPI FADT revisoin
s/revisoin/revision
- 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 ?
} 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 ?
+{
- 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;
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
+}
#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
On 2015年01月10日 03:04, Lorenzo Pieralisi wrote:
On Sun, Jan 04, 2015 at 10:55:09AM +0000, Hanjun Guo wrote:
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 ?
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?
Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Tomasz Nowicki 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);
Is not there a better way to avoid this function dt/acpi duplication ?
#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 ?
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?
- return -EINVAL;
+}
- /*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- check ACPI FADT revisoin
s/revisoin/revision
Good catch, will update it.
- 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.
}
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.
+{
- 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;
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
On Mon, Jan 12, 2015 at 04:26:41AM +0000, Hanjun Guo wrote:
On 2015年01月10日 03:04, Lorenzo Pieralisi wrote:
On Sun, Jan 04, 2015 at 10:55:09AM +0000, Hanjun Guo wrote:
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 ?
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.
[...]
+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 ?
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;
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.
- 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.
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.
- return -EINVAL;
+}
- /*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- check ACPI FADT revisoin
s/revisoin/revision
Good catch, will update it.
- 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.
}
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 :)
[...]
-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
On 2015年01月12日 19:41, Lorenzo Pieralisi wrote:
On Mon, Jan 12, 2015 at 04:26:41AM +0000, Hanjun Guo wrote:
On 2015年01月10日 03:04, Lorenzo Pieralisi wrote:
On Sun, Jan 04, 2015 at 10:55:09AM +0000, Hanjun Guo wrote:
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 ?
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.
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.
[...]
+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 ?
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;
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.
- 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.
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.
- return -EINVAL;
+}
- /*
- acpi_boot_table_init() called from setup_arch(), always.
- find RSDP and get its address, and then find XSDT
- extract all tables and checksums them all
- check ACPI FADT revisoin
s/revisoin/revision
Good catch, will update it.
* * 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.
}
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
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 Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki 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);
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 Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo hanjun.guo@linaro.org Signed-off-by: Tomasz Nowicki 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;
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 Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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);
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 amit.daniel@samsung.com Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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 };
From: Tomasz Nowicki 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 Suravee.Suthikulpanit@amd.com Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org Signed-off-by: Hanjun Guo 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 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_ */
Using the information presented by GTDT to initialize the arch timer (not memory-mapped).
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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 */
On 1/4/15, 04:55, "Hanjun Guo" hanjun.guo@linaro.org wrote:
Using the information presented by GTDT to initialize the arch timer (not memory-mapped).
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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 ||
if (cntbase) arch_timer_rate = readl_relaxed(cntbase + CNTFRQ); elseof_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
@@ -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
On 2015年01月05日 15:55, Suthikulpanit, Suravee wrote:
On 1/4/15, 04:55, "Hanjun Guo" hanjun.guo@linaro.org wrote:
Using the information presented by GTDT to initialize the arch timer (not memory-mapped).
Originally-by: Amit Daniel Kachhap amit.daniel@samsung.com Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Hanjun Guo 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(-)
[...]
+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
This bug fix patch was merged in Dec 30 by Linus, which is the date after 3.19-rc2 released :)
Thanks Hanjun
From: Al Stone 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 grant.likely@linaro.org Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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
From: Graeme Gregory 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 grant.likely@linaro.org Tested-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Reviewed-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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-UUI... + +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.
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 phoenix.liyi@huawei.com
-----邮件原件----- 发件人: Hanjun Guo [mailto:hanjun.guo@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-Tobin@arm.com; liyi 00215672; Timur Tabi; suravee.suthikulpanit@amd.com; linux-acpi@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linaro-acpi@lists.linaro.org; Al Stone; Hanjun Guo 主题: [PATCH v6 17/17] Documentation: ACPI for ARM64
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Reviewed-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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
Hi Yi,
On 2015年01月06日 17:52, liyi 00215672 wrote:
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 phoenix.liyi@huawei.com
Thanks a lot!
Regards, Hanjun
On Tuesday 06 January 2015 09:52:05 liyi 00215672 wrote:
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
Hi,
On Sun, Jan 04, 2015 at 06:55:18PM +0800, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Reviewed-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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.
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
Hi Christoffer,
Sorry for the late reply, I got no answer yet but with one question below.
On 2015年01月20日 04:33, Christoffer Dall wrote:
Hi,
On Sun, Jan 04, 2015 at 06:55:18PM +0800, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Reviewed-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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.
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
On Wed, 21 Jan 2015, Hanjun Guo wrote:
Hi Christoffer,
Sorry for the late reply, I got no answer yet but with one question below.
On 2015年01月20日 04:33, Christoffer Dall wrote:
Hi,
On Sun, Jan 04, 2015 at 06:55:18PM +0800, Hanjun Guo wrote:
From: Graeme Gregory graeme.gregory@linaro.org
Add documentation for the guidelines of how to use ACPI on ARM64.
Reviewed-by: Suravee Suthikulpanit Suravee.Suthikulpanit@amd.com Signed-off-by: Graeme Gregory graeme.gregory@linaro.org Signed-off-by: Al Stone al.stone@linaro.org Signed-off-by: Hanjun Guo 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.
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).
On Wed, Jan 21, 2015 at 08:37:00PM +0800, Hanjun Guo wrote:
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.ht...
-Christoffer
On 2015/1/4 18:55, Hanjun Guo wrote:
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 wangyijing@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+ (wkf@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 maxk@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.
updates from v5:
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 that. Here is the test results for linaro leg kernel release test results:
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
and here is the *summary*:
summary -SUM:77 passed, 6 failed, 2 warnings, 5 aborted, 186 skipped, 8 info only. summary -NLN: summary -SUM:Test Failure Summary summary -SEP:=========================================================================================== summary -NLN: summary -SUM:Critical failures: NONE summary -NLN: 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 -NLN: 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 -NLN: summary -SUM:Low failures: NONE summary -NLN: summary -SUM:Other failures: NONE summary -NLN: 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:---------------+-----+-----+-----+-----+-----+-----+
Thanks
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
.
On 2015年01月06日 15:05, Yijing Wang wrote:
On 2015/1/4 18:55, Hanjun Guo wrote:
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 wangyijing@huawei.com if you want.
Great, thanks a lot!
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