@@ -45,6 +45,7 @@
#include <linux/aer.h>
#include <linux/nmi.h>
+#include <acpi/actbl1.h>
#include <acpi/ghes.h>
#include <acpi/apei.h>
#include <asm/tlbflush.h>
@@ -239,10 +240,22 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
struct ghes *ghes;
unsigned int error_block_length;
int rc;
+ struct acpi_hest_header *hest_hdr;
ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
if (!ghes)
return ERR_PTR(-ENOMEM);
+
+ hest_hdr = (struct acpi_hest_header *)generic;
+ if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
+ ghes->generic_v2 = (struct acpi_hest_generic_v2 *)generic;
+ rc = apei_map_generic_address(
+ &ghes->generic_v2->read_ack_reg_address);
+ if (rc)
+ goto err_unmap;
+ } else
+ ghes->generic_v2 = NULL;
+
ghes->generic = generic;
rc = apei_map_generic_address(&generic->error_status_address);
if (rc)
@@ -265,6 +278,9 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
err_unmap:
apei_unmap_generic_address(&generic->error_status_address);
+ if (ghes->generic_v2)
+ apei_unmap_generic_address(
+ &ghes->generic_v2->read_ack_reg_address);
err_free:
kfree(ghes);
return ERR_PTR(rc);
@@ -274,6 +290,9 @@ static void ghes_fini(struct ghes *ghes)
{
kfree(ghes->estatus);
apei_unmap_generic_address(&ghes->generic->error_status_address);
+ if (ghes->generic_v2)
+ apei_unmap_generic_address(
+ &ghes->generic_v2->error_status_address);
}
static inline int ghes_severity(int severity)
@@ -643,6 +662,22 @@ static void ghes_estatus_cache_add(
rcu_read_unlock();
}
+static int ghes_do_read_ack(struct acpi_hest_generic_v2 *generic_v2)
+{
+ int rc;
+ u64 val = 0;
+
+ rc = apei_read(&val, &generic_v2->read_ack_reg_address);
+ if (rc)
+ return rc;
+ val &= generic_v2->read_ack_preserve <<
+ generic_v2->read_ack_reg_address.bit_offset;
+ val |= generic_v2->read_ack_write;
+ rc = apei_write(val, &generic_v2->read_ack_reg_address);
+
+ return rc;
+}
+
static int ghes_proc(struct ghes *ghes)
{
int rc;
@@ -655,6 +690,12 @@ static int ghes_proc(struct ghes *ghes)
ghes_estatus_cache_add(ghes->generic, ghes->estatus);
}
ghes_do_proc(ghes, ghes->estatus);
+
+ if (ghes->generic_v2) {
+ rc = ghes_do_read_ack(ghes->generic_v2);
+ if (rc)
+ return rc;
+ }
out:
ghes_clear_estatus(ghes);
return 0;
@@ -52,6 +52,7 @@ static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
[ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer),
[ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge),
[ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic),
+ [ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2),
};
static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
@@ -147,7 +148,8 @@ static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void
{
int *count = data;
- if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR)
+ if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR ||
+ hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR_V2)
(*count)++;
return 0;
}
@@ -158,7 +160,8 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
struct ghes_arr *ghes_arr = data;
int rc, i;
- if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
+ if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR &&
+ hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR_V2)
return 0;
if (!((struct acpi_hest_generic *)hest_hdr)->enabled)
@@ -427,7 +427,8 @@ enum acpi_hest_types {
ACPI_HEST_TYPE_AER_ENDPOINT = 7,
ACPI_HEST_TYPE_AER_BRIDGE = 8,
ACPI_HEST_TYPE_GENERIC_ERROR = 9,
- ACPI_HEST_TYPE_RESERVED = 10 /* 10 and greater are reserved */
+ ACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10,
+ ACPI_HEST_TYPE_RESERVED = 11 /* 11 and greater are reserved */
};
/*
@@ -603,6 +604,24 @@ struct acpi_hest_generic {
u32 error_block_length;
};
+/* 10: Generic Hardware Error Source V2*/
+
+struct acpi_hest_generic_v2 {
+ struct acpi_hest_header header;
+ u16 related_source_id;
+ u8 reserved;
+ u8 enabled;
+ u32 records_to_preallocate;
+ u32 max_sections_per_record;
+ u32 max_raw_data_length;
+ struct acpi_generic_address error_status_address;
+ struct acpi_hest_notify notify;
+ u32 error_block_length;
+ struct acpi_generic_address read_ack_reg_address;
+ u64 read_ack_preserve;
+ u64 read_ack_write;
+};
+
/* Generic Error Status block */
struct acpi_hest_generic_status {
@@ -14,6 +14,7 @@
struct ghes {
struct acpi_hest_generic *generic;
+ struct acpi_hest_generic_v2 *generic_v2;
struct acpi_hest_generic_status *estatus;
u64 buffer_paddr;
unsigned long flags;