.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * APEI Hardware Error Souce Table support |
---|
3 | 4 | * |
---|
.. | .. |
---|
12 | 13 | * |
---|
13 | 14 | * Copyright 2009 Intel Corp. |
---|
14 | 15 | * Author: Huang Ying <ying.huang@intel.com> |
---|
15 | | - * |
---|
16 | | - * This program is free software; you can redistribute it and/or |
---|
17 | | - * modify it under the terms of the GNU General Public License version |
---|
18 | | - * 2 as published by the Free Software Foundation; |
---|
19 | | - * |
---|
20 | | - * This program is distributed in the hope that it will be useful, |
---|
21 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
22 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
23 | | - * GNU General Public License for more details. |
---|
24 | 16 | */ |
---|
25 | 17 | |
---|
26 | 18 | #include <linux/kernel.h> |
---|
.. | .. |
---|
32 | 24 | #include <linux/io.h> |
---|
33 | 25 | #include <linux/platform_device.h> |
---|
34 | 26 | #include <acpi/apei.h> |
---|
| 27 | +#include <acpi/ghes.h> |
---|
35 | 28 | |
---|
36 | 29 | #include "apei-internal.h" |
---|
37 | 30 | |
---|
.. | .. |
---|
53 | 46 | [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge), |
---|
54 | 47 | [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic), |
---|
55 | 48 | [ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2), |
---|
| 49 | + [ACPI_HEST_TYPE_IA32_DEFERRED_CHECK] = -1, |
---|
56 | 50 | }; |
---|
57 | 51 | |
---|
58 | 52 | static int hest_esrc_len(struct acpi_hest_header *hest_hdr) |
---|
.. | .. |
---|
75 | 69 | mc = (struct acpi_hest_ia_machine_check *)hest_hdr; |
---|
76 | 70 | len = sizeof(*mc) + mc->num_hardware_banks * |
---|
77 | 71 | sizeof(struct acpi_hest_ia_error_bank); |
---|
| 72 | + } else if (hest_type == ACPI_HEST_TYPE_IA32_DEFERRED_CHECK) { |
---|
| 73 | + struct acpi_hest_ia_deferred_check *mc; |
---|
| 74 | + mc = (struct acpi_hest_ia_deferred_check *)hest_hdr; |
---|
| 75 | + len = sizeof(*mc) + mc->num_hardware_banks * |
---|
| 76 | + sizeof(struct acpi_hest_ia_error_bank); |
---|
78 | 77 | } |
---|
79 | 78 | BUG_ON(len == -1); |
---|
80 | 79 | |
---|
.. | .. |
---|
93 | 92 | for (i = 0; i < hest_tab->error_source_count; i++) { |
---|
94 | 93 | len = hest_esrc_len(hest_hdr); |
---|
95 | 94 | if (!len) { |
---|
96 | | - pr_warning(FW_WARN HEST_PFX |
---|
97 | | - "Unknown or unused hardware error source " |
---|
98 | | - "type: %d for hardware error source: %d.\n", |
---|
99 | | - hest_hdr->type, hest_hdr->source_id); |
---|
| 95 | + pr_warn(FW_WARN HEST_PFX |
---|
| 96 | + "Unknown or unused hardware error source " |
---|
| 97 | + "type: %d for hardware error source: %d.\n", |
---|
| 98 | + hest_hdr->type, hest_hdr->source_id); |
---|
100 | 99 | return -EINVAL; |
---|
101 | 100 | } |
---|
102 | 101 | if ((void *)hest_hdr + len > |
---|
103 | 102 | (void *)hest_tab + hest_tab->header.length) { |
---|
104 | | - pr_warning(FW_BUG HEST_PFX |
---|
| 103 | + pr_warn(FW_BUG HEST_PFX |
---|
105 | 104 | "Table contents overflow for hardware error source: %d.\n", |
---|
106 | 105 | hest_hdr->source_id); |
---|
107 | 106 | return -EINVAL; |
---|
.. | .. |
---|
165 | 164 | ghes_dev = ghes_arr->ghes_devs[i]; |
---|
166 | 165 | hdr = *(struct acpi_hest_header **)ghes_dev->dev.platform_data; |
---|
167 | 166 | if (hdr->source_id == hest_hdr->source_id) { |
---|
168 | | - pr_warning(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n", |
---|
169 | | - hdr->source_id); |
---|
| 167 | + pr_warn(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n", |
---|
| 168 | + hdr->source_id); |
---|
170 | 169 | return -EIO; |
---|
171 | 170 | } |
---|
172 | 171 | } |
---|
.. | .. |
---|
203 | 202 | rc = apei_hest_parse(hest_parse_ghes, &ghes_arr); |
---|
204 | 203 | if (rc) |
---|
205 | 204 | goto err; |
---|
| 205 | + |
---|
| 206 | + rc = ghes_estatus_pool_init(ghes_count); |
---|
| 207 | + if (rc) |
---|
| 208 | + goto err; |
---|
| 209 | + |
---|
206 | 210 | out: |
---|
207 | 211 | kfree(ghes_arr.ghes_devs); |
---|
208 | 212 | return rc; |
---|
.. | .. |
---|
215 | 219 | static int __init setup_hest_disable(char *str) |
---|
216 | 220 | { |
---|
217 | 221 | hest_disable = HEST_DISABLED; |
---|
218 | | - return 0; |
---|
| 222 | + return 1; |
---|
219 | 223 | } |
---|
220 | 224 | |
---|
221 | 225 | __setup("hest_disable", setup_hest_disable); |
---|
.. | .. |
---|
223 | 227 | void __init acpi_hest_init(void) |
---|
224 | 228 | { |
---|
225 | 229 | acpi_status status; |
---|
226 | | - int rc = -ENODEV; |
---|
| 230 | + int rc; |
---|
227 | 231 | unsigned int ghes_count = 0; |
---|
228 | 232 | |
---|
229 | 233 | if (hest_disable) { |
---|
.. | .. |
---|
239 | 243 | } else if (ACPI_FAILURE(status)) { |
---|
240 | 244 | const char *msg = acpi_format_exception(status); |
---|
241 | 245 | pr_err(HEST_PFX "Failed to get table, %s\n", msg); |
---|
242 | | - rc = -EINVAL; |
---|
243 | | - goto err; |
---|
| 246 | + hest_disable = HEST_DISABLED; |
---|
| 247 | + return; |
---|
244 | 248 | } |
---|
245 | 249 | |
---|
246 | 250 | rc = apei_hest_parse(hest_parse_cmc, NULL); |
---|
.. | .. |
---|
251 | 255 | rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); |
---|
252 | 256 | if (rc) |
---|
253 | 257 | goto err; |
---|
254 | | - rc = hest_ghes_dev_register(ghes_count); |
---|
| 258 | + |
---|
| 259 | + if (ghes_count) |
---|
| 260 | + rc = hest_ghes_dev_register(ghes_count); |
---|
255 | 261 | if (rc) |
---|
256 | 262 | goto err; |
---|
257 | 263 | } |
---|
.. | .. |
---|
260 | 266 | return; |
---|
261 | 267 | err: |
---|
262 | 268 | hest_disable = HEST_DISABLED; |
---|
| 269 | + acpi_put_table((struct acpi_table_header *)hest_tab); |
---|
263 | 270 | } |
---|