1. 程式人生 > 其它 >nand_write_skip_bad函式解析

nand_write_skip_bad函式解析

技術標籤:#uboot原始碼分析核心驅動#ubuntu

/**
 * 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; }