Skip to content

Commit 1753d40

Browse files
committed
Merge tag 'acpi-6.18-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI fix from Rafael Wysocki: "This fixes EINJV2 support introduced during the 6.17 cycle by unbreaking the initialization broken by a previous attempted fix, adding sanity checks for data coming from the platform firmware, and updating the code to handle injecting legacy error types on an EINJV2 capable systems properly (Tony Luck)" * tag 'acpi-6.18-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI: APEI: EINJ: Fix EINJV2 initialization and injection
2 parents 6ba3bb3 + d2932a5 commit 1753d40

File tree

1 file changed

+41
-23
lines changed

1 file changed

+41
-23
lines changed

drivers/acpi/apei/einj-core.c

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ bool einj_initialized __ro_after_init;
182182

183183
static void __iomem *einj_param;
184184
static u32 v5param_size;
185+
static u32 v66param_size;
185186
static bool is_v2;
186187

187188
static void einj_exec_ctx_init(struct apei_exec_context *ctx)
@@ -283,6 +284,24 @@ static void check_vendor_extension(u64 paddr,
283284
acpi_os_unmap_iomem(p, sizeof(v));
284285
}
285286

287+
static u32 einjv2_init(struct einjv2_extension_struct *e)
288+
{
289+
if (e->revision != 1) {
290+
pr_info("Unknown v2 extension revision %u\n", e->revision);
291+
return 0;
292+
}
293+
if (e->length < sizeof(*e) || e->length > PAGE_SIZE) {
294+
pr_info(FW_BUG "Bad1 v2 extension length %u\n", e->length);
295+
return 0;
296+
}
297+
if ((e->length - sizeof(*e)) % sizeof(e->component_arr[0])) {
298+
pr_info(FW_BUG "Bad2 v2 extension length %u\n", e->length);
299+
return 0;
300+
}
301+
302+
return (e->length - sizeof(*e)) / sizeof(e->component_arr[0]);
303+
}
304+
286305
static void __iomem *einj_get_parameter_address(void)
287306
{
288307
int i;
@@ -310,28 +329,21 @@ static void __iomem *einj_get_parameter_address(void)
310329
v5param_size = sizeof(v5param);
311330
p = acpi_os_map_iomem(pa_v5, sizeof(*p));
312331
if (p) {
313-
int offset, len;
314-
315332
memcpy_fromio(&v5param, p, v5param_size);
316333
acpi5 = 1;
317334
check_vendor_extension(pa_v5, &v5param);
318-
if (is_v2 && available_error_type & ACPI65_EINJV2_SUPP) {
319-
len = v5param.einjv2_struct.length;
320-
offset = offsetof(struct einjv2_extension_struct, component_arr);
321-
max_nr_components = (len - offset) /
322-
sizeof(v5param.einjv2_struct.component_arr[0]);
323-
/*
324-
* The first call to acpi_os_map_iomem above does not include the
325-
* component array, instead it is used to read and calculate maximum
326-
* number of components supported by the system. Below, the mapping
327-
* is expanded to include the component array.
328-
*/
335+
if (available_error_type & ACPI65_EINJV2_SUPP) {
336+
struct einjv2_extension_struct *e;
337+
338+
e = &v5param.einjv2_struct;
339+
max_nr_components = einjv2_init(e);
340+
341+
/* remap including einjv2_extension_struct */
329342
acpi_os_unmap_iomem(p, v5param_size);
330-
offset = offsetof(struct set_error_type_with_address, einjv2_struct);
331-
v5param_size = offset + struct_size(&v5param.einjv2_struct,
332-
component_arr, max_nr_components);
333-
p = acpi_os_map_iomem(pa_v5, v5param_size);
343+
v66param_size = v5param_size - sizeof(*e) + e->length;
344+
p = acpi_os_map_iomem(pa_v5, v66param_size);
334345
}
346+
335347
return p;
336348
}
337349
}
@@ -527,6 +539,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
527539
u64 param3, u64 param4)
528540
{
529541
struct apei_exec_context ctx;
542+
u32 param_size = is_v2 ? v66param_size : v5param_size;
530543
u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
531544
int i, rc;
532545

@@ -539,11 +552,11 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
539552
if (acpi5) {
540553
struct set_error_type_with_address *v5param;
541554

542-
v5param = kmalloc(v5param_size, GFP_KERNEL);
555+
v5param = kmalloc(param_size, GFP_KERNEL);
543556
if (!v5param)
544557
return -ENOMEM;
545558

546-
memcpy_fromio(v5param, einj_param, v5param_size);
559+
memcpy_fromio(v5param, einj_param, param_size);
547560
v5param->type = type;
548561
if (type & ACPI5_VENDOR_BIT) {
549562
switch (vendor_flags) {
@@ -601,7 +614,7 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
601614
break;
602615
}
603616
}
604-
memcpy_toio(einj_param, v5param, v5param_size);
617+
memcpy_toio(einj_param, v5param, param_size);
605618
kfree(v5param);
606619
} else {
607620
rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
@@ -1132,9 +1145,14 @@ static void einj_remove(struct faux_device *fdev)
11321145
struct apei_exec_context ctx;
11331146

11341147
if (einj_param) {
1135-
acpi_size size = (acpi5) ?
1136-
v5param_size :
1137-
sizeof(struct einj_parameter);
1148+
acpi_size size;
1149+
1150+
if (v66param_size)
1151+
size = v66param_size;
1152+
else if (acpi5)
1153+
size = v5param_size;
1154+
else
1155+
size = sizeof(struct einj_parameter);
11381156

11391157
acpi_os_unmap_iomem(einj_param, size);
11401158
if (vendor_errors.size)

0 commit comments

Comments
 (0)