--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2641,6 +2641,17 @@ static const struct fw_mem_map qca99x0_f
 	{QCA99X0_APB_REG_SPACE_2, QCA99X0_APB_REG_LEN_2, ATTR_REG_SPACE},
 };
 
+static const struct fw_mem_map ipq40xx_fw_mem_map[] = {
+	{QCA99X0_DRAM_ADDR, IPQ40XX_DRAM_LEN, 0},
+	{QCA99X0_SRAM_ADDR, QCA99X0_SRAM_LEN, ATTR_SRAM_MEM},
+	{QCA99X0_IRAM_ADDR, QCA99X0_IRAM_LEN, 0},
+	{QCA99X0_APB_REG_SPACE_1, QCA99X0_APB_REG_LEN_1, ATTR_REG_SPACE},
+	{QCA99X0_WIFI_REG_SPACE, QCA99X0_WIFI_REG_LEN, ATTR_REG_SPACE},
+	{QCA99X0_CE_REG_SPACE, QCA99X0_CE_REG_LEN, ATTR_REG_SPACE},
+	{QCA99X0_SOC_REG_SPACE, QCA99X0_SOC_REG_LEN, ATTR_SOC_REG_SPACE},
+	{QCA99X0_APB_REG_SPACE_2, QCA99X0_APB_REG_LEN_2, ATTR_REG_SPACE},
+};
+
 static int ath10k_dbg_qca99x0_fw_sram_dump(struct ath10k *ar, u32 sram_base,
 					   u8 *dst_buf, u32 len)
 {
@@ -2658,7 +2669,7 @@ static int ath10k_dbg_qca99x0_fw_sram_du
 	return 0;
 }
 
-static int ath10k_dbg_qca99x0_hw_reg_dump(struct ath10k *ar, u32 base_addr,
+static int ath10k_dbg_hw_reg_dump(struct ath10k *ar, u32 base_addr,
 				          u8 *dst_buf, u32 len)
 {
 	struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -2705,7 +2716,7 @@ void ath10k_dbg_qca99x0_bug_on_fw_assert
 							      pos, rd_len);
 			break;
 		case ATTR_REG_SPACE:
-			ret = ath10k_dbg_qca99x0_hw_reg_dump(ar, rd_addr,
+			ret = ath10k_dbg_hw_reg_dump(ar, rd_addr,
 							     pos, rd_len);
 			break;
 		default:
@@ -2731,10 +2742,112 @@ void ath10k_dbg_qca99x0_bug_on_fw_assert
         BUG();
 }
 
+struct reg_range {
+	int start;
+	int end;
+} ipq40xx_soc_reg_range[] = {
+	{ 0x080000, 0x080000 },
+	{ 0x080020, 0x080020 },
+	{ 0x080028, 0x080050 },
+	{ 0x0800d4, 0x0800ec },
+	{ 0x08010c, 0x080118 },
+	{ 0x080284, 0x080290 },
+	{ 0x0802a8, 0x0802b8 },
+	{ 0x0802dc, 0x08030c },
+	{ 0x082000, 0x083fff }};
+
+int ath10k_dbg_ipq40xx_soc_reg_dump(struct ath10k *ar, u32 address,
+		u8 *data, int nbytes)
+{
+	int i = 0;
+	int range = 0;
+	int ret, length;
+	u32 *ptr = (u32 *)data;
+	u8 *data_base = data;
+
+	for (i = 0; i < nbytes/4; i++) {
+		ptr[i] = 0xdeadbeef;
+	}
+
+	for (range = 0; range < 9; range++) {
+		length = ipq40xx_soc_reg_range[range].end - ipq40xx_soc_reg_range[range].start + 4;
+		data = data_base + (ipq40xx_soc_reg_range[range].start - 0x80000);
+		address = ipq40xx_soc_reg_range[range].start;
+		ret = ath10k_hif_diag_read(ar, address, data, length);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+void ath10k_dbg_ipq40xx_bug_on_fw_assert(struct ath10k *ar)
+{
+	u32 rd_addr, rd_len;
+	u8 *dump_addr, *pos, i;
+	int ret;
+
+	dump_addr = (u8 *)ioremap(IPQ40XX_FW_IO_MEM_ADDR,
+				  ATH10K_FW_IO_MEM_REGION_2_SIZE);
+	if (!dump_addr) {
+		ath10k_err(ar, "Cannot access memory to dump WLAN Firmware data\n");
+		return;
+	}
+
+	pos = dump_addr;
+	memset(dump_addr, 0, ATH10K_FW_IO_MEM_REGION_2_SIZE);
+
+	ath10k_err(ar, "Collecting WLAN Firmware Dump...\n");
+
+	for (i = 0; i < ARRAY_SIZE(ipq40xx_fw_mem_map); i++) {
+		rd_addr = ipq40xx_fw_mem_map[i].addr;
+		rd_len = ipq40xx_fw_mem_map[i].len;
+
+		if ((pos + rd_len) >
+				(dump_addr + ATH10K_FW_IO_MEM_REGION_2_SIZE)) {
+			ath10k_err(ar, "Memory overflow, stopping WLAN FW dump collection\n");
+			iounmap(dump_addr);
+			return;
+		}
+
+		switch(ipq40xx_fw_mem_map[i].attr) {
+			case ATTR_REG_SPACE:
+				ret = ath10k_dbg_hw_reg_dump(ar, rd_addr,
+						pos, rd_len);
+				break;
+			case ATTR_SOC_REG_SPACE:
+				ret = ath10k_dbg_ipq40xx_soc_reg_dump(ar, rd_addr,
+						pos, rd_len);
+
+				break;
+			default:
+				ret = ath10k_hif_diag_read(ar, rd_addr,
+						pos, rd_len);
+				break;
+		}
+
+		if (ret) {
+			ath10k_err(ar, "Failed to read from WLAN target address 0x%x: %d\n",
+					rd_addr, ret);
+			iounmap(dump_addr);
+			return;
+		}
+		pos += rd_len;
+	}
+
+	ath10k_err(ar, "Firmware dump collected successfully\n");
+	iounmap(dump_addr);
+
+	ath10k_err(ar, "XXX: Asserting Host...\n");
+	BUG();
+}
+
 void ath10k_dbg_bug_on_fw_assert(struct ath10k *ar)
 {
 	if (QCA_REV_99X0(ar))
 		ath10k_dbg_qca99x0_bug_on_fw_assert(ar);
+	else if (QCA_REV_40XX(ar))
+		ath10k_dbg_ipq40xx_bug_on_fw_assert(ar);
 	else
 		ath10k_dbg_gen_bug_on_fw_assert(ar);
 }
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -70,6 +70,7 @@ __printf(2, 3) void ath10k_warn(struct a
 
 #define        ATTR_SRAM_MEM   BIT(0)
 #define        ATTR_REG_SPACE  BIT(1)
+#define        ATTR_SOC_REG_SPACE      BIT(2)
 
 struct fw_mem_map {
 	u32 addr;
@@ -84,9 +85,11 @@ struct fw_mem_map {
 
 #define ATH10K_FW_IO_MEM_REGION_2_ADDR 0x44000000
 #define ATH10K_FW_IO_MEM_REGION_2_SIZE 0x00600000 /* 6 mb */
+#define IPQ40XX_FW_IO_MEM_ADDR         0x87500000
 
 #define QCA99X0_DRAM_ADDR              0x00400000
 #define QCA99X0_DRAM_LEN               0x00060000 /* 384 kb */
+#define IPQ40XX_DRAM_LEN               0x00068000 /* 416 kb */
 
 #define QCA99X0_IRAM_ADDR              0x00980000
 #define QCA99X0_IRAM_LEN               0x00050000 /* 320 kb */
