forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/acpi/apei/bert.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * APEI Boot Error Record Table (BERT) support
34 *
....@@ -16,9 +17,6 @@
1617 *
1718 * For more information about BERT, please refer to ACPI Specification
1819 * version 4.0, section 17.3.1
19
- *
20
- * This file is licensed under GPLv2.
21
- *
2220 */
2321
2422 #include <linux/kernel.h>
....@@ -32,35 +30,52 @@
3230 #undef pr_fmt
3331 #define pr_fmt(fmt) "BERT: " fmt
3432
33
+#define ACPI_BERT_PRINT_MAX_RECORDS 5
34
+#define ACPI_BERT_PRINT_MAX_LEN 1024
35
+
3536 static int bert_disable;
3637
38
+/*
39
+ * Print "all" the error records in the BERT table, but avoid huge spam to
40
+ * the console if the BIOS included oversize records, or too many records.
41
+ * Skipping some records here does not lose anything because the full
42
+ * data is available to user tools in:
43
+ * /sys/firmware/acpi/tables/data/BERT
44
+ */
3745 static void __init bert_print_all(struct acpi_bert_region *region,
3846 unsigned int region_len)
3947 {
4048 struct acpi_hest_generic_status *estatus =
4149 (struct acpi_hest_generic_status *)region;
4250 int remain = region_len;
51
+ int printed = 0, skipped = 0;
4352 u32 estatus_len;
4453
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
+ while (remain >= sizeof(struct acpi_bert_region)) {
5455 estatus_len = cper_estatus_len(estatus);
5556 if (remain < estatus_len) {
5657 pr_err(FW_BUG "Truncated status block (length: %u).\n",
5758 estatus_len);
58
- return;
59
+ break;
5960 }
6061
61
- pr_info_once("Error records from previous boot:\n");
62
+ /* No more error records. */
63
+ if (!estatus->block_status)
64
+ break;
6265
63
- cper_estatus_print(KERN_INFO HW_ERR, estatus);
66
+ if (cper_estatus_check(estatus)) {
67
+ pr_err(FW_BUG "Invalid error record.\n");
68
+ break;
69
+ }
70
+
71
+ if (estatus_len < ACPI_BERT_PRINT_MAX_LEN &&
72
+ printed < ACPI_BERT_PRINT_MAX_RECORDS) {
73
+ pr_info_once("Error records from previous boot:\n");
74
+ cper_estatus_print(KERN_INFO HW_ERR, estatus);
75
+ printed++;
76
+ } else {
77
+ skipped++;
78
+ }
6479
6580 /*
6681 * Because the boot error source is "one-time polled" type,
....@@ -70,19 +85,18 @@
7085 estatus->block_status = 0;
7186
7287 estatus = (void *)estatus + estatus_len;
73
- /* No more error records. */
74
- if (!estatus->block_status)
75
- return;
76
-
7788 remain -= estatus_len;
7889 }
90
+
91
+ if (skipped)
92
+ pr_info(HW_ERR "Skipped %d error records\n", skipped);
7993 }
8094
8195 static int __init setup_bert_disable(char *str)
8296 {
8397 bert_disable = 1;
8498
85
- return 0;
99
+ return 1;
86100 }
87101 __setup("bert_disable", setup_bert_disable);
88102
....@@ -124,7 +138,7 @@
124138 rc = bert_check_table(bert_tab);
125139 if (rc) {
126140 pr_err(FW_BUG "table invalid.\n");
127
- return rc;
141
+ goto out_put_bert_tab;
128142 }
129143
130144 region_len = bert_tab->region_length;
....@@ -132,7 +146,7 @@
132146 rc = apei_resources_add(&bert_resources, bert_tab->address,
133147 region_len, true);
134148 if (rc)
135
- return rc;
149
+ goto out_put_bert_tab;
136150 rc = apei_resources_request(&bert_resources, "APEI BERT");
137151 if (rc)
138152 goto out_fini;
....@@ -147,6 +161,8 @@
147161 apei_resources_release(&bert_resources);
148162 out_fini:
149163 apei_resources_fini(&bert_resources);
164
+out_put_bert_tab:
165
+ acpi_put_table((struct acpi_table_header *)bert_tab);
150166
151167 return rc;
152168 }