Skip to content

Commit 6149dff

Browse files
committed
Merge branches 'acpi-processor', 'acpi-cppc', 'acpi-apei' and 'acpi-sleep'
* acpi-processor: ACPI: enable ACPI_PROCESSOR_IDLE on ARM64 arm64: add support for ACPI Low Power Idle(LPI) drivers: firmware: psci: initialise idle states using ACPI LPI cpuidle: introduce CPU_PM_CPU_IDLE_ENTER macro for ARM{32, 64} arm64: cpuidle: drop __init section marker to arm_cpuidle_init ACPI / processor_idle: Add support for Low Power Idle(LPI) states ACPI / processor_idle: introduce ACPI_PROCESSOR_CSTATE * acpi-cppc: mailbox: pcc: Add PCC request and free channel declarations ACPI / CPPC: Prevent cpc_desc_ptr points to the invalid data ACPI: CPPC: Return error if _CPC is invalid on a CPU * acpi-apei: ACPI / APEI: Add Boot Error Record Table (BERT) support ACPI / einj: Make error paths more talkative ACPI / einj: Convert EINJ_PFX to proper pr_fmt * acpi-sleep: ACPI: Execute _PTS before system reboot
5 parents f6bc0a1 + 8fc85c6 + 866ae69 + a3e2acc + 2c85025 commit 6149dff

File tree

19 files changed

+868
-159
lines changed

19 files changed

+868
-159
lines changed

Documentation/kernel-parameters.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
582582

583583
bootmem_debug [KNL] Enable bootmem allocator debug messages.
584584

585+
bert_disable [ACPI]
586+
Disable BERT OS support on buggy BIOSes.
587+
585588
bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards)
586589
bttv.radio= Most important insmod options are available as
587590
kernel args too.

arch/arm64/kernel/cpuidle.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
* published by the Free Software Foundation.
1010
*/
1111

12+
#include <linux/acpi.h>
13+
#include <linux/cpuidle.h>
14+
#include <linux/cpu_pm.h>
1215
#include <linux/of.h>
1316
#include <linux/of_device.h>
1417

1518
#include <asm/cpuidle.h>
1619
#include <asm/cpu_ops.h>
1720

18-
int __init arm_cpuidle_init(unsigned int cpu)
21+
int arm_cpuidle_init(unsigned int cpu)
1922
{
2023
int ret = -EOPNOTSUPP;
2124

@@ -39,3 +42,18 @@ int arm_cpuidle_suspend(int index)
3942

4043
return cpu_ops[cpu]->cpu_suspend(index);
4144
}
45+
46+
#ifdef CONFIG_ACPI
47+
48+
#include <acpi/processor.h>
49+
50+
int acpi_processor_ffh_lpi_probe(unsigned int cpu)
51+
{
52+
return arm_cpuidle_init(cpu);
53+
}
54+
55+
int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
56+
{
57+
return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, lpi->index);
58+
}
59+
#endif

drivers/acpi/Kconfig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ config ACPI_CPU_FREQ_PSS
213213
bool
214214
select THERMAL
215215

216+
config ACPI_PROCESSOR_CSTATE
217+
def_bool y
218+
depends on IA64 || X86
219+
216220
config ACPI_PROCESSOR_IDLE
217221
bool
218222
select CPU_IDLE
@@ -234,7 +238,7 @@ config ACPI_CPPC_LIB
234238
config ACPI_PROCESSOR
235239
tristate "Processor"
236240
depends on X86 || IA64 || ARM64
237-
select ACPI_PROCESSOR_IDLE if X86 || IA64
241+
select ACPI_PROCESSOR_IDLE
238242
select ACPI_CPU_FREQ_PSS if X86 || IA64
239243
default y
240244
help

drivers/acpi/apei/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o
33
obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o
44
obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o
55

6-
apei-y := apei-base.o hest.o erst.o
6+
apei-y := apei-base.o hest.o erst.o bert.o

drivers/acpi/apei/apei-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* apei-internal.h - ACPI Platform Error Interface internal
3-
* definations.
3+
* definitions.
44
*/
55

66
#ifndef APEI_INTERNAL_H

drivers/acpi/apei/bert.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* APEI Boot Error Record Table (BERT) support
3+
*
4+
* Copyright 2011 Intel Corp.
5+
* Author: Huang Ying <ying.huang@intel.com>
6+
*
7+
* Under normal circumstances, when a hardware error occurs, the error
8+
* handler receives control and processes the error. This gives OSPM a
9+
* chance to process the error condition, report it, and optionally attempt
10+
* recovery. In some cases, the system is unable to process an error.
11+
* For example, system firmware or a management controller may choose to
12+
* reset the system or the system might experience an uncontrolled crash
13+
* or reset.The boot error source is used to report unhandled errors that
14+
* occurred in a previous boot. This mechanism is described in the BERT
15+
* table.
16+
*
17+
* For more information about BERT, please refer to ACPI Specification
18+
* version 4.0, section 17.3.1
19+
*
20+
* This file is licensed under GPLv2.
21+
*
22+
*/
23+
24+
#include <linux/kernel.h>
25+
#include <linux/module.h>
26+
#include <linux/init.h>
27+
#include <linux/acpi.h>
28+
#include <linux/io.h>
29+
30+
#include "apei-internal.h"
31+
32+
#undef pr_fmt
33+
#define pr_fmt(fmt) "BERT: " fmt
34+
35+
static int bert_disable;
36+
37+
static void __init bert_print_all(struct acpi_bert_region *region,
38+
unsigned int region_len)
39+
{
40+
struct acpi_hest_generic_status *estatus =
41+
(struct acpi_hest_generic_status *)region;
42+
int remain = region_len;
43+
u32 estatus_len;
44+
45+
if (!estatus->block_status)
46+
return;
47+
48+
while (remain > sizeof(struct acpi_bert_region)) {
49+
if (cper_estatus_check(estatus)) {
50+
pr_err(FW_BUG "Invalid error record.\n");
51+
return;
52+
}
53+
54+
estatus_len = cper_estatus_len(estatus);
55+
if (remain < estatus_len) {
56+
pr_err(FW_BUG "Truncated status block (length: %u).\n",
57+
estatus_len);
58+
return;
59+
}
60+
61+
pr_info_once("Error records from previous boot:\n");
62+
63+
cper_estatus_print(KERN_INFO HW_ERR, estatus);
64+
65+
/*
66+
* Because the boot error source is "one-time polled" type,
67+
* clear Block Status of current Generic Error Status Block,
68+
* once it's printed.
69+
*/
70+
estatus->block_status = 0;
71+
72+
estatus = (void *)estatus + estatus_len;
73+
/* No more error records. */
74+
if (!estatus->block_status)
75+
return;
76+
77+
remain -= estatus_len;
78+
}
79+
}
80+
81+
static int __init setup_bert_disable(char *str)
82+
{
83+
bert_disable = 1;
84+
85+
return 0;
86+
}
87+
__setup("bert_disable", setup_bert_disable);
88+
89+
static int __init bert_check_table(struct acpi_table_bert *bert_tab)
90+
{
91+
if (bert_tab->header.length < sizeof(struct acpi_table_bert) ||
92+
bert_tab->region_length < sizeof(struct acpi_bert_region))
93+
return -EINVAL;
94+
95+
return 0;
96+
}
97+
98+
static int __init bert_init(void)
99+
{
100+
struct acpi_bert_region *boot_error_region;
101+
struct acpi_table_bert *bert_tab;
102+
unsigned int region_len;
103+
acpi_status status;
104+
int rc = 0;
105+
106+
if (acpi_disabled)
107+
return 0;
108+
109+
if (bert_disable) {
110+
pr_info("Boot Error Record Table support is disabled.\n");
111+
return 0;
112+
}
113+
114+
status = acpi_get_table(ACPI_SIG_BERT, 0, (struct acpi_table_header **)&bert_tab);
115+
if (status == AE_NOT_FOUND)
116+
return 0;
117+
118+
if (ACPI_FAILURE(status)) {
119+
pr_err("get table failed, %s.\n", acpi_format_exception(status));
120+
return -EINVAL;
121+
}
122+
123+
rc = bert_check_table(bert_tab);
124+
if (rc) {
125+
pr_err(FW_BUG "table invalid.\n");
126+
return rc;
127+
}
128+
129+
region_len = bert_tab->region_length;
130+
if (!request_mem_region(bert_tab->address, region_len, "APEI BERT")) {
131+
pr_err("Can't request iomem region <%016llx-%016llx>.\n",
132+
(unsigned long long)bert_tab->address,
133+
(unsigned long long)bert_tab->address + region_len - 1);
134+
return -EIO;
135+
}
136+
137+
boot_error_region = ioremap_cache(bert_tab->address, region_len);
138+
if (boot_error_region) {
139+
bert_print_all(boot_error_region, region_len);
140+
iounmap(boot_error_region);
141+
} else {
142+
rc = -ENOMEM;
143+
}
144+
145+
release_mem_region(bert_tab->address, region_len);
146+
147+
return rc;
148+
}
149+
150+
late_initcall(bert_init);

drivers/acpi/apei/einj.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333

3434
#include "apei-internal.h"
3535

36-
#define EINJ_PFX "EINJ: "
36+
#undef pr_fmt
37+
#define pr_fmt(fmt) "EINJ: " fmt
3738

3839
#define SPIN_UNIT 100 /* 100ns */
3940
/* Firmware should respond within 1 milliseconds */
@@ -179,8 +180,7 @@ static int einj_get_available_error_type(u32 *type)
179180
static int einj_timedout(u64 *t)
180181
{
181182
if ((s64)*t < SPIN_UNIT) {
182-
pr_warning(FW_WARN EINJ_PFX
183-
"Firmware does not respond in time\n");
183+
pr_warning(FW_WARN "Firmware does not respond in time\n");
184184
return 1;
185185
}
186186
*t -= SPIN_UNIT;
@@ -307,22 +307,20 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
307307
r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
308308
"APEI EINJ Trigger Table");
309309
if (!r) {
310-
pr_err(EINJ_PFX
311-
"Can not request [mem %#010llx-%#010llx] for Trigger table\n",
310+
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n",
312311
(unsigned long long)trigger_paddr,
313312
(unsigned long long)trigger_paddr +
314313
sizeof(*trigger_tab) - 1);
315314
goto out;
316315
}
317316
trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
318317
if (!trigger_tab) {
319-
pr_err(EINJ_PFX "Failed to map trigger table!\n");
318+
pr_err("Failed to map trigger table!\n");
320319
goto out_rel_header;
321320
}
322321
rc = einj_check_trigger_header(trigger_tab);
323322
if (rc) {
324-
pr_warning(FW_BUG EINJ_PFX
325-
"The trigger error action table is invalid\n");
323+
pr_warning(FW_BUG "Invalid trigger error action table.\n");
326324
goto out_rel_header;
327325
}
328326

@@ -336,16 +334,15 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
336334
table_size - sizeof(*trigger_tab),
337335
"APEI EINJ Trigger Table");
338336
if (!r) {
339-
pr_err(EINJ_PFX
340-
"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
337+
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
341338
(unsigned long long)trigger_paddr + sizeof(*trigger_tab),
342339
(unsigned long long)trigger_paddr + table_size - 1);
343340
goto out_rel_header;
344341
}
345342
iounmap(trigger_tab);
346343
trigger_tab = ioremap_cache(trigger_paddr, table_size);
347344
if (!trigger_tab) {
348-
pr_err(EINJ_PFX "Failed to map trigger table!\n");
345+
pr_err("Failed to map trigger table!\n");
349346
goto out_rel_entry;
350347
}
351348
trigger_entry = (struct acpi_whea_header *)
@@ -695,34 +692,42 @@ static int __init einj_init(void)
695692
struct dentry *fentry;
696693
struct apei_exec_context ctx;
697694

698-
if (acpi_disabled)
695+
if (acpi_disabled) {
696+
pr_warn("ACPI disabled.\n");
699697
return -ENODEV;
698+
}
700699

701700
status = acpi_get_table(ACPI_SIG_EINJ, 0,
702701
(struct acpi_table_header **)&einj_tab);
703-
if (status == AE_NOT_FOUND)
702+
if (status == AE_NOT_FOUND) {
703+
pr_warn("EINJ table not found.\n");
704704
return -ENODEV;
705+
}
705706
else if (ACPI_FAILURE(status)) {
706-
const char *msg = acpi_format_exception(status);
707-
pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
707+
pr_err("Failed to get EINJ table: %s\n",
708+
acpi_format_exception(status));
708709
return -EINVAL;
709710
}
710711

711712
rc = einj_check_table(einj_tab);
712713
if (rc) {
713-
pr_warning(FW_BUG EINJ_PFX "EINJ table is invalid\n");
714+
pr_warn(FW_BUG "Invalid EINJ table.n");
714715
return -EINVAL;
715716
}
716717

717718
rc = -ENOMEM;
718719
einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir());
719-
if (!einj_debug_dir)
720+
if (!einj_debug_dir) {
721+
pr_err("Error creating debugfs node.\n");
720722
goto err_cleanup;
723+
}
724+
721725
fentry = debugfs_create_file("available_error_type", S_IRUSR,
722726
einj_debug_dir, NULL,
723727
&available_error_type_fops);
724728
if (!fentry)
725729
goto err_cleanup;
730+
726731
fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR,
727732
einj_debug_dir, NULL, &error_type_fops);
728733
if (!fentry)
@@ -735,14 +740,22 @@ static int __init einj_init(void)
735740
apei_resources_init(&einj_resources);
736741
einj_exec_ctx_init(&ctx);
737742
rc = apei_exec_collect_resources(&ctx, &einj_resources);
738-
if (rc)
743+
if (rc) {
744+
pr_err("Error collecting EINJ resources.\n");
739745
goto err_fini;
746+
}
747+
740748
rc = apei_resources_request(&einj_resources, "APEI EINJ");
741-
if (rc)
749+
if (rc) {
750+
pr_err("Error requesting memory/port resources.\n");
742751
goto err_fini;
752+
}
753+
743754
rc = apei_exec_pre_map_gars(&ctx);
744-
if (rc)
755+
if (rc) {
756+
pr_err("Error pre-mapping GARs.\n");
745757
goto err_release;
758+
}
746759

747760
rc = -ENOMEM;
748761
einj_param = einj_get_parameter_address();
@@ -787,7 +800,7 @@ static int __init einj_init(void)
787800
goto err_unmap;
788801
}
789802

790-
pr_info(EINJ_PFX "Error INJection is initialized.\n");
803+
pr_info("Error INJection is initialized.\n");
791804

792805
return 0;
793806

@@ -798,13 +811,15 @@ static int __init einj_init(void)
798811
sizeof(struct einj_parameter);
799812

800813
acpi_os_unmap_iomem(einj_param, size);
814+
pr_err("Error creating param extension debugfs nodes.\n");
801815
}
802816
apei_exec_post_unmap_gars(&ctx);
803817
err_release:
804818
apei_resources_release(&einj_resources);
805819
err_fini:
806820
apei_resources_fini(&einj_resources);
807821
err_cleanup:
822+
pr_err("Error creating primary debugfs nodes.\n");
808823
debugfs_remove_recursive(einj_debug_dir);
809824

810825
return rc;

0 commit comments

Comments
 (0)