nand_write_skip_bad函式解析
阿新 • • 發佈:2021-01-06
/**
* nand_write_skip_bad:
*
* Write image to NAND flash.
* Blocks that are marked bad are skipped and the is written to the next
* block instead as long as the image is short enough to fit even after
* skipping the bad blocks. Due to bad blocks we may not be able to
* perform the requested write. In the case where the write would
* extend beyond the end of the NAND device, both length and actual (if
* not NULL) are set to 0. In the case where the write would extend
* beyond the limit we are passed, length is set to 0 and actual is set
* to the required length.
*
* @param nand NAND device
* @param offset offset in flash
* @param length buffer length
* @param actual set to size required to write length worth of
* buffer or 0 on error, if not NULL
* @param lim maximum size that actual may be in order to not
* exceed the buffer
* @param buffer buffer to read from
* @param flags flags modifying the behaviour of the write to NAND
* @return 0 in case of success
*/
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
size_t *actual, loff_t lim, u_char *buffer, int flags)
{
int rval = 0, blocksize;
size_t left_to_write = *length;
size_t used_for_write = 0;
u_char *p_buffer = buffer;
int need_skip;
if (actual)
*actual = 0;
blocksize = nand->erasesize;
/*
* nand_write() handles unaligned, partial page writes.
*
* We allow length to be unaligned, for convenience in
* using the $filesize variable.
*
* However, starting at an unaligned offset makes the
* semantics of bad block skipping ambiguous (really,
* you should only start a block skipping access at a
* partition boundary). So don't try to handle that.
*/
if ((offset & (nand->writesize - 1)) != 0) { //-- 頁不對齊,出錯誤返回
printf("Attempt to write non page-aligned data\n");
*length = 0;
return -EINVAL;
}
need_skip = check_skip_len(nand, offset, *length, &used_for_write);//-- 計算含壞塊後的寫總長度,用used_for_write返回
if (actual)
*actual = used_for_write;
if (need_skip < 0) {//-- 說明要寫的區域超過的裝置容量
printf("Attempt to write outside the flash area\n");
*length = 0;
return -EINVAL;
}
if (used_for_write > lim) {
puts("Size of write exceeds partition or device limit\n");
*length = 0;
return -EFBIG;
}
if (!need_skip && !(flags & WITH_DROP_FFS)) {//-- 沒有壞塊並且flag不是WITH_DROP_FFS引數,直接按length長度寫入
rval = nand_write(nand, offset, length, buffer);
if ((flags & WITH_WR_VERIFY) && !rval)
rval = nand_verify(nand, offset, *length, buffer);
if (rval == 0)
return 0;
*length = 0;
printf("NAND write to offset %llx failed %d\n",
offset, rval);
return rval;
}
while (left_to_write > 0) {
size_t block_offset = offset & (nand->erasesize - 1); //-- 獲取塊內偏移,例如一個page 2048個位元組,對於第2個page來說,在該塊內該值為4096
size_t write_size, truncated_write_size;
WATCHDOG_RESET();
//-- offset & ~(nand->erasesize - 1)算出來的值是要寫入的page所在的block的第一個page的第一個位元組。比如一個block有64個page,一個page有2048個位元組,如果要
//-- 要寫第10個block的第2個page,那麼該值為10 * 64 * 2048.此處應該就是壞塊標記,是按照該塊的第一個page的第一個位元組是否為0xff來判斷是否為壞塊。
if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) {//-- 跳過一個壞塊
printf("Skip bad block 0x%08llx\n",
offset & ~(nand->erasesize - 1));
offset += nand->erasesize - block_offset;
continue;
}
if (left_to_write < (blocksize - block_offset))
write_size = left_to_write;
else
write_size = blocksize - block_offset;
truncated_write_size = write_size;
#ifdef CONFIG_CMD_NAND_TRIMFFS
if (flags & WITH_DROP_FFS)
truncated_write_size = drop_ffs(nand, p_buffer,
&write_size);
#endif
rval = nand_write(nand, offset, &truncated_write_size,
p_buffer);
if ((flags & WITH_WR_VERIFY) && !rval)
rval = nand_verify(nand, offset,//-- 將寫入的資料再讀一遍驗證寫入是否正確
truncated_write_size, p_buffer);
offset += write_size;
p_buffer += write_size;
if (rval != 0) {
printf("NAND write to offset %llx failed %d\n",
offset, rval);
*length -= left_to_write;
return rval;
}
left_to_write -= write_size;
}
return 0;
}