goto err_release_fw;
        }
 
+       status = ath10k_coredump_register(ar);
+       if (status) {
+               ath10k_err(ar, "unable to register coredump\n");
+               goto err_unregister_mac;
+       }
+
        status = ath10k_debug_register(ar);
        if (status) {
                ath10k_err(ar, "unable to initialize debugfs\n");
-               goto err_unregister_mac;
+               goto err_unregister_coredump;
        }
 
        status = ath10k_spectral_create(ar);
        ath10k_spectral_destroy(ar);
 err_debug_destroy:
        ath10k_debug_destroy(ar);
+err_unregister_coredump:
+       ath10k_coredump_unregister(ar);
 err_unregister_mac:
        ath10k_mac_unregister(ar);
 err_release_fw:
 
        struct ath10k_ce_crash_data entries[];
 };
 
+#define MAX_MEM_DUMP_TYPE      5
+
 /* used for crash-dump storage, protected by data-lock */
 struct ath10k_fw_crash_data {
        guid_t guid;
        struct timespec64 timestamp;
        __le32 registers[REG_DUMP_COUNT_QCA988X];
        struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX];
+
+       u8 *ramdump_buf;
+       size_t ramdump_buf_len;
 };
 
 struct ath10k_debug {
 
 #include "coredump.h"
 
 #include <linux/devcoredump.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
 #include <linux/utsname.h>
 
 #include "debug.h"
+#include "hw.h"
+
+static const struct ath10k_mem_section qca6174_hw21_register_sections[] = {
+       {0x800, 0x810},
+       {0x820, 0x82C},
+       {0x830, 0x8F4},
+       {0x90C, 0x91C},
+       {0xA14, 0xA18},
+       {0xA84, 0xA94},
+       {0xAA8, 0xAD4},
+       {0xADC, 0xB40},
+       {0x1000, 0x10A4},
+       {0x10BC, 0x111C},
+       {0x1134, 0x1138},
+       {0x1144, 0x114C},
+       {0x1150, 0x115C},
+       {0x1160, 0x1178},
+       {0x1240, 0x1260},
+       {0x2000, 0x207C},
+       {0x3000, 0x3014},
+       {0x4000, 0x4014},
+       {0x5000, 0x5124},
+       {0x6000, 0x6040},
+       {0x6080, 0x60CC},
+       {0x6100, 0x611C},
+       {0x6140, 0x61D8},
+       {0x6200, 0x6238},
+       {0x6240, 0x628C},
+       {0x62C0, 0x62EC},
+       {0x6380, 0x63E8},
+       {0x6400, 0x6440},
+       {0x6480, 0x64CC},
+       {0x6500, 0x651C},
+       {0x6540, 0x6580},
+       {0x6600, 0x6638},
+       {0x6640, 0x668C},
+       {0x66C0, 0x66EC},
+       {0x6780, 0x67E8},
+       {0x7080, 0x708C},
+       {0x70C0, 0x70C8},
+       {0x7400, 0x741C},
+       {0x7440, 0x7454},
+       {0x7800, 0x7818},
+       {0x8000, 0x8004},
+       {0x8010, 0x8064},
+       {0x8080, 0x8084},
+       {0x80A0, 0x80A4},
+       {0x80C0, 0x80C4},
+       {0x80E0, 0x80F4},
+       {0x8100, 0x8104},
+       {0x8110, 0x812C},
+       {0x9000, 0x9004},
+       {0x9800, 0x982C},
+       {0x9830, 0x9838},
+       {0x9840, 0x986C},
+       {0x9870, 0x9898},
+       {0x9A00, 0x9C00},
+       {0xD580, 0xD59C},
+       {0xF000, 0xF0E0},
+       {0xF140, 0xF190},
+       {0xF250, 0xF25C},
+       {0xF260, 0xF268},
+       {0xF26C, 0xF2A8},
+       {0x10008, 0x1000C},
+       {0x10014, 0x10018},
+       {0x1001C, 0x10020},
+       {0x10024, 0x10028},
+       {0x10030, 0x10034},
+       {0x10040, 0x10054},
+       {0x10058, 0x1007C},
+       {0x10080, 0x100C4},
+       {0x100C8, 0x10114},
+       {0x1012C, 0x10130},
+       {0x10138, 0x10144},
+       {0x10200, 0x10220},
+       {0x10230, 0x10250},
+       {0x10260, 0x10280},
+       {0x10290, 0x102B0},
+       {0x102C0, 0x102DC},
+       {0x102E0, 0x102F4},
+       {0x102FC, 0x1037C},
+       {0x10380, 0x10390},
+       {0x10800, 0x10828},
+       {0x10840, 0x10844},
+       {0x10880, 0x10884},
+       {0x108C0, 0x108E8},
+       {0x10900, 0x10928},
+       {0x10940, 0x10944},
+       {0x10980, 0x10984},
+       {0x109C0, 0x109E8},
+       {0x10A00, 0x10A28},
+       {0x10A40, 0x10A50},
+       {0x11000, 0x11028},
+       {0x11030, 0x11034},
+       {0x11038, 0x11068},
+       {0x11070, 0x11074},
+       {0x11078, 0x110A8},
+       {0x110B0, 0x110B4},
+       {0x110B8, 0x110E8},
+       {0x110F0, 0x110F4},
+       {0x110F8, 0x11128},
+       {0x11138, 0x11144},
+       {0x11178, 0x11180},
+       {0x111B8, 0x111C0},
+       {0x111F8, 0x11200},
+       {0x11238, 0x1123C},
+       {0x11270, 0x11274},
+       {0x11278, 0x1127C},
+       {0x112B0, 0x112B4},
+       {0x112B8, 0x112BC},
+       {0x112F0, 0x112F4},
+       {0x112F8, 0x112FC},
+       {0x11338, 0x1133C},
+       {0x11378, 0x1137C},
+       {0x113B8, 0x113BC},
+       {0x113F8, 0x113FC},
+       {0x11438, 0x11440},
+       {0x11478, 0x11480},
+       {0x114B8, 0x114BC},
+       {0x114F8, 0x114FC},
+       {0x11538, 0x1153C},
+       {0x11578, 0x1157C},
+       {0x115B8, 0x115BC},
+       {0x115F8, 0x115FC},
+       {0x11638, 0x1163C},
+       {0x11678, 0x1167C},
+       {0x116B8, 0x116BC},
+       {0x116F8, 0x116FC},
+       {0x11738, 0x1173C},
+       {0x11778, 0x1177C},
+       {0x117B8, 0x117BC},
+       {0x117F8, 0x117FC},
+       {0x17000, 0x1701C},
+       {0x17020, 0x170AC},
+       {0x18000, 0x18050},
+       {0x18054, 0x18074},
+       {0x18080, 0x180D4},
+       {0x180DC, 0x18104},
+       {0x18108, 0x1813C},
+       {0x18144, 0x18148},
+       {0x18168, 0x18174},
+       {0x18178, 0x18180},
+       {0x181C8, 0x181E0},
+       {0x181E4, 0x181E8},
+       {0x181EC, 0x1820C},
+       {0x1825C, 0x18280},
+       {0x18284, 0x18290},
+       {0x18294, 0x182A0},
+       {0x18300, 0x18304},
+       {0x18314, 0x18320},
+       {0x18328, 0x18350},
+       {0x1835C, 0x1836C},
+       {0x18370, 0x18390},
+       {0x18398, 0x183AC},
+       {0x183BC, 0x183D8},
+       {0x183DC, 0x183F4},
+       {0x18400, 0x186F4},
+       {0x186F8, 0x1871C},
+       {0x18720, 0x18790},
+       {0x19800, 0x19830},
+       {0x19834, 0x19840},
+       {0x19880, 0x1989C},
+       {0x198A4, 0x198B0},
+       {0x198BC, 0x19900},
+       {0x19C00, 0x19C88},
+       {0x19D00, 0x19D20},
+       {0x19E00, 0x19E7C},
+       {0x19E80, 0x19E94},
+       {0x19E98, 0x19EAC},
+       {0x19EB0, 0x19EBC},
+       {0x19F70, 0x19F74},
+       {0x19F80, 0x19F8C},
+       {0x19FA0, 0x19FB4},
+       {0x19FC0, 0x19FD8},
+       {0x1A000, 0x1A200},
+       {0x1A204, 0x1A210},
+       {0x1A228, 0x1A22C},
+       {0x1A230, 0x1A248},
+       {0x1A250, 0x1A270},
+       {0x1A280, 0x1A290},
+       {0x1A2A0, 0x1A2A4},
+       {0x1A2C0, 0x1A2EC},
+       {0x1A300, 0x1A3BC},
+       {0x1A3F0, 0x1A3F4},
+       {0x1A3F8, 0x1A434},
+       {0x1A438, 0x1A444},
+       {0x1A448, 0x1A468},
+       {0x1A580, 0x1A58C},
+       {0x1A644, 0x1A654},
+       {0x1A670, 0x1A698},
+       {0x1A6AC, 0x1A6B0},
+       {0x1A6D0, 0x1A6D4},
+       {0x1A6EC, 0x1A70C},
+       {0x1A710, 0x1A738},
+       {0x1A7C0, 0x1A7D0},
+       {0x1A7D4, 0x1A7D8},
+       {0x1A7DC, 0x1A7E4},
+       {0x1A7F0, 0x1A7F8},
+       {0x1A888, 0x1A89C},
+       {0x1A8A8, 0x1A8AC},
+       {0x1A8C0, 0x1A8DC},
+       {0x1A8F0, 0x1A8FC},
+       {0x1AE04, 0x1AE08},
+       {0x1AE18, 0x1AE24},
+       {0x1AF80, 0x1AF8C},
+       {0x1AFA0, 0x1AFB4},
+       {0x1B000, 0x1B200},
+       {0x1B284, 0x1B288},
+       {0x1B2D0, 0x1B2D8},
+       {0x1B2DC, 0x1B2EC},
+       {0x1B300, 0x1B340},
+       {0x1B374, 0x1B378},
+       {0x1B380, 0x1B384},
+       {0x1B388, 0x1B38C},
+       {0x1B404, 0x1B408},
+       {0x1B420, 0x1B428},
+       {0x1B440, 0x1B444},
+       {0x1B448, 0x1B44C},
+       {0x1B450, 0x1B458},
+       {0x1B45C, 0x1B468},
+       {0x1B584, 0x1B58C},
+       {0x1B68C, 0x1B690},
+       {0x1B6AC, 0x1B6B0},
+       {0x1B7F0, 0x1B7F8},
+       {0x1C800, 0x1CC00},
+       {0x1CE00, 0x1CE04},
+       {0x1CF80, 0x1CF84},
+       {0x1D200, 0x1D800},
+       {0x1E000, 0x20014},
+       {0x20100, 0x20124},
+       {0x21400, 0x217A8},
+       {0x21800, 0x21BA8},
+       {0x21C00, 0x21FA8},
+       {0x22000, 0x223A8},
+       {0x22400, 0x227A8},
+       {0x22800, 0x22BA8},
+       {0x22C00, 0x22FA8},
+       {0x23000, 0x233A8},
+       {0x24000, 0x24034},
+       {0x26000, 0x26064},
+       {0x27000, 0x27024},
+       {0x34000, 0x3400C},
+       {0x34400, 0x3445C},
+       {0x34800, 0x3485C},
+       {0x34C00, 0x34C5C},
+       {0x35000, 0x3505C},
+       {0x35400, 0x3545C},
+       {0x35800, 0x3585C},
+       {0x35C00, 0x35C5C},
+       {0x36000, 0x3605C},
+       {0x38000, 0x38064},
+       {0x38070, 0x380E0},
+       {0x3A000, 0x3A064},
+       {0x40000, 0x400A4},
+       {0x80000, 0x8000C},
+       {0x80010, 0x80020},
+};
+
+static const struct ath10k_mem_section qca6174_hw30_register_sections[] = {
+       {0x800, 0x810},
+       {0x820, 0x82C},
+       {0x830, 0x8F4},
+       {0x90C, 0x91C},
+       {0xA14, 0xA18},
+       {0xA84, 0xA94},
+       {0xAA8, 0xAD4},
+       {0xADC, 0xB40},
+       {0x1000, 0x10A4},
+       {0x10BC, 0x111C},
+       {0x1134, 0x1138},
+       {0x1144, 0x114C},
+       {0x1150, 0x115C},
+       {0x1160, 0x1178},
+       {0x1240, 0x1260},
+       {0x2000, 0x207C},
+       {0x3000, 0x3014},
+       {0x4000, 0x4014},
+       {0x5000, 0x5124},
+       {0x6000, 0x6040},
+       {0x6080, 0x60CC},
+       {0x6100, 0x611C},
+       {0x6140, 0x61D8},
+       {0x6200, 0x6238},
+       {0x6240, 0x628C},
+       {0x62C0, 0x62EC},
+       {0x6380, 0x63E8},
+       {0x6400, 0x6440},
+       {0x6480, 0x64CC},
+       {0x6500, 0x651C},
+       {0x6540, 0x6580},
+       {0x6600, 0x6638},
+       {0x6640, 0x668C},
+       {0x66C0, 0x66EC},
+       {0x6780, 0x67E8},
+       {0x7080, 0x708C},
+       {0x70C0, 0x70C8},
+       {0x7400, 0x741C},
+       {0x7440, 0x7454},
+       {0x7800, 0x7818},
+       {0x8000, 0x8004},
+       {0x8010, 0x8064},
+       {0x8080, 0x8084},
+       {0x80A0, 0x80A4},
+       {0x80C0, 0x80C4},
+       {0x80E0, 0x80F4},
+       {0x8100, 0x8104},
+       {0x8110, 0x812C},
+       {0x9000, 0x9004},
+       {0x9800, 0x982C},
+       {0x9830, 0x9838},
+       {0x9840, 0x986C},
+       {0x9870, 0x9898},
+       {0x9A00, 0x9C00},
+       {0xD580, 0xD59C},
+       {0xF000, 0xF0E0},
+       {0xF140, 0xF190},
+       {0xF250, 0xF25C},
+       {0xF260, 0xF268},
+       {0xF26C, 0xF2A8},
+       {0x10008, 0x1000C},
+       {0x10014, 0x10018},
+       {0x1001C, 0x10020},
+       {0x10024, 0x10028},
+       {0x10030, 0x10034},
+       {0x10040, 0x10054},
+       {0x10058, 0x1007C},
+       {0x10080, 0x100C4},
+       {0x100C8, 0x10114},
+       {0x1012C, 0x10130},
+       {0x10138, 0x10144},
+       {0x10200, 0x10220},
+       {0x10230, 0x10250},
+       {0x10260, 0x10280},
+       {0x10290, 0x102B0},
+       {0x102C0, 0x102DC},
+       {0x102E0, 0x102F4},
+       {0x102FC, 0x1037C},
+       {0x10380, 0x10390},
+       {0x10800, 0x10828},
+       {0x10840, 0x10844},
+       {0x10880, 0x10884},
+       {0x108C0, 0x108E8},
+       {0x10900, 0x10928},
+       {0x10940, 0x10944},
+       {0x10980, 0x10984},
+       {0x109C0, 0x109E8},
+       {0x10A00, 0x10A28},
+       {0x10A40, 0x10A50},
+       {0x11000, 0x11028},
+       {0x11030, 0x11034},
+       {0x11038, 0x11068},
+       {0x11070, 0x11074},
+       {0x11078, 0x110A8},
+       {0x110B0, 0x110B4},
+       {0x110B8, 0x110E8},
+       {0x110F0, 0x110F4},
+       {0x110F8, 0x11128},
+       {0x11138, 0x11144},
+       {0x11178, 0x11180},
+       {0x111B8, 0x111C0},
+       {0x111F8, 0x11200},
+       {0x11238, 0x1123C},
+       {0x11270, 0x11274},
+       {0x11278, 0x1127C},
+       {0x112B0, 0x112B4},
+       {0x112B8, 0x112BC},
+       {0x112F0, 0x112F4},
+       {0x112F8, 0x112FC},
+       {0x11338, 0x1133C},
+       {0x11378, 0x1137C},
+       {0x113B8, 0x113BC},
+       {0x113F8, 0x113FC},
+       {0x11438, 0x11440},
+       {0x11478, 0x11480},
+       {0x114B8, 0x114BC},
+       {0x114F8, 0x114FC},
+       {0x11538, 0x1153C},
+       {0x11578, 0x1157C},
+       {0x115B8, 0x115BC},
+       {0x115F8, 0x115FC},
+       {0x11638, 0x1163C},
+       {0x11678, 0x1167C},
+       {0x116B8, 0x116BC},
+       {0x116F8, 0x116FC},
+       {0x11738, 0x1173C},
+       {0x11778, 0x1177C},
+       {0x117B8, 0x117BC},
+       {0x117F8, 0x117FC},
+       {0x17000, 0x1701C},
+       {0x17020, 0x170AC},
+       {0x18000, 0x18050},
+       {0x18054, 0x18074},
+       {0x18080, 0x180D4},
+       {0x180DC, 0x18104},
+       {0x18108, 0x1813C},
+       {0x18144, 0x18148},
+       {0x18168, 0x18174},
+       {0x18178, 0x18180},
+       {0x181C8, 0x181E0},
+       {0x181E4, 0x181E8},
+       {0x181EC, 0x1820C},
+       {0x1825C, 0x18280},
+       {0x18284, 0x18290},
+       {0x18294, 0x182A0},
+       {0x18300, 0x18304},
+       {0x18314, 0x18320},
+       {0x18328, 0x18350},
+       {0x1835C, 0x1836C},
+       {0x18370, 0x18390},
+       {0x18398, 0x183AC},
+       {0x183BC, 0x183D8},
+       {0x183DC, 0x183F4},
+       {0x18400, 0x186F4},
+       {0x186F8, 0x1871C},
+       {0x18720, 0x18790},
+       {0x19800, 0x19830},
+       {0x19834, 0x19840},
+       {0x19880, 0x1989C},
+       {0x198A4, 0x198B0},
+       {0x198BC, 0x19900},
+       {0x19C00, 0x19C88},
+       {0x19D00, 0x19D20},
+       {0x19E00, 0x19E7C},
+       {0x19E80, 0x19E94},
+       {0x19E98, 0x19EAC},
+       {0x19EB0, 0x19EBC},
+       {0x19F70, 0x19F74},
+       {0x19F80, 0x19F8C},
+       {0x19FA0, 0x19FB4},
+       {0x19FC0, 0x19FD8},
+       {0x1A000, 0x1A200},
+       {0x1A204, 0x1A210},
+       {0x1A228, 0x1A22C},
+       {0x1A230, 0x1A248},
+       {0x1A250, 0x1A270},
+       {0x1A280, 0x1A290},
+       {0x1A2A0, 0x1A2A4},
+       {0x1A2C0, 0x1A2EC},
+       {0x1A300, 0x1A3BC},
+       {0x1A3F0, 0x1A3F4},
+       {0x1A3F8, 0x1A434},
+       {0x1A438, 0x1A444},
+       {0x1A448, 0x1A468},
+       {0x1A580, 0x1A58C},
+       {0x1A644, 0x1A654},
+       {0x1A670, 0x1A698},
+       {0x1A6AC, 0x1A6B0},
+       {0x1A6D0, 0x1A6D4},
+       {0x1A6EC, 0x1A70C},
+       {0x1A710, 0x1A738},
+       {0x1A7C0, 0x1A7D0},
+       {0x1A7D4, 0x1A7D8},
+       {0x1A7DC, 0x1A7E4},
+       {0x1A7F0, 0x1A7F8},
+       {0x1A888, 0x1A89C},
+       {0x1A8A8, 0x1A8AC},
+       {0x1A8C0, 0x1A8DC},
+       {0x1A8F0, 0x1A8FC},
+       {0x1AE04, 0x1AE08},
+       {0x1AE18, 0x1AE24},
+       {0x1AF80, 0x1AF8C},
+       {0x1AFA0, 0x1AFB4},
+       {0x1B000, 0x1B200},
+       {0x1B284, 0x1B288},
+       {0x1B2D0, 0x1B2D8},
+       {0x1B2DC, 0x1B2EC},
+       {0x1B300, 0x1B340},
+       {0x1B374, 0x1B378},
+       {0x1B380, 0x1B384},
+       {0x1B388, 0x1B38C},
+       {0x1B404, 0x1B408},
+       {0x1B420, 0x1B428},
+       {0x1B440, 0x1B444},
+       {0x1B448, 0x1B44C},
+       {0x1B450, 0x1B458},
+       {0x1B45C, 0x1B468},
+       {0x1B584, 0x1B58C},
+       {0x1B68C, 0x1B690},
+       {0x1B6AC, 0x1B6B0},
+       {0x1B7F0, 0x1B7F8},
+       {0x1C800, 0x1CC00},
+       {0x1CE00, 0x1CE04},
+       {0x1CF80, 0x1CF84},
+       {0x1D200, 0x1D800},
+       {0x1E000, 0x20014},
+       {0x20100, 0x20124},
+       {0x21400, 0x217A8},
+       {0x21800, 0x21BA8},
+       {0x21C00, 0x21FA8},
+       {0x22000, 0x223A8},
+       {0x22400, 0x227A8},
+       {0x22800, 0x22BA8},
+       {0x22C00, 0x22FA8},
+       {0x23000, 0x233A8},
+       {0x24000, 0x24034},
+       {0x26000, 0x26064},
+       {0x27000, 0x27024},
+       {0x34000, 0x3400C},
+       {0x34400, 0x3445C},
+       {0x34800, 0x3485C},
+       {0x34C00, 0x34C5C},
+       {0x35000, 0x3505C},
+       {0x35400, 0x3545C},
+       {0x35800, 0x3585C},
+       {0x35C00, 0x35C5C},
+       {0x36000, 0x3605C},
+       {0x38000, 0x38064},
+       {0x38070, 0x380E0},
+       {0x3A000, 0x3A074},
+       {0x40000, 0x400A4},
+       {0x80000, 0x8000C},
+       {0x80010, 0x80020},
+};
+
+static const struct ath10k_mem_region qca6174_hw10_mem_regions[] = {
+       {
+               .type = ATH10K_MEM_REGION_TYPE_DRAM,
+               .start = 0x400000,
+               .len = 0x70000,
+               .name = "DRAM",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_REG,
+
+               /* RTC_SOC_BASE_ADDRESS */
+               .start = 0x0,
+
+               /* WLAN_MBOX_BASE_ADDRESS - RTC_SOC_BASE_ADDRESS */
+               .len = 0x800 - 0x0,
+
+               .name = "REG_PART1",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_REG,
+
+               /* STEREO_BASE_ADDRESS */
+               .start = 0x27000,
+
+               /* USB_BASE_ADDRESS - STEREO_BASE_ADDRESS */
+               .len = 0x60000 - 0x27000,
+
+               .name = "REG_PART2",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+};
+
+static const struct ath10k_mem_region qca6174_hw21_mem_regions[] = {
+       {
+               .type = ATH10K_MEM_REGION_TYPE_DRAM,
+               .start = 0x400000,
+               .len = 0x70000,
+               .name = "DRAM",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_AXI,
+               .start = 0xa0000,
+               .len = 0x18000,
+               .name = "AXI",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_REG,
+               .start = 0x800,
+               .len = 0x80020 - 0x800,
+               .name = "REG_TOTAL",
+               .section_table = {
+                       .sections = qca6174_hw21_register_sections,
+                       .size = ARRAY_SIZE(qca6174_hw21_register_sections),
+               },
+       },
+};
+
+static const struct ath10k_mem_region qca6174_hw30_mem_regions[] = {
+       {
+               .type = ATH10K_MEM_REGION_TYPE_DRAM,
+               .start = 0x400000,
+               .len = 0x90000,
+               .name = "DRAM",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_AXI,
+               .start = 0xa0000,
+               .len = 0x18000,
+               .name = "AXI",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_REG,
+               .start = 0x800,
+               .len = 0x80020 - 0x800,
+               .name = "REG_TOTAL",
+               .section_table = {
+                       .sections = qca6174_hw30_register_sections,
+                       .size = ARRAY_SIZE(qca6174_hw30_register_sections),
+               },
+       },
+
+       /* IRAM dump must be put last */
+       {
+               .type = ATH10K_MEM_REGION_TYPE_IRAM1,
+               .start = 0x00980000,
+               .len = 0x00080000,
+               .name = "IRAM1",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+       {
+               .type = ATH10K_MEM_REGION_TYPE_IRAM2,
+               .start = 0x00a00000,
+               .len = 0x00040000,
+               .name = "IRAM2",
+               .section_table = {
+                       .sections = NULL,
+                       .size = 0,
+               },
+       },
+};
+
+static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
+       {
+               .hw_id = QCA6174_HW_1_0_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw10_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA6174_HW_1_1_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw10_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA6174_HW_1_3_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw10_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw10_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA6174_HW_2_1_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw21_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw21_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA6174_HW_3_0_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw30_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA6174_HW_3_2_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw30_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
+               },
+       },
+       {
+               .hw_id = QCA9377_HW_1_1_DEV_VERSION,
+               .region_table = {
+                       .regions = qca6174_hw30_mem_regions,
+                       .size = ARRAY_SIZE(qca6174_hw30_mem_regions),
+               },
+       },
+};
+
+static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)
+{
+       const struct ath10k_hw_mem_layout *hw;
+       const struct ath10k_mem_region *mem_region;
+       size_t size = 0;
+       int i;
+
+       hw = ath10k_coredump_get_mem_layout(ar);
+
+       if (!hw)
+               return 0;
+
+       mem_region = &hw->region_table.regions[0];
+
+       for (i = 0; i < hw->region_table.size; i++) {
+               size += mem_region->len;
+               mem_region++;
+       }
+
+       /* reserve space for the headers */
+       size += hw->region_table.size * sizeof(struct ath10k_dump_ram_data_hdr);
+
+       /* make sure it is aligned 16 bytes for debug message print out */
+       size = ALIGN(size, 16);
+
+       return size;
+}
+
+const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar)
+{
+       int i;
+
+       if (!test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask))
+               return NULL;
+
+       if (WARN_ON(ar->target_version == 0))
+               return NULL;
+
+       for (i = 0; i < ARRAY_SIZE(hw_mem_layouts); i++) {
+               if (ar->target_version == hw_mem_layouts[i].hw_id)
+                       return &hw_mem_layouts[i];
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(ath10k_coredump_get_mem_layout);
 
 struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
 {
                len += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
                        CE_COUNT * sizeof(ce_hdr->entries[0]);
 
+       if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask))
+               len += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+
        sofar += hdr_len;
 
        /* This is going to get big when we start dumping FW RAM and such,
                        CE_COUNT * sizeof(ce_hdr->entries[0]);
        }
 
+       /* Gather ram dump */
+       if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
+               dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+               dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA);
+               dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len);
+               memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf,
+                      crash_data->ramdump_buf_len);
+               sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len;
+       }
+
        spin_unlock_bh(&ar->data_lock);
 
        return dump_data;
        return 0;
 }
 
+int ath10k_coredump_register(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
+
+       if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) {
+               crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar);
+
+               crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len);
+               if (!crash_data->ramdump_buf)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void ath10k_coredump_unregister(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data = ar->coredump.fw_crash_data;
+
+       vfree(crash_data->ramdump_buf);
+}
+
 void ath10k_coredump_destroy(struct ath10k *ar)
 {
+       if (ar->coredump.fw_crash_data->ramdump_buf) {
+               vfree(ar->coredump.fw_crash_data->ramdump_buf);
+               ar->coredump.fw_crash_data->ramdump_buf = NULL;
+               ar->coredump.fw_crash_data->ramdump_buf_len = 0;
+       }
+
        vfree(ar->coredump.fw_crash_data);
        ar->coredump.fw_crash_data = NULL;
 }
 
        ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
        ATH10K_FW_CRASH_DUMP_CE_DATA = 1,
 
+       /* contains multiple struct ath10k_dump_ram_data_hdr */
+       ATH10K_FW_CRASH_DUMP_RAM_DATA = 2,
+
        ATH10K_FW_CRASH_DUMP_MAX,
 };
 
        u8 data[0];
 } __packed;
 
+struct ath10k_dump_ram_data_hdr {
+       /* enum ath10k_mem_region_type */
+       __le32 region_type;
+
+       __le32 start;
+
+       /* length of payload data, not including this header */
+       __le32 length;
+
+       u8 data[0];
+};
+
+/* magic number to fill the holes not copied due to sections in regions */
+#define ATH10K_MAGIC_NOT_COPIED                0xAA
+
+/* part of user space ABI */
+enum ath10k_mem_region_type {
+       ATH10K_MEM_REGION_TYPE_REG      = 1,
+       ATH10K_MEM_REGION_TYPE_DRAM     = 2,
+       ATH10K_MEM_REGION_TYPE_AXI      = 3,
+       ATH10K_MEM_REGION_TYPE_IRAM1    = 4,
+       ATH10K_MEM_REGION_TYPE_IRAM2    = 5,
+};
+
+/* Define a section of the region which should be copied. As not all parts
+ * of the memory is possible to copy, for example some of the registers can
+ * be like that, sections can be used to define what is safe to copy.
+ *
+ * To minimize the size of the array, the list must obey the format:
+ * '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must
+ * also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise
+ * we may encouter error in the dump processing.
+ */
+struct ath10k_mem_section {
+       u32 start;
+       u32 end;
+};
+
+/* One region of a memory layout. If the sections field is null entire
+ * region is copied. If sections is non-null only the areas specified in
+ * sections are copied and rest of the areas are filled with
+ * ATH10K_MAGIC_NOT_COPIED.
+ */
+struct ath10k_mem_region {
+       enum ath10k_mem_region_type type;
+       u32 start;
+       u32 len;
+
+       const char *name;
+
+       struct {
+               const struct ath10k_mem_section *sections;
+               u32 size;
+       } section_table;
+};
+
+/* Contains the memory layout of a hardware version identified with the
+ * hardware id, split into regions.
+ */
+struct ath10k_hw_mem_layout {
+       u32 hw_id;
+
+       struct {
+               const struct ath10k_mem_region *regions;
+               int size;
+       } region_table;
+};
+
+/* FIXME: where to put this? */
+extern unsigned long ath10k_coredump_mask;
+
 #ifdef CONFIG_DEV_COREDUMP
 
 int ath10k_coredump_submit(struct ath10k *ar);
 struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar);
 int ath10k_coredump_create(struct ath10k *ar);
+int ath10k_coredump_register(struct ath10k *ar);
+void ath10k_coredump_unregister(struct ath10k *ar);
 void ath10k_coredump_destroy(struct ath10k *ar);
 
+const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar);
+
 #else /* CONFIG_DEV_COREDUMP */
 
 static inline int ath10k_coredump_submit(struct ath10k *ar)
        return 0;
 }
 
+static inline int ath10k_coredump_register(struct ath10k *ar)
+{
+       return 0;
+}
+
+static inline void ath10k_coredump_unregister(struct ath10k *ar)
+{
+}
+
 static inline void ath10k_coredump_destroy(struct ath10k *ar)
 {
 }
 
+static inline const struct ath10k_hw_mem_layout *
+ath10k_coredump_get_mem_layout(struct ath10k *ar)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_DEV_COREDUMP */
 
 #endif /* _COREDUMP_H_ */
 
 #define PCIE_INTR_CLR_ADDRESS                  ar->regs->pcie_intr_clr_address
 #define SCRATCH_3_ADDRESS                      ar->regs->scratch_3_address
 #define CPU_INTR_ADDRESS                       0x0010
+#define FW_RAM_CONFIG_ADDRESS                  0x0018
 
 #define CCNT_TO_MSEC(ar, x) ((x) / ar->hw_params.channel_counters_freq_hz)
 
 
 #define ATH10K_PCI_TARGET_WAIT 3000
 #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
 
+/* Maximum number of bytes that can be handled atomically by
+ * diag read and write.
+ */
+#define ATH10K_DIAG_TRANSFER_LIMIT     0x5000
+
 static const struct pci_device_id ath10k_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
        { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
                crash_data->registers[i] = reg_dump_values[i];
 }
 
+static int ath10k_pci_dump_memory_section(struct ath10k *ar,
+                                         const struct ath10k_mem_region *mem_region,
+                                         u8 *buf, size_t buf_len)
+{
+       const struct ath10k_mem_section *cur_section, *next_section;
+       unsigned int count, section_size, skip_size;
+       int ret, i, j;
+
+       if (!mem_region || !buf)
+               return 0;
+
+       if (mem_region->section_table.size < 0)
+               return 0;
+
+       cur_section = &mem_region->section_table.sections[0];
+
+       if (mem_region->start > cur_section->start) {
+               ath10k_warn(ar, "incorrect memdump region 0x%x with section start addrress 0x%x.\n",
+                           mem_region->start, cur_section->start);
+               return 0;
+       }
+
+       skip_size = cur_section->start - mem_region->start;
+
+       /* fill the gap between the first register section and register
+        * start address
+        */
+       for (i = 0; i < skip_size; i++) {
+               *buf = ATH10K_MAGIC_NOT_COPIED;
+               buf++;
+       }
+
+       count = 0;
+
+       for (i = 0; cur_section != NULL; i++) {
+               section_size = cur_section->end - cur_section->start;
+
+               if (section_size <= 0) {
+                       ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n",
+                                   cur_section->start,
+                                   cur_section->end);
+                       break;
+               }
+
+               if ((i + 1) == mem_region->section_table.size) {
+                       /* last section */
+                       next_section = NULL;
+                       skip_size = 0;
+               } else {
+                       next_section = cur_section + 1;
+
+                       if (cur_section->end > next_section->start) {
+                               ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n",
+                                           next_section->start,
+                                           cur_section->end);
+                               break;
+                       }
+
+                       skip_size = next_section->start - cur_section->end;
+               }
+
+               if (buf_len < (skip_size + section_size)) {
+                       ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len);
+                       break;
+               }
+
+               buf_len -= skip_size + section_size;
+
+               /* read section to dest memory */
+               ret = ath10k_pci_diag_read_mem(ar, cur_section->start,
+                                              buf, section_size);
+               if (ret) {
+                       ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n",
+                                   cur_section->start, ret);
+                       break;
+               }
+
+               buf += section_size;
+               count += section_size;
+
+               /* fill in the gap between this section and the next */
+               for (j = 0; j < skip_size; j++) {
+                       *buf = ATH10K_MAGIC_NOT_COPIED;
+                       buf++;
+               }
+
+               count += skip_size;
+
+               if (!next_section)
+                       /* this was the last section */
+                       break;
+
+               cur_section = next_section;
+       }
+
+       return count;
+}
+
+static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config)
+{
+       u32 val;
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                          FW_RAM_CONFIG_ADDRESS, config);
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+                               FW_RAM_CONFIG_ADDRESS);
+       if (val != config) {
+               ath10k_warn(ar, "failed to set RAM config from 0x%x to 0x%x\n",
+                           val, config);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void ath10k_pci_dump_memory(struct ath10k *ar,
+                                  struct ath10k_fw_crash_data *crash_data)
+{
+       const struct ath10k_hw_mem_layout *mem_layout;
+       const struct ath10k_mem_region *current_region;
+       struct ath10k_dump_ram_data_hdr *hdr;
+       u32 count, shift;
+       size_t buf_len;
+       int ret, i;
+       u8 *buf;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       if (!crash_data)
+               return;
+
+       mem_layout = ath10k_coredump_get_mem_layout(ar);
+       if (!mem_layout)
+               return;
+
+       current_region = &mem_layout->region_table.regions[0];
+
+       buf = crash_data->ramdump_buf;
+       buf_len = crash_data->ramdump_buf_len;
+
+       memset(buf, 0, buf_len);
+
+       for (i = 0; i < mem_layout->region_table.size; i++) {
+               count = 0;
+
+               if (current_region->len > buf_len) {
+                       ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n",
+                                   current_region->name,
+                                   current_region->len,
+                                   buf_len);
+                       break;
+               }
+
+               /* To get IRAM dump, the host driver needs to switch target
+                * ram config from DRAM to IRAM.
+                */
+               if (current_region->type == ATH10K_MEM_REGION_TYPE_IRAM1 ||
+                   current_region->type == ATH10K_MEM_REGION_TYPE_IRAM2) {
+                       shift = current_region->start >> 20;
+
+                       ret = ath10k_pci_set_ram_config(ar, shift);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to switch ram config to IRAM for section %s: %d\n",
+                                           current_region->name, ret);
+                               break;
+                       }
+               }
+
+               /* Reserve space for the header. */
+               hdr = (void *)buf;
+               buf += sizeof(*hdr);
+               buf_len -= sizeof(*hdr);
+
+               if (current_region->section_table.size > 0) {
+                       /* Copy each section individually. */
+                       count = ath10k_pci_dump_memory_section(ar,
+                                                              current_region,
+                                                              buf,
+                                                              current_region->len);
+               } else {
+                       /* No individiual memory sections defined so we can
+                        * copy the entire memory region.
+                        */
+                       ret = ath10k_pci_diag_read_mem(ar,
+                                                      current_region->start,
+                                                      buf,
+                                                      current_region->len);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to copy ramdump region %s: %d\n",
+                                           current_region->name, ret);
+                               break;
+                       }
+
+                       count = current_region->len;
+               }
+
+               hdr->region_type = cpu_to_le32(current_region->type);
+               hdr->start = cpu_to_le32(current_region->start);
+               hdr->length = cpu_to_le32(count);
+
+               if (count == 0)
+                       /* Note: the header remains, just with zero length. */
+                       break;
+
+               buf += count;
+               buf_len -= count;
+
+               current_region++;
+       }
+}
+
 static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
 {
        struct ath10k_fw_crash_data *crash_data;
        ath10k_print_driver_info(ar);
        ath10k_pci_dump_registers(ar, crash_data);
        ath10k_ce_dump_registers(ar, crash_data);
+       ath10k_pci_dump_memory(ar, crash_data);
 
        spin_unlock_bh(&ar->data_lock);