diff --git a/board/qca/arm/common/cmd_bootqca.c b/board/qca/arm/common/cmd_bootqca.c index 61c623645d..b6a52c05b5 100644 --- a/board/qca/arm/common/cmd_bootqca.c +++ b/board/qca/arm/common/cmd_bootqca.c @@ -51,6 +51,7 @@ static qca_smem_flash_info_t *sfi = &qca_smem_flash_info; int ipq_fs_on_nand ; extern int nand_env_device; extern qca_mmc mmc_host; +extern void set_minidump_bootargs(void); #ifdef CONFIG_QCA_MMC static qca_mmc *host = &mmc_host; @@ -112,7 +113,7 @@ void __stack_chk_fail(void) static int update_bootargs(void *addr) { - char *fit_bootargs, *strings = getenv("bootargs"); + char *fit_bootargs, *strings; int len, ret = CMD_RET_SUCCESS; char * cmd_line = malloc(CONFIG_SYS_CBSIZE); if (!cmd_line) { @@ -120,6 +121,12 @@ static int update_bootargs(void *addr) return CMD_RET_FAILURE; } +#ifdef CONFIG_QCA_APPSBL_DLOAD + if (getenv("dump_to_nvmem")) + set_minidump_bootargs(); +#endif + + strings = getenv("bootargs"); memset(cmd_line, 0, CONFIG_SYS_CBSIZE); fit_bootargs = (char *)fdt_getprop(addr, 0, FIT_BOOTARGS_PROP, &len); if ((fit_bootargs != NULL) && len) { diff --git a/board/qca/arm/common/crashdump.c b/board/qca/arm/common/crashdump.c index d406db7a93..629c6f6a1b 100644 --- a/board/qca/arm/common/crashdump.c +++ b/board/qca/arm/common/crashdump.c @@ -141,6 +141,19 @@ struct memdump_hdr { uint32_t reserved[2]; }; +struct dump2nvmem_config { + int flash_type; + uint32_t offset; + uint32_t dump_off; + uint32_t size; + uint32_t blksize; +}; + +void *crashdump_cnxt; +int (*crashdump_flash_write)(void *cnxt, unsigned char *data, unsigned int size); +int (*crashdump_flash_write_init)(void *cnxt, loff_t offset, unsigned int total_size); +int (*crashdump_flash_write_deinit)(void *cnxt); + #ifdef CONFIG_MTD_DEVICE static struct crashdump_flash_nand_cxt crashdump_nand_cnxt; #endif @@ -158,6 +171,7 @@ struct qca_wdt_scm_tlv_msg tlv_msg ; static ulong dump2mem_addr_curr = 0, dump2mem_addr = 0; static uint32_t dumplist_entrymax = DEFAULT_MINIDUMP_LIST_ENTRY_MAX; static struct memdump_hdr dump2mem_hdr; +static struct dump2nvmem_config dump2nvmem_info; static struct memdumps_list_info *dumps_list = NULL; __weak int scm_set_boot_addr(bool enable_sec_core) @@ -198,7 +212,7 @@ static int dump_to_dst (int is_aligned_access, uint32_t memaddr, uint32_t size, unsigned int dump_level) { char runcmd[256]; - char *usb_dump = NULL, *dump2mem = NULL; + char *usb_dump = NULL, *dump2mem = NULL, *dump2nvmem = NULL; ulong is_usb_dump = 0; int ret = 0; @@ -207,6 +221,7 @@ static int dump_to_dst (int is_aligned_access, uint32_t memaddr, uint32_t size, return CMD_RET_SUCCESS; } + dump2nvmem = getenv("dump_to_nvmem"); dump2mem = getenv("dump_to_mem"); usb_dump = getenv("dump_to_usb"); if (usb_dump) { @@ -255,6 +270,38 @@ static int dump_to_dst (int is_aligned_access, uint32_t memaddr, uint32_t size, printf("Dumping %s @ 0x%lX \n", dumps_list[idx].name, dump2mem_addr_curr); dump2mem_addr_curr = roundup(dump2mem_addr_curr + size, ARCH_DMA_MINALIGN); + + } else if (dump2nvmem && (dump_level == MINIMAL_DUMP)) { + int idx = dump2mem_hdr.nos_dumps++; + + if (idx >= dumplist_entrymax) { + dumplist_entrymax += MINIDUMP_LIST_ENTRY_INC_ORDER; + dumps_list = realloc(dumps_list, + dumplist_entrymax * sizeof(struct memdumps_list_info)); + if (!dumps_list) { + printf("failed to do realloc the minidumps list entry table\n"); + return CMD_RET_FAILURE; + } + } + + strlcpy(dumps_list[idx].name, name, sizeof(dumps_list[idx].name)); + dumps_list[idx].offset = dump2mem_addr_curr; + dumps_list[idx].size = size; + + if (dump2mem_addr_curr + size > dump2nvmem_info.size) { + printf("Error: Not enough memory in %s partition to save dumps\n", dump2nvmem); + return CMD_RET_FAILURE; + } + + ret = crashdump_flash_write(crashdump_cnxt, (unsigned char *)memaddr, size); + if (ret) + return ret; + + printf("Writing %s in %s @ offset 0x%lx\n", dumps_list[idx].name, + dump2nvmem, dump2mem_addr_curr); + dump2mem_addr_curr += size; + + return CMD_RET_SUCCESS; } else { char *dumpdir; dumpdir = getenv("dumpdir"); @@ -533,6 +580,7 @@ static int do_dumpqca_data(unsigned int dump_level) char wlan_segment_name[32], runcmd[128], *s; char *usb_dump = NULL, *compress = NULL; char *dump2mem = NULL, *dump2mem_addr_s = NULL, *dump2mem_sz_s = NULL; + char *dump2nvmem = NULL; ulong is_usb_dump = 0, is_compress = 0, dump2mem_sz = 0; char temp[256]; @@ -572,6 +620,28 @@ static int do_dumpqca_data(unsigned int dump_level) sizeof(struct memdump_hdr), ARCH_DMA_MINALIGN); } + dump2nvmem = getenv("dump_to_nvmem"); + if (dump2nvmem && (dump_level == MINIMAL_DUMP)) { + snprintf(runcmd, sizeof(runcmd), "flasherase %s", dump2nvmem); + ret = run_command(runcmd, 0); + if (ret) + return ret; + + dump2mem_addr = dump2nvmem_info.offset; + dump2mem_hdr.magic1 = MINIDUMP_MAGIC1_COOKIE; + dump2mem_hdr.magic2 = MINIDUMP_MAGIC2_COOKIE; + dump2mem_hdr.nos_dumps = 0; + dump2mem_hdr.total_dump_sz = 0; + dump2mem_hdr.dumps_list_info_offset = 0; + dumps_list = malloc(dumplist_entrymax * sizeof(struct memdumps_list_info)); + dump2mem_addr_curr = dump2nvmem_info.blksize; + + ret = crashdump_flash_write_init(crashdump_cnxt, + dump2nvmem_info.offset + dump2nvmem_info.dump_off, 0); + if (ret) + return ret; + } + usb_dump = getenv("dump_to_usb"); if (usb_dump) { ret = str2long(usb_dump, &is_usb_dump); @@ -829,6 +899,44 @@ stop_dump: } } + if (dump2nvmem && (dump_level == MINIMAL_DUMP)) { + if (ret != CMD_RET_SUCCESS) + return ret; + + /* updating dump_list in flash at the end */ + ret = crashdump_flash_write(crashdump_cnxt, (unsigned char *)dumps_list, + dump2mem_hdr.nos_dumps * sizeof(struct memdumps_list_info)); + if (ret) + return ret; + + ret = crashdump_flash_write_deinit(crashdump_cnxt); + if (ret) + return ret; + + dump2mem_hdr.total_dump_sz = dump2mem_addr_curr + + (dump2mem_hdr.nos_dumps * sizeof(struct memdumps_list_info)); + dump2mem_hdr.dumps_list_info_offset = dump2mem_addr_curr; + + if (dump2mem_hdr.total_dump_sz > dump2nvmem_info.size) { + printf("Error: Not enough memory in %s partition to save dumps", dump2nvmem); + return CMD_RET_FAILURE; + } + + /* updating memdump_hdr in flash at the first block */ + ret = crashdump_flash_write_init(crashdump_cnxt, dump2mem_addr, 0); + if (ret) + return ret; + + ret = crashdump_flash_write(crashdump_cnxt, (unsigned char *)&dump2mem_hdr, + sizeof(struct memdump_hdr)); + if (ret) + return ret; + + ret = crashdump_flash_write_deinit(crashdump_cnxt); + if (ret) + return ret; + } + #if defined(CONFIG_USB_STORAGE) && defined(CONFIG_FS_FAT) if (is_usb_dump == 1) { mdelay(2000); @@ -1355,24 +1463,9 @@ int crashdump_emmc_flash_write_data(void *cnxt, } #endif -/* -* This function writes the crashdump data in flash memory. -* It has function pointers for init, deinit and writing. These -* function pointers are being initialized with respective flash -* memory writing routines. -*/ -static int qca_wdt_write_crashdump_data( - struct qca_wdt_crashdump_data *crashdump_data, - int flash_type, loff_t crashdump_offset) +static int qca_wdt_write_crashdump_configure(int flash_type) { int ret = 0; - void *crashdump_cnxt; - int (*crashdump_flash_write)(void *cnxt, unsigned char *data, - unsigned int size); - int (*crashdump_flash_write_init)(void *cnxt, loff_t offset, - unsigned int total_size); - int (*crashdump_flash_write_deinit)(void *cnxt); - unsigned int required_size; /* * Determine the flash type and initialize function pointer for flash @@ -1426,6 +1519,95 @@ static int qca_wdt_write_crashdump_data( return -EINVAL; } + return ret; +} + +void set_minidump_bootargs(void) +{ + char runcmd[128], *part_name = getenv("dump_to_nvmem"); + int flash_type = sfi->flash_type; + uint32_t * buf = NULL; + + switch (sfi->flash_type) { + case SMEM_BOOT_NAND_FLASH: + case SMEM_BOOT_QSPI_NAND_FLASH: + case SMEM_BOOT_MMC_FLASH: + flash_type = sfi->flash_type; + break; + + case SMEM_BOOT_SPI_FLASH: + if (get_which_flash_param(part_name)) + flash_type = SMEM_BOOT_QSPI_NAND_FLASH; + else + flash_type = SMEM_BOOT_MMC_FLASH; + break; + default: + goto retn; + } + + + if ((flash_type == SMEM_BOOT_NAND_FLASH) || + (flash_type == SMEM_BOOT_QSPI_NAND_FLASH)) { +#ifdef CONFIG_MTD_DEVICE + uint32_t offset, part_size, read_size = 64; + + if (getpart_offset_size(part_name, &offset, &part_size)) + goto retn; + + buf = malloc(read_size); + if (!buf) + goto retn; + + snprintf(runcmd, sizeof(runcmd), "nand read 0x%x 0x%x 0x%x", + (uint32_t)buf, offset, read_size); +#endif + } else { +#ifdef CONFIG_QCA_MMC + block_dev_desc_t *blk_dev = mmc_get_dev(0); + disk_partition_t disk_info; + + if (!blk_dev) + goto retn; + + if (get_partition_info_efi_by_name(blk_dev, part_name, + &disk_info)) + goto retn; + + buf = malloc(disk_info.blksz); + if (!buf) + goto retn; + + snprintf(runcmd, sizeof(runcmd), "mmc read 0x%x 0x%lx 0x1", + (uint32_t)buf, disk_info.start); +#endif + } + + if (run_command(runcmd, 0)) { + free(buf); + goto retn; + } + + if (buf && (buf[0] == MINIDUMP_MAGIC1_COOKIE) && + (buf[1] == MINIDUMP_MAGIC2_COOKIE)) + run_command("setenv bootargs ${bootargs} collect_minidump", 0); + +retn: + return; +} + +/* +* This function writes the crashdump data in flash memory. +* It has function pointers for init, deinit and writing. These +* function pointers are being initialized with respective flash +* memory writing routines. +*/ +static int qca_wdt_write_crashdump_data( + struct qca_wdt_crashdump_data *crashdump_data, + loff_t crashdump_offset) +{ + int ret = 0; + unsigned int required_size; + /* Start writing cpu context and uname in flash */ required_size = CONFIG_CPU_CONTEXT_DUMP_SIZE + crashdump_data->uname_length; @@ -1468,7 +1650,17 @@ int do_dumpqca_minimal_data(const char *offset) int flash_type; int ret_val; loff_t crashdump_offset; + char *dump_to_flash = getenv("dump_to_flash"); + char *dump_to_nvmem = NULL; + if (dump_to_flash) { + setenv("dump_to_nvmem", ""); + setenv("dump_to_mem", ""); + } else { + dump_to_nvmem = getenv("dump_to_nvmem"); + if (dump_to_nvmem) + setenv("dump_to_mem", ""); + } if (sfi->flash_type == SMEM_BOOT_NAND_FLASH) { flash_type = SMEM_BOOT_NAND_FLASH; @@ -1501,9 +1693,83 @@ int do_dumpqca_minimal_data(const char *offset) return ret_val; } - if (getenv("dump_to_flash")) { + if (dump_to_flash || dump_to_nvmem) + { + if (dump_to_nvmem) { + if (flash_type == SMEM_BOOT_SPI_FLASH) { + if (get_which_flash_param(dump_to_nvmem)) + flash_type = SMEM_BOOT_QSPI_NAND_FLASH; + else + flash_type = SMEM_BOOT_MMC_FLASH; + } + + dump2nvmem_info.flash_type = flash_type; + if ((flash_type == SMEM_BOOT_NAND_FLASH) || + (flash_type == SMEM_BOOT_QSPI_NAND_FLASH)) { +#ifdef CONFIG_MTD_DEVICE + uint32_t off, size, valid_start_off; + uint8_t valid_start_found = 0; + ret_val = getpart_offset_size(dump_to_nvmem, + &off, &size); + if (ret_val) { + printf("Error: %s Invalid partition\n", dump_to_nvmem); + return ret_val; + } + + dump2nvmem_info.offset = valid_start_off = off; + dump2nvmem_info.size = size; + dump2nvmem_info.blksize = nand_info[0].erasesize; + dump2nvmem_info.dump_off = nand_info[0].erasesize;; + for (; off < (dump2nvmem_info.offset + size); + off += nand_info[0].erasesize) { + if (nand_block_isbad(&nand_info[0], off)) { + dump2nvmem_info.size -= nand_info[0].erasesize; + } else if (!valid_start_found) { + valid_start_off = off; + valid_start_found = 1; + } + } + + if (!dump2nvmem_info.size) { + printf("Error: %s bad partition\n", dump_to_nvmem); + return -EIO; + } else + dump2nvmem_info.offset = valid_start_off; +#endif + } else { +#ifdef CONFIG_QCA_MMC + block_dev_desc_t *blk_dev = mmc_get_dev(0); + disk_partition_t disk_info; + + if (!blk_dev) { + printf("Error: %s Invalid partition\n", dump_to_nvmem); + return ret_val; + } + + ret_val = get_partition_info_efi_by_name(blk_dev, + dump_to_nvmem, &disk_info); + if (ret_val) { + printf("Error: %s Invalid partition\n", dump_to_nvmem); + return ret_val; + } + + dump2nvmem_info.offset = disk_info.start; + dump2nvmem_info.dump_off = 1; + dump2nvmem_info.blksize = disk_info.blksz; + dump2nvmem_info.size = disk_info.size * disk_info.blksz; +#endif + } + } + + ret_val = qca_wdt_write_crashdump_configure(flash_type); + if (ret_val) { + printf("crashdump configure flash failure\n"); + return ret_val; + } + } + + if (dump_to_flash) { ret_val = qca_wdt_write_crashdump_data(&g_crashdump_data, - flash_type, crashdump_offset); if (ret_val) { printf("crashdump data writing in flash failure\n");