size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
 
        size = PAGE_ALIGN(size);
+
+       /* This is to hold kernel metadata on platforms that support it */
+       size += (fw_dump.ops->fadump_get_metadata_size ?
+                fw_dump.ops->fadump_get_metadata_size() : 0);
        return size;
 }
 
                pr_info("Firmware-Assisted Dump is not supported on this hardware\n");
                goto error_out;
        }
+
        /*
         * Initialize boot memory size
         * If dump is active then we have already calculated the size during
                        base += size;
                }
 
-               if ((base > (mem_boundary - size)) ||
-                   memblock_reserve(base, size)) {
+               if (base > (mem_boundary - size)) {
+                       pr_err("Failed to find memory chunk for reservation!\n");
+                       goto error_out;
+               }
+               fw_dump.reserve_dump_area_start = base;
+
+               /*
+                * Calculate the kernel metadata address and register it with
+                * f/w if the platform supports.
+                */
+               if (fw_dump.ops->fadump_setup_metadata &&
+                   (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
+                       goto error_out;
+
+               if (memblock_reserve(base, size)) {
                        pr_err("Failed to reserve memory!\n");
                        goto error_out;
                }
                pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n",
                        (size >> 20), base, (memblock_phys_mem_size() >> 20));
 
-               fw_dump.reserve_dump_area_start = base;
                ret = fadump_cma_init();
        }
 
 
 #include <linux/seq_file.h>
 #include <linux/of_fdt.h>
 #include <linux/libfdt.h>
+#include <linux/mm.h>
 
+#include <asm/page.h>
 #include <asm/opal.h>
 #include <asm/fadump-internal.h>
 
+#include "opal-fadump.h"
+
+static struct opal_fadump_mem_struct *opal_fdm;
+
+/* Initialize kernel metadata */
+static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
+{
+       fdm->version = OPAL_FADUMP_VERSION;
+       fdm->region_cnt = 0;
+       fdm->registered_regions = 0;
+       fdm->fadumphdr_addr = 0;
+}
+
 static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
 {
-       return fadump_conf->reserve_dump_area_start;
+       u64 addr = fadump_conf->reserve_dump_area_start;
+
+       opal_fdm = __va(fadump_conf->kernel_metadata);
+       opal_fadump_init_metadata(opal_fdm);
+
+       opal_fdm->region_cnt = 1;
+       opal_fdm->rgn[0].src    = 0;
+       opal_fdm->rgn[0].dest   = addr;
+       opal_fdm->rgn[0].size   = fadump_conf->boot_memory_size;
+       addr += fadump_conf->boot_memory_size;
+
+       /*
+        * Kernel metadata is passed to f/w and retrieved in capture kerenl.
+        * So, use it to save fadump header address instead of calculating it.
+        */
+       opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
+                                   fadump_conf->boot_memory_size);
+
+       return addr;
+}
+
+static u64 opal_fadump_get_metadata_size(void)
+{
+       return PAGE_ALIGN(sizeof(struct opal_fadump_mem_struct));
+}
+
+static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf)
+{
+       int err = 0;
+       s64 ret;
+
+       /*
+        * Use the last page(s) in FADump memory reservation for
+        * kernel metadata.
+        */
+       fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start +
+                                       fadump_conf->reserve_dump_area_size -
+                                       opal_fadump_get_metadata_size());
+       pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata);
+
+       /* Initialize kernel metadata before registering the address with f/w */
+       opal_fdm = __va(fadump_conf->kernel_metadata);
+       opal_fadump_init_metadata(opal_fdm);
+
+       /*
+        * Register metadata address with f/w. Can be retrieved in
+        * the capture kernel.
+        */
+       ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL,
+                                     fadump_conf->kernel_metadata);
+       if (ret != OPAL_SUCCESS) {
+               pr_err("Failed to set kernel metadata tag!\n");
+               err = -EPERM;
+       }
+
+       return err;
 }
 
 static int opal_fadump_register(struct fw_dump *fadump_conf)
 static void opal_fadump_region_show(struct fw_dump *fadump_conf,
                                    struct seq_file *m)
 {
+       const struct opal_fadump_mem_struct *fdm_ptr = opal_fdm;
+       u64 dumped_bytes = 0;
+       int i;
+
+       for (i = 0; i < fdm_ptr->region_cnt; i++) {
+               seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
+                          fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
+               seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
+                          fdm_ptr->rgn[i].size, dumped_bytes);
+       }
 }
 
 static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
 
 static struct fadump_ops opal_fadump_ops = {
        .fadump_init_mem_struct         = opal_fadump_init_mem_struct,
+       .fadump_get_metadata_size       = opal_fadump_get_metadata_size,
+       .fadump_setup_metadata          = opal_fadump_setup_metadata,
        .fadump_register                = opal_fadump_register,
        .fadump_unregister              = opal_fadump_unregister,
        .fadump_invalidate              = opal_fadump_invalidate,
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Firmware-Assisted Dump support on POWER platform (OPAL).
+ *
+ * Copyright 2019, Hari Bathini, IBM Corporation.
+ */
+
+#ifndef _POWERNV_OPAL_FADUMP_H
+#define _POWERNV_OPAL_FADUMP_H
+
+/*
+ * OPAL FADump metadata structure format version
+ *
+ * OPAL FADump kernel metadata structure stores kernel metadata needed to
+ * register-for/process crash dump. Format version is used to keep a tab on
+ * the changes in the structure format. The changes, if any, to the format
+ * are expected to be minimal and backward compatible.
+ */
+#define OPAL_FADUMP_VERSION                    0x1
+
+/* Maximum number of memory regions kernel supports */
+#define OPAL_FADUMP_MAX_MEM_REGS               128
+
+/*
+ * OPAL FADump kernel metadata
+ *
+ * The address of this structure will be registered with f/w for retrieving
+ * and processing during crash dump.
+ */
+struct opal_fadump_mem_struct {
+       u8      version;
+       u8      reserved[3];
+       u16     region_cnt;             /* number of regions */
+       u16     registered_regions;     /* Regions registered for MPIPL */
+       u64     fadumphdr_addr;
+       struct opal_mpipl_region        rgn[OPAL_FADUMP_MAX_MEM_REGS];
+} __packed;
+
+#endif /* _POWERNV_OPAL_FADUMP_H */