ipq: Added nand bad block skipping to dump_to_flash feature

This change will skip the bad blocks offsets, if any while writing
into the nand flash duirng crash when dump_to_flash enabled. This
change also verifies whether the dump data is not overwritten into
the next partition.

Signed-off-by: Karthick Shanmugham <kartshan@codeaurora.org>
Change-Id: I0eec4c772a5f5efb3c17bfd1fd3d3d9a5ff85d1d
This commit is contained in:
Karthick Shanmugham 2020-09-09 20:54:00 +05:30
parent c1ece2b859
commit 434cc613fc
3 changed files with 153 additions and 23 deletions

View file

@ -585,6 +585,52 @@ unsigned int get_partition_table_offset(void)
return primary_mibib;
}
/*
* smem_getpart_from_offset - retreive partition start and size for given offset
* belongs to.
* @part_name: offset for which part start and size needed
* @start: location where the start offset is to be stored
* @size: location where the size is to be stored
*
* Returns 0 at success or -ENOENT otherwise.
*/
int smem_getpart_from_offset(uint32_t offset, uint32_t *start, uint32_t *size)
{
unsigned i;
qca_smem_flash_info_t *sfi = &qca_smem_flash_info;
struct smem_ptn *p;
uint32_t bsize;
for (i = 0; i < smem_ptable.len; i++) {
p = &smem_ptable.parts[i];
*start = p->start;
bsize = get_part_block_size(p, sfi);
if (p->size == (~0u)) {
/*
* Partition size is 'till end of device', calculate
* appropriately
*/
#ifdef CONFIG_CMD_NAND
*size = (nand_info[get_device_id_by_part(p)].size /
bsize) - p->start;
#else
*size = 0;
bsize = bsize;
#endif
} else {
*size = p->size;
}
*start = *start * bsize;
*size = *size * bsize;
if (*start <= offset && *start + *size > offset) {
return 0;
}
}
return -ENOENT;
}
/*
* smem_getpart - retreive partition start and size
* @part_name: partition name

View file

@ -61,6 +61,7 @@ int smem_get_boot_flash(uint32_t *flash_type,
uint32_t *flash_block_size,
uint32_t *flash_density);
int smem_getpart(char *name, uint32_t *start, uint32_t *size);
int smem_getpart_from_offset(uint32_t offset, uint32_t *start, uint32_t *size);
int getpart_offset_size(char *part_name, uint32_t *offset, uint32_t *size);
unsigned int smem_get_board_machtype(void);
uint32_t get_nand_block_size(uint8_t dev_id);

View file

@ -97,6 +97,8 @@ struct crashdump_flash_nand_cxt {
int cur_page_data_len;
int write_size;
unsigned char temp_data[MAX_NAND_PAGE_SIZE];
uint32_t part_start;
uint32_t part_size;
};
#ifdef CONFIG_QCA_SPI
@ -748,6 +750,93 @@ reset:
reset_board();
}
#ifdef CONFIG_MTD_DEVICE
/*
* NAND flash check and write. Before writing into the nand flash
* this function checks if the block is non-bad, and skips if bad. While
* skipping, there is also possiblity of crossing the partition and corrupting
* next partition with crashdump data. So this function also checks whether
* offset is within the partition, where the configured offset belongs.
*
* Returns 0 on succes and 1 otherwise
*/
static int check_and_write_crashdump_nand_flash(
struct crashdump_flash_nand_cxt *nand_cnxt,
nand_info_t *nand, unsigned char *data,
unsigned int req_size)
{
nand_erase_options_t nand_erase_options;
uint32_t part_start = nand_cnxt->part_start;
uint32_t part_end = nand_cnxt->part_start + nand_cnxt->part_size;
unsigned int remaining_len = req_size;
unsigned int data_offset = 0;
loff_t skipoff, skipoff_cmp, *offset;
int ret = 0;
static int first_erase = 1;
offset = &nand_cnxt->cur_crashdump_offset;
memset(&nand_erase_options, 0, sizeof(nand_erase_options));
nand_erase_options.length = nand->erasesize;
while (remaining_len)
{
skipoff = *offset - (*offset & (nand->erasesize - 1));
skipoff_cmp = skipoff;
for (; skipoff < part_end; skipoff += nand->erasesize) {
if (nand_block_isbad(nand, skipoff)) {
printf("Skipping bad block at 0x%llx\n", skipoff);
continue;
}
else
break;
}
if (skipoff_cmp != skipoff)
*offset = skipoff;
if(part_start > *offset || ((*offset + remaining_len) >= part_end)) {
printf("Failure: Attempt to write in next partition\n");
return 1;
}
if((*offset & (nand->erasesize - 1)) == 0 || first_erase){
nand_erase_options.offset = *offset;
ret = nand_erase_opts(&nand_info[0],
&nand_erase_options);
if (ret)
return ret;
first_erase = 0;
}
if( remaining_len > nand->erasesize) {
ret = nand_write(nand, *offset, &nand->erasesize,
data + data_offset);
if (ret)
return ret;
remaining_len -= nand->erasesize;
*offset += nand->erasesize;
data_offset += nand->erasesize;
}
else {
ret = nand_write(nand, *offset, &remaining_len,
data + data_offset);
*offset += remaining_len;
remaining_len = 0;
}
}
return ret;
}
/*
* Init function for NAND flash writing. It intializes its own context
* and erases the required sectors
@ -755,10 +844,14 @@ reset:
int init_crashdump_nand_flash_write(void *cnxt, loff_t offset,
unsigned int total_size)
{
nand_erase_options_t nand_erase_options;
struct crashdump_flash_nand_cxt *nand_cnxt = cnxt;
int ret;
ret = smem_getpart_from_offset(offset, &nand_cnxt->part_start,
&nand_cnxt->part_size);
if (ret)
return ret;
nand_cnxt->start_crashdump_offset = offset;
nand_cnxt->cur_crashdump_offset = offset;
nand_cnxt->cur_page_data_len = 0;
@ -769,16 +862,6 @@ int init_crashdump_nand_flash_write(void *cnxt, loff_t offset,
return -ENOMEM;
}
memset(&nand_erase_options, 0, sizeof(nand_erase_options));
nand_erase_options.length = total_size;
nand_erase_options.offset = offset;
ret = nand_erase_opts(&nand_info[0],
&nand_erase_options);
if (ret)
return ret;
return 0;
}
@ -803,9 +886,11 @@ int deinit_crashdump_nand_flash_write(void *cnxt)
0xFF, remaining_bytes);
cur_nand_write_len = nand_cnxt->write_size;
ret_val = nand_write(&nand_info[0],
nand_cnxt->cur_crashdump_offset,
&cur_nand_write_len, nand_cnxt->temp_data);
ret_val = check_and_write_crashdump_nand_flash(nand_cnxt,
&nand_info[0], nand_cnxt->temp_data,
cur_nand_write_len);
}
return ret_val;
@ -853,15 +938,14 @@ int crashdump_nand_flash_write_data(void *cnxt,
memcpy(nand_cnxt->temp_data + nand_cnxt->cur_page_data_len, data,
remaining_len_cur_page);
ret_val = nand_write(&nand_info[0], nand_cnxt->cur_crashdump_offset,
&cur_nand_write_len,
nand_cnxt->temp_data);
ret_val = check_and_write_crashdump_nand_flash(nand_cnxt,
&nand_info[0], nand_cnxt->temp_data,
cur_nand_write_len);
if (ret_val)
return ret_val;
cur_data_pos += remaining_len_cur_page;
nand_cnxt->cur_crashdump_offset += cur_nand_write_len;
/*
* Calculate the write length in multiple of page length and do the nand
@ -871,17 +955,16 @@ int crashdump_nand_flash_write_data(void *cnxt,
nand_cnxt->write_size) * nand_cnxt->write_size;
if (cur_nand_write_len > 0) {
ret_val = nand_write(&nand_info[0],
nand_cnxt->cur_crashdump_offset,
&cur_nand_write_len,
cur_data_pos);
ret_val = check_and_write_crashdump_nand_flash(nand_cnxt,
&nand_info[0], cur_data_pos,
cur_nand_write_len);
if (ret_val)
return ret_val;
}
cur_data_pos += cur_nand_write_len;
nand_cnxt->cur_crashdump_offset += cur_nand_write_len;
/* Store the remaining data in temp data */
remaining_bytes = data + size - cur_data_pos;