From 2e7684f3f96fcd9cc5791fd63fbbccec8132d871 Mon Sep 17 00:00:00 2001 From: Venkat Raju Sana Date: Mon, 11 Mar 2019 19:29:46 -0700 Subject: [PATCH] ip1807x:Initial commit for Minidump Change-Id: If08d31ebb009d6b37ee55861644ab1f11a46ac98 Signed-off-by: Venkat Raju Sana --- .../include/asm/arch-qca-common/qca_common.h | 9 +- board/qca/arm/common/crashdump.c | 400 +++++++++++------- board/qca/arm/ipq807x/ipq807x.c | 10 + common/autoboot.c | 12 +- include/configs/ipq807x.h | 2 +- 5 files changed, 272 insertions(+), 161 deletions(-) diff --git a/arch/arm/include/asm/arch-qca-common/qca_common.h b/arch/arm/include/asm/arch-qca-common/qca_common.h index 62d0d52364..d9d50ec2b9 100644 --- a/arch/arm/include/asm/arch-qca-common/qca_common.h +++ b/arch/arm/include/asm/arch-qca-common/qca_common.h @@ -32,6 +32,12 @@ #define XMK_STR(x)#x #define MK_STR(x)XMK_STR(x) +/* Crashdump levels */ +enum { + FULL_DUMP, + MINIMAL_DUMP +}; + struct ipq_i2c_platdata { int type; }; @@ -53,7 +59,7 @@ int qca_mmc_init(bd_t *, qca_mmc *); void board_mmc_deinit(void); void board_pci_deinit(void); void set_flash_secondary_type(qca_smem_flash_info_t *); -void dump_func(void); +void dump_func(unsigned int dump_level); int do_dumpqca_flash_data(const char *); int apps_iscrashed(void); int set_uuid_bootargs(char *boot_args, char *part_name, int buflen, bool gpt_flag); @@ -74,6 +80,7 @@ struct dumpinfo_t{ * to address to be dumped */ uint32_t offset; /* offset to be added to start address */ + uint32_t dump_level; }; extern struct dumpinfo_t dumpinfo_n[]; extern int dump_entries_n; diff --git a/board/qca/arm/common/crashdump.c b/board/qca/arm/common/crashdump.c index dbf6a1cc35..b893732ca3 100644 --- a/board/qca/arm/common/crashdump.c +++ b/board/qca/arm/common/crashdump.c @@ -47,6 +47,74 @@ DECLARE_GLOBAL_DATA_PTR; static qca_smem_flash_info_t *sfi = &qca_smem_flash_info; +enum { + /*Basic DDR segments */ + QCA_WDT_LOG_DUMP_TYPE_INVALID, + QCA_WDT_LOG_DUMP_TYPE_UNAME, + QCA_WDT_LOG_DUMP_TYPE_DMESG, + QCA_WDT_LOG_DUMP_TYPE_LEVEL1_PT, + /* Module structures are in highmem zone*/ + QCA_WDT_LOG_DUMP_TYPE_WLAN_MOD, +}; +/* This will be used for parsing the TLV data */ +struct qca_wdt_scm_tlv_msg { + unsigned char *msg_buffer; + unsigned char *cur_msg_buffer_pos; + unsigned int len; +}; + +/* Structure to hold crashdump related pointers */ +struct st_tlv_info { + uint64_t start; + uint64_t size; +}; +/* Actual crashdump related data */ +struct qca_wdt_crashdump_data { + unsigned char uname[MAX_UNAME_SIZE]; + unsigned int uname_length; + unsigned char *cpu_context; + unsigned char *log_buf; + unsigned int log_buf_len; + unsigned char *pt_start; + unsigned int pt_len; +}; + +/* Context for NAND Flash memory */ +struct crashdump_flash_nand_cxt { + loff_t start_crashdump_offset; + loff_t cur_crashdump_offset; + int cur_page_data_len; + int write_size; + unsigned char temp_data[MAX_NAND_PAGE_SIZE]; +}; + +/* Context for SPI NOR Flash memory */ +struct crashdump_flash_spi_cxt { + loff_t start_crashdump_offset; + loff_t cur_crashdump_offset; +}; + +#ifdef CONFIG_QCA_MMC +/* Context for EMMC Flash memory */ +struct crashdump_flash_emmc_cxt { + loff_t start_crashdump_offset; + loff_t cur_crashdump_offset; + int cur_blk_data_len; + int write_size; + unsigned char temp_data[MAX_EMMC_BLK_LEN]; +}; +#endif + + +static struct spi_flash *crashdump_spi_flash; +static struct crashdump_flash_nand_cxt crashdump_nand_cnxt; +static struct crashdump_flash_spi_cxt crashdump_flash_spi_cnxt; +#ifdef CONFIG_QCA_MMC +static struct mmc *mmc; +static struct crashdump_flash_emmc_cxt crashdump_emmc_cnxt; +#endif +static struct qca_wdt_crashdump_data g_crashdump_data; +struct qca_wdt_scm_tlv_msg tlv_msg ; __weak int scm_set_boot_addr(bool enable_sec_core) { return -1; @@ -116,8 +184,147 @@ static int tftpdump (int is_aligned_access, uint32_t memaddr, uint32_t size, cha return CMD_RET_SUCCESS; } +/* Extracts the type and length in TLV for current offset */ +static int qca_wdt_scm_extract_tlv_info( + struct qca_wdt_scm_tlv_msg *scm_tlv_msg, + unsigned char *type, + unsigned int *size) +{ + unsigned char *x = scm_tlv_msg->cur_msg_buffer_pos; + unsigned char *y = scm_tlv_msg->msg_buffer + + scm_tlv_msg->len; -static int do_dumpqca_data(void) + if ((x + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE) >= y) + return -EINVAL; + + *type = x[0]; + *size = x[1] | (x[2] << 8); + return 0; +} + +/* Extracts the value from TLV for current offset */ +static int qca_wdt_scm_extract_tlv_data( + struct qca_wdt_scm_tlv_msg *scm_tlv_msg, + unsigned char *data, + unsigned int size) +{ + unsigned char *x = scm_tlv_msg->cur_msg_buffer_pos; + unsigned char *y = scm_tlv_msg->msg_buffer + scm_tlv_msg->len; + + if ((x + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE + size) >= y) + return -EINVAL; + + memcpy(data, x + 3, size); + + scm_tlv_msg->cur_msg_buffer_pos += + (size + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE); + return 0; +} + +/* +* This function parses the TLV message and stores the actual values +* in crashdump_data. For each TLV, It first determines the type and +* length, then it extracts the actual value and stores in the appropriate +* field in crashdump_data. +*/ +static int qca_wdt_extract_crashdump_data( + struct qca_wdt_scm_tlv_msg *scm_tlv_msg, + struct qca_wdt_crashdump_data *crashdump_data) +{ + unsigned char cur_type = QCA_WDT_LOG_DUMP_TYPE_INVALID; + unsigned int cur_size; + int ret_val; + struct st_tlv_info tlv_info; + int static_enum_count; + + for (static_enum_count = QCA_WDT_LOG_DUMP_TYPE_INVALID; static_enum_count + < QCA_WDT_LOG_DUMP_TYPE_WLAN_MOD ; static_enum_count++ ) { + ret_val = qca_wdt_scm_extract_tlv_info(scm_tlv_msg, + &cur_type, &cur_size); + if (!ret_val && cur_type == QCA_WDT_LOG_DUMP_TYPE_UNAME ){ + crashdump_data->uname_length = cur_size; + ret_val = qca_wdt_scm_extract_tlv_data(scm_tlv_msg, + crashdump_data->uname, cur_size); + }else if (!ret_val && cur_type == QCA_WDT_LOG_DUMP_TYPE_DMESG){ + ret_val = qca_wdt_scm_extract_tlv_data(scm_tlv_msg, + (unsigned char *)&tlv_info, + cur_size); + if (!ret_val) { + crashdump_data->log_buf = (uint32_t *)tlv_info.start; + crashdump_data->log_buf_len = *(uint32_t *)tlv_info.size; + } + }else if (!ret_val && cur_type == QCA_WDT_LOG_DUMP_TYPE_LEVEL1_PT){ + ret_val = qca_wdt_scm_extract_tlv_data(scm_tlv_msg,(unsigned char *)&tlv_info,cur_size); + if (!ret_val) { + crashdump_data->pt_start = (uint32_t *)tlv_info.start; + crashdump_data->pt_len = tlv_info.size; + } + } + } + return ret_val; +} + +uint32_t dump_minimal(struct dumpinfo_t *dumpinfo, int indx) { + + if (g_crashdump_data.pt_start && + !strncmp(dumpinfo[indx].name, + "PT.BIN", strlen("PT.BIN"))) { + dumpinfo[indx].start = g_crashdump_data.pt_start; + dumpinfo[indx].size = g_crashdump_data.pt_len; + } else if (g_crashdump_data.log_buf && + !strncmp(dumpinfo[indx].name, + "DMESG.BIN", strlen("DMESG.BIN"))) { + dumpinfo[indx].start = g_crashdump_data.log_buf; + dumpinfo[indx].size = g_crashdump_data.log_buf_len; + } else if (!strncmp(dumpinfo[indx].name, + "UNAME", strlen("UNAME"))) { + dumpinfo[indx].start = g_crashdump_data.uname; + dumpinfo[indx].size = + g_crashdump_data.uname_length; + } else if (!strncmp(dumpinfo[indx].name, + "CPU_INFO", strlen("CPU_INFO"))) { + dumpinfo[indx].start = + g_crashdump_data.cpu_context; + dumpinfo[indx].size = + CONFIG_CPU_CONTEXT_DUMP_SIZE; + } + return dumpinfo[indx].start; +} + +static int dump_wlan_segments(struct dumpinfo_t *dumpinfo, int indx) +{ + uint32_t memaddr; + struct qca_wdt_scm_tlv_msg *scm_tlv_msg = &tlv_msg; + unsigned char cur_type = QCA_WDT_LOG_DUMP_TYPE_WLAN_MOD; + unsigned int cur_size; + int ret_val; + struct st_tlv_info tlv_info; + uint32_t wlan_tlv_size; + char wlan_segment_name[32]; + + if(strncmp(dumpinfo[indx].name, "WLAN_MOD" ,strlen("WLAN_MOD"))) { + return CMD_RET_FAILURE; + } + + do { + ret_val = qca_wdt_scm_extract_tlv_info(scm_tlv_msg, + &cur_type, &cur_size); + if (!ret_val && cur_type == QCA_WDT_LOG_DUMP_TYPE_WLAN_MOD ) + ret_val = qca_wdt_scm_extract_tlv_data(scm_tlv_msg, + (unsigned char *)&tlv_info,cur_size); + memaddr = (uint32_t *)tlv_info.start; + wlan_tlv_size = tlv_info.size; + snprintf(wlan_segment_name, sizeof(wlan_segment_name), "%lx.BIN", memaddr); + ret_val = tftpdump (dumpinfo[indx].is_aligned_access, memaddr, wlan_tlv_size, wlan_segment_name); + udelay(10000); /* give some delay for server */ + if (ret_val == CMD_RET_FAILURE) + return CMD_RET_FAILURE; + }while (cur_type != QCA_WDT_LOG_DUMP_TYPE_INVALID); + return CMD_RET_SUCCESS; +}; + + +static int do_dumpqca_data(unsigned int dump_level) { char *serverip = NULL; /* dump to root of TFTP server if none specified */ @@ -129,7 +336,8 @@ static int do_dumpqca_data(void) char buf = 1; struct dumpinfo_t *dumpinfo = dumpinfo_n; int dump_entries = dump_entries_n; - + int dynamic_enum_count; + char wlan_segment_name[32]; serverip = getenv("serverip"); if (serverip != NULL) { printf("Using serverip from env %s\n", serverip); @@ -151,6 +359,8 @@ static int do_dumpqca_data(void) } for (indx = 0; indx < dump_entries; indx++) { + if (dump_level != dumpinfo[indx].dump_level) + continue; printf("\nProcessing %s:", dumpinfo[indx].name); if (dumpinfo[indx].is_redirected) { @@ -200,12 +410,27 @@ static int do_dumpqca_data(void) } else { - ret = tftpdump (dumpinfo[indx].is_aligned_access, memaddr, dumpinfo[indx].size, dumpinfo[indx].name); - if (ret == CMD_RET_FAILURE) - return CMD_RET_FAILURE; + if (dumpinfo[indx].dump_level == MINIMAL_DUMP ) + memaddr = dump_minimal(dumpinfo, indx); + if (dumpinfo[indx].size && memaddr) { + if(dumpinfo[indx].dump_level == MINIMAL_DUMP){ + snprintf(wlan_segment_name, sizeof(wlan_segment_name), "%lx.BIN", memaddr); + ret = tftpdump (dumpinfo[indx].is_aligned_access, memaddr, dumpinfo[indx].size, wlan_segment_name); + if (ret == CMD_RET_FAILURE) + return CMD_RET_FAILURE; + } + else{ + ret = tftpdump (dumpinfo[indx].is_aligned_access, memaddr, dumpinfo[indx].size, dumpinfo[indx].name); + if (ret == CMD_RET_FAILURE) + return CMD_RET_FAILURE; + } + } + else { + ret = dump_wlan_segments(dumpinfo, indx); + if (ret == CMD_RET_FAILURE) + return CMD_RET_FAILURE; + } } - - udelay(10000); /* give some delay for server */ } return CMD_RET_SUCCESS; } @@ -214,7 +439,7 @@ static int do_dumpqca_data(void) * Inovke the dump routine and in case of failure, do not stop unless the user * requested to stop */ -void dump_func(void) +void dump_func(unsigned int dump_level) { uint64_t etime; uint64_t ptime; @@ -250,7 +475,7 @@ void dump_func(void) printf("Ping failed\n"); goto reset; } - if (do_dumpqca_data() == CMD_RET_FAILURE) + if (do_dumpqca_data(dump_level) == CMD_RET_FAILURE) printf("Crashdump saving failed!\n"); goto reset; } else { @@ -258,7 +483,7 @@ void dump_func(void) printf("\nHit any key within 10s to stop dump activity..."); while (!tstc()) { /* while no incoming data */ if (get_timer_masked() >= etime) { - if (do_dumpqca_data() == CMD_RET_FAILURE) + if (do_dumpqca_data(dump_level) == CMD_RET_FAILURE) printf("Crashdump saving failed!\n"); break; } @@ -271,145 +496,6 @@ reset: run_command("reset", 0); } -/* Type in TLV for crashdump data type */ -enum { - QCA_WDT_LOG_DUMP_TYPE_INVALID, - QCA_WDT_LOG_DUMP_TYPE_UNAME, -}; - -/* This will be used for parsing the TLV data */ -struct qca_wdt_scm_tlv_msg { - unsigned char *msg_buffer; - unsigned char *cur_msg_buffer_pos; - unsigned int len; -}; - -/* Actual crashdump related data */ -struct qca_wdt_crashdump_data { - unsigned char uname[MAX_UNAME_SIZE]; - unsigned int uname_length; - unsigned char *cpu_context; -}; - -/* Context for NAND Flash memory */ -struct crashdump_flash_nand_cxt { - loff_t start_crashdump_offset; - loff_t cur_crashdump_offset; - int cur_page_data_len; - int write_size; - unsigned char temp_data[MAX_NAND_PAGE_SIZE]; -}; - -/* Context for SPI NOR Flash memory */ -struct crashdump_flash_spi_cxt { - loff_t start_crashdump_offset; - loff_t cur_crashdump_offset; -}; - -#ifdef CONFIG_QCA_MMC -/* Context for EMMC Flash memory */ -struct crashdump_flash_emmc_cxt { - loff_t start_crashdump_offset; - loff_t cur_crashdump_offset; - int cur_blk_data_len; - int write_size; - unsigned char temp_data[MAX_EMMC_BLK_LEN]; -}; -#endif - -static struct spi_flash *crashdump_spi_flash; -static struct crashdump_flash_nand_cxt crashdump_nand_cnxt; -static struct crashdump_flash_spi_cxt crashdump_flash_spi_cnxt; -#ifdef CONFIG_QCA_MMC -static struct mmc *mmc; -static struct crashdump_flash_emmc_cxt crashdump_emmc_cnxt; -#endif -static struct qca_wdt_crashdump_data g_crashdump_data; - -/* Extracts the type and length in TLV for current offset */ -static int qca_wdt_scm_extract_tlv_info( - struct qca_wdt_scm_tlv_msg *scm_tlv_msg, - unsigned char *type, - unsigned int *size) -{ - unsigned char *x = scm_tlv_msg->cur_msg_buffer_pos; - unsigned char *y = scm_tlv_msg->msg_buffer + - scm_tlv_msg->len; - - if ((x + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE) >= y) - return -EINVAL; - - *type = x[0]; - *size = x[1] | (x[2] << 8); - - return 0; -} - -/* Extracts the value from TLV for current offset */ -static int qca_wdt_scm_extract_tlv_data( - struct qca_wdt_scm_tlv_msg *scm_tlv_msg, - unsigned char *data, - unsigned int size) -{ - unsigned char *x = scm_tlv_msg->cur_msg_buffer_pos; - unsigned char *y = scm_tlv_msg->msg_buffer + scm_tlv_msg->len; - - if ((x + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE + size) >= y) - return -EINVAL; - - memcpy(data, x + 3, size); - - scm_tlv_msg->cur_msg_buffer_pos += - (size + QCA_WDT_SCM_TLV_TYPE_LEN_SIZE); - - return 0; -} - -/* -* This function parses the TLV message and stores the actual values -* in crashdump_data. For each TLV, It first determines the type and -* length, then it extracts the actual value and stores in the appropriate -* field in crashdump_data. -*/ -static int qca_wdt_extract_crashdump_data( - struct qca_wdt_scm_tlv_msg *scm_tlv_msg, - struct qca_wdt_crashdump_data *crashdump_data) -{ - unsigned char cur_type = QCA_WDT_LOG_DUMP_TYPE_INVALID; - unsigned int cur_size; - int ret_val; - - do { - ret_val = qca_wdt_scm_extract_tlv_info(scm_tlv_msg, - &cur_type, &cur_size); - - if (ret_val) - break; - - switch (cur_type) { - case QCA_WDT_LOG_DUMP_TYPE_UNAME: - crashdump_data->uname_length = cur_size; - ret_val = qca_wdt_scm_extract_tlv_data(scm_tlv_msg, - crashdump_data->uname, cur_size); - - break; - - case QCA_WDT_LOG_DUMP_TYPE_INVALID: - break; - - default: - ret_val = -EINVAL; - break; - } - - if (ret_val != 0) - break; - - } while (cur_type != QCA_WDT_LOG_DUMP_TYPE_INVALID); - - return ret_val; -} - /* * Init function for NAND flash writing. It intializes its own context * and erases the required sectors @@ -863,6 +949,8 @@ static int qca_wdt_write_crashdump_data( return ret; } + + /* * Function for collecting the crashdump data in flash. It extracts the * crashdump TLV(Type Length Value) data and CPU context information from @@ -870,11 +958,10 @@ static int qca_wdt_write_crashdump_data( * the type of boot flash memory and writes all these crashdump information * in provided offset in flash memory. */ -int do_dumpqca_flash_data(const char *offset) +int do_dumpqca_minimal_data(const char *offset) { unsigned char *kernel_crashdump_address = (unsigned char *) CONFIG_QCA_KERNEL_CRASHDUMP_ADDRESS; - struct qca_wdt_scm_tlv_msg tlv_msg; int flash_type; int ret_val; loff_t crashdump_offset; @@ -905,9 +992,14 @@ int do_dumpqca_flash_data(const char *offset) ret_val = qca_wdt_extract_crashdump_data(&tlv_msg, &g_crashdump_data); - if (!ret_val) - ret_val = qca_wdt_write_crashdump_data(&g_crashdump_data, - flash_type, crashdump_offset); + if (!ret_val) { + if (getenv("dump_to_flash")) { + ret_val = qca_wdt_write_crashdump_data(&g_crashdump_data, + flash_type, crashdump_offset); + } else { + dump_func(MINIMAL_DUMP); + } + } if (ret_val) { printf("crashdump data writing in flash failure\n"); diff --git a/board/qca/arm/ipq807x/ipq807x.c b/board/qca/arm/ipq807x/ipq807x.c index d5cbae3094..c071e44845 100644 --- a/board/qca/arm/ipq807x/ipq807x.c +++ b/board/qca/arm/ipq807x/ipq807x.c @@ -85,6 +85,11 @@ struct dumpinfo_t dumpinfo_n[] = { { "MSGRAM.BIN", 0x00060000, 0x00006000, 1 }, { "IMEM.BIN", 0x08600000, 0x00001000, 0 }, { "NSSIMEM.BIN", 0x08600658, 0x00060000, 0, 1, 0x2000 }, + { "UNAME.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "CPU_INFO.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "DMESG.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "PT.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "WLAN_MOD.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, }; int dump_entries_n = ARRAY_SIZE(dumpinfo_n); @@ -95,6 +100,11 @@ struct dumpinfo_t dumpinfo_s[] = { { "MSGRAM.BIN", 0x00060000, 0x00006000, 1 }, { "IMEM.BIN", 0x08600000, 0x00001000, 0 }, { "NSSIMEM.BIN", 0x08600658, 0x00060000, 0, 1, 0x2000 }, + { "UNAME.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "CPU_INFO.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "DMESG.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "PT.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, + { "WLAN_MOD.BIN", 0, 0, 0, 0, 0, MINIMAL_DUMP }, }; int dump_entries_s = ARRAY_SIZE(dumpinfo_s); diff --git a/common/autoboot.c b/common/autoboot.c index 08407a6ae0..36604f5a63 100644 --- a/common/autoboot.c +++ b/common/autoboot.c @@ -371,12 +371,14 @@ void autoboot_command(const char *s) if (apps_iscrashed()) { printf("Crashdump magic found, initializing dump activity..\n"); s = getenv("dump_to_flash"); - if (s) { - do_dumpqca_flash_data(s); /* write core dump data to flash */ - run_command("reset", 0); - } + if (!s) + s = getenv("dump_minimal"); + if (s) { + do_dumpqca_minimal_data(s); /* write core dump data to flash */ + run_command("reset", 0); + } else - dump_func(); + dump_func(FULL_DUMP); return; } #endif diff --git a/include/configs/ipq807x.h b/include/configs/ipq807x.h index c8d980f735..937bd68d40 100644 --- a/include/configs/ipq807x.h +++ b/include/configs/ipq807x.h @@ -321,7 +321,7 @@ extern loff_t board_env_size; #define CONFIG_QCA_KERNEL_CRASHDUMP_ADDRESS *((unsigned int *)0x08600658) #define CONFIG_CPU_CONTEXT_DUMP_SIZE 4096 -#define CONFIG_TLV_DUMP_SIZE 2048 +#define CONFIG_TLV_DUMP_SIZE 10240 /* L1 cache line size is 64 bytes, L2 cache line size is 128 bytes * Cache flush and invalidation based on L1 cache, so the cache line