#include <linux/nmi.h>
 #include <linux/sched/clock.h>
 
+#include <acpi/actbl1.h>
 #include <acpi/ghes.h>
 #include <acpi/apei.h>
 #include <asm/tlbflush.h>
        ((struct acpi_hest_generic_status *)                            \
         ((struct ghes_estatus_node *)(estatus_node) + 1))
 
+static inline bool is_hest_type_generic_v2(struct ghes *ghes)
+{
+       return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
+}
+
 /*
  * This driver isn't really modular, however for the time being,
  * continuing to use module_param is the easiest way to remain
        return 0;
 }
 
+static int map_gen_v2(struct ghes *ghes)
+{
+       return apei_map_generic_address(&ghes->generic_v2->read_ack_register);
+}
+
+static void unmap_gen_v2(struct ghes *ghes)
+{
+       apei_unmap_generic_address(&ghes->generic_v2->read_ack_register);
+}
+
 static struct ghes *ghes_new(struct acpi_hest_generic *generic)
 {
        struct ghes *ghes;
        ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
        if (!ghes)
                return ERR_PTR(-ENOMEM);
+
        ghes->generic = generic;
+       if (is_hest_type_generic_v2(ghes)) {
+               rc = map_gen_v2(ghes);
+               if (rc)
+                       goto err_free;
+       }
+
        rc = apei_map_generic_address(&generic->error_status_address);
        if (rc)
-               goto err_free;
+               goto err_unmap_read_ack_addr;
        error_block_length = generic->error_block_length;
        if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
                pr_warning(FW_WARN GHES_PFX
        ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
        if (!ghes->estatus) {
                rc = -ENOMEM;
-               goto err_unmap;
+               goto err_unmap_status_addr;
        }
 
        return ghes;
 
-err_unmap:
+err_unmap_status_addr:
        apei_unmap_generic_address(&generic->error_status_address);
+err_unmap_read_ack_addr:
+       if (is_hest_type_generic_v2(ghes))
+               unmap_gen_v2(ghes);
 err_free:
        kfree(ghes);
        return ERR_PTR(rc);
 {
        kfree(ghes->estatus);
        apei_unmap_generic_address(&ghes->generic->error_status_address);
+       if (is_hest_type_generic_v2(ghes))
+               unmap_gen_v2(ghes);
 }
 
 static inline int ghes_severity(int severity)
        rcu_read_unlock();
 }
 
+static int ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
+{
+       int rc;
+       u64 val = 0;
+
+       rc = apei_read(&val, &gv2->read_ack_register);
+       if (rc)
+               return rc;
+
+       val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset;
+       val |= gv2->read_ack_write    << gv2->read_ack_register.bit_offset;
+
+       return apei_write(val, &gv2->read_ack_register);
+}
+
 static int ghes_proc(struct ghes *ghes)
 {
        int rc;
                        ghes_estatus_cache_add(ghes->generic, ghes->estatus);
        }
        ghes_do_proc(ghes, ghes->estatus);
+
+       /*
+        * GHESv2 type HEST entries introduce support for error acknowledgment,
+        * so only acknowledge the error if this support is present.
+        */
+       if (is_hest_type_generic_v2(ghes)) {
+               rc = ghes_ack_error(ghes->generic_v2);
+               if (rc)
+                       return rc;
+       }
 out:
        ghes_clear_estatus(ghes);
        return rc;
 
        [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)
 {
        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;
 }
        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)