mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2025-12-10 07:44:53 +01:00
board: qca: crashdump: add support save minidumps in nvmem
This patch enable the uboot to collec the minidump by parsing the TLVs exposed by the kernel and store it into the nvmem (Non volatile memory) either NAND / eMMC To enable this feature, setenv dump_minimal 1 setenv dump_to_nvmem "<partition_name>" Change-Id: I2f2ed2ad2e8506957288052edaf5d6290ae787b7 Signed-off-by: Ram Kumar D <quic_ramd@quicinc.com>
This commit is contained in:
parent
6187ef3200
commit
d7c6d8dd31
2 changed files with 293 additions and 20 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue