@@ -632,7 +632,7 @@ static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
writel(ctl, nfc->regs + NFC_REG_CTL);
}
-static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
+static int sunxi_nfc_read_buf(struct nand_chip *nand, u8 *buf, int len)
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
@@ -648,7 +648,7 @@ static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
- break;
+ return ret;
writel(cnt, nfc->regs + NFC_REG_CNT);
tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD;
@@ -660,17 +660,19 @@ static void sunxi_nfc_read_buf(struct nand_chip *nand, uint8_t *buf, int len)
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
if (ret)
- break;
+ return ret;
if (buf)
memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE,
cnt);
offs += cnt;
}
+
+ return 0;
}
-static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
- int len)
+static int sunxi_nfc_write_buf(struct nand_chip *nand, const u8 *buf,
+ int len)
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
@@ -686,7 +688,7 @@ static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
- break;
+ return ret;
writel(cnt, nfc->regs + NFC_REG_CNT);
memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt);
@@ -700,10 +702,12 @@ static void sunxi_nfc_write_buf(struct nand_chip *nand, const uint8_t *buf,
ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0);
if (ret)
- break;
+ return ret;
offs += cnt;
}
+
+ return 0;
}
/* These seed values have been extracted from Allwinner's BSP */
@@ -853,23 +857,31 @@ static void sunxi_nfc_randomize_bbm(struct nand_chip *nand, int page, u8 *bbm)
bbm[1] ^= sunxi_nfc_randomizer_step(state, 8);
}
-static void sunxi_nfc_randomizer_write_buf(struct nand_chip *nand,
- const uint8_t *buf, int len,
- bool ecc, int page)
+static int sunxi_nfc_randomizer_write_buf(struct nand_chip *nand,
+ const u8 *buf, int len,
+ bool ecc, int page)
{
+ int ret;
+
sunxi_nfc_randomizer_config(nand, page, ecc);
sunxi_nfc_randomizer_enable(nand);
- sunxi_nfc_write_buf(nand, buf, len);
+ ret = sunxi_nfc_write_buf(nand, buf, len);
sunxi_nfc_randomizer_disable(nand);
+
+ return ret;
}
-static void sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, uint8_t *buf,
- int len, bool ecc, int page)
+static int sunxi_nfc_randomizer_read_buf(struct nand_chip *nand, u8 *buf,
+ int len, bool ecc, int page)
{
+ int ret;
+
sunxi_nfc_randomizer_config(nand, page, ecc);
sunxi_nfc_randomizer_enable(nand);
- sunxi_nfc_read_buf(nand, buf, len);
+ ret = sunxi_nfc_read_buf(nand, buf, len);
sunxi_nfc_randomizer_disable(nand);
+
+ return ret;
}
static void sunxi_nfc_hw_ecc_enable(struct nand_chip *nand)
@@ -1140,17 +1152,25 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
u32 pattern_found;
bool bbm = !step;
bool erased;
- int ret;
+ int ret, bitflips;
/* From the controller point of view, we are at step 0 */
const int nfc_step = 0;
- if (*cur_off != data_off)
- nand_change_read_column_op(nand, data_off, NULL, 0, false);
+ if (*cur_off != data_off) {
+ ret = nand_change_read_column_op(nand, data_off, NULL, 0, false);
+ if (ret)
+ return ret;
+ }
- sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page);
+ ret = sunxi_nfc_randomizer_read_buf(nand, NULL, ecc->size, false, page);
+ if (ret)
+ return ret;
- if (data_off + ecc->size != oob_off)
- nand_change_read_column_op(nand, oob_off, NULL, 0, false);
+ if (data_off + ecc->size != oob_off) {
+ ret = nand_change_read_column_op(nand, oob_off, NULL, 0, false);
+ if (ret)
+ return ret;
+ }
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
@@ -1172,13 +1192,13 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
pattern_found = readl(nfc->regs + nfc->caps->reg_pat_found);
pattern_found = field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found);
- ret = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL,
- nfc_step, readl(nfc->regs + NFC_REG_ECC_ST),
- pattern_found, user_data_sz, &erased);
+ bitflips = sunxi_nfc_hw_ecc_correct(nand, data, oob_required ? oob : NULL,
+ nfc_step, readl(nfc->regs + NFC_REG_ECC_ST),
+ pattern_found, user_data_sz, &erased);
if (erased)
return 1;
- if (ret < 0) {
+ if (bitflips < 0) {
if (!(nand->options & NAND_NEED_SCRAMBLING))
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE,
ecc->size);
@@ -1190,17 +1210,22 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct nand_chip *nand,
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
if (oob_required) {
- nand_change_read_column_op(nand, oob_off, NULL, 0,
- false);
- sunxi_nfc_randomizer_read_buf(nand, oob, ecc->bytes + user_data_sz,
- true, page);
+ ret = nand_change_read_column_op(nand, oob_off, NULL, 0,
+ false);
+ if (ret)
+ return ret;
+ ret = sunxi_nfc_randomizer_read_buf(nand, oob,
+ ecc->bytes + user_data_sz,
+ true, page);
+ if (ret)
+ return ret;
sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, nfc_step,
bbm, page, user_data_sz);
}
}
- sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, ret);
+ sunxi_nfc_hw_ecc_update_stats(nand, max_bitflips, bitflips);
return 0;
}
@@ -1233,31 +1258,39 @@ static int sunxi_get_ecc_offset(struct sunxi_nand_chip *sunxi_nand,
sunxi_nfc_user_data_sz(sunxi_nand, step);
}
-static void sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand,
- u8 *oob, int *cur_off,
- bool randomize, int page)
+static int sunxi_nfc_hw_ecc_read_extra_oob(struct nand_chip *nand,
+ u8 *oob, int *cur_off,
+ bool randomize, int page)
{
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct mtd_info *mtd = nand_to_mtd(nand);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps);
int len = mtd->oobsize - offset;
+ int ret;
if (len <= 0)
- return;
+ return 0;
- if (!cur_off || *cur_off != (offset + mtd->writesize))
- nand_change_read_column_op(nand, mtd->writesize + offset,
- NULL, 0, false);
+ if (!cur_off || *cur_off != (offset + mtd->writesize)) {
+ ret = nand_change_read_column_op(nand, mtd->writesize + offset,
+ NULL, 0, false);
+ if (ret)
+ return ret;
+ }
if (!randomize)
- sunxi_nfc_read_buf(nand, oob + offset, len);
+ ret = sunxi_nfc_read_buf(nand, oob + offset, len);
else
- sunxi_nfc_randomizer_read_buf(nand, oob + offset, len,
- false, page);
+ ret = sunxi_nfc_randomizer_read_buf(nand, oob + offset, len,
+ false, page);
+ if (ret)
+ return ret;
if (cur_off)
*cur_off = mtd->oobsize + mtd->writesize;
+
+ return 0;
}
static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf,
@@ -1328,21 +1361,24 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
u8 *data = buf + data_off;
u8 *oob = nand->oob_poi + oob_off;
bool erased;
+ int bitflips;
- ret = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL,
- oob_required ? oob : NULL,
- i, status, pattern_found,
- user_data_sz, &erased);
+ bitflips = sunxi_nfc_hw_ecc_correct(nand, randomized ? data : NULL,
+ oob_required ? oob : NULL,
+ i, status, pattern_found,
+ user_data_sz, &erased);
/* ECC errors are handled in the second loop. */
- if (ret < 0)
+ if (bitflips < 0)
continue;
if (oob_required && !erased) {
/* TODO: use DMA to retrieve OOB */
- nand_change_read_column_op(nand,
- mtd->writesize + oob_off,
- oob, ecc->bytes + user_data_sz, false);
+ ret = nand_change_read_column_op(nand, mtd->writesize + oob_off,
+ oob, ecc->bytes + user_data_sz,
+ false);
+ if (ret)
+ goto err_stats;
sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, i, !i,
page, user_data_sz);
@@ -1351,7 +1387,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
if (erased)
raw_mode = 1;
- sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, ret);
+ sunxi_nfc_hw_ecc_update_stats(nand, &max_bitflips, bitflips);
}
if (status & NFC_ECC_ERR_MSK(nfc)) {
@@ -1369,23 +1405,27 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
mtd->writesize + oob_off,
user_data_sz,
&max_bitflips);
- if (ret < 0) {
- /* The caller retries the whole read in PIO mode. */
- mtd->ecc_stats.corrected = corrected;
- mtd->ecc_stats.failed = failed;
- return ret;
- }
+ if (ret < 0)
+ goto err_stats;
if (ret)
raw_mode = 1;
}
}
- if (oob_required)
- sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi,
- NULL, !raw_mode,
- page);
+ if (oob_required) {
+ ret = sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi,
+ NULL, !raw_mode, page);
+ if (ret)
+ goto err_stats;
+ }
return max_bitflips;
+
+err_stats:
+ /* The caller retries the whole read in PIO mode. */
+ mtd->ecc_stats.corrected = corrected;
+ mtd->ecc_stats.failed = failed;
+ return ret;
}
static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand,
@@ -1403,13 +1443,21 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand,
/* From the controller point of view, we are at step 0 */
const int nfc_step = 0;
- if (data_off != *cur_off)
- nand_change_write_column_op(nand, data_off, NULL, 0, false);
+ if (data_off != *cur_off) {
+ ret = nand_change_write_column_op(nand, data_off, NULL, 0, false);
+ if (ret)
+ return ret;
+ }
- sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page);
+ ret = sunxi_nfc_randomizer_write_buf(nand, data, ecc->size, false, page);
+ if (ret)
+ return ret;
- if (data_off + ecc->size != oob_off)
- nand_change_write_column_op(nand, oob_off, NULL, 0, false);
+ if (data_off + ecc->size != oob_off) {
+ ret = nand_change_write_column_op(nand, oob_off, NULL, 0, false);
+ if (ret)
+ return ret;
+ }
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
if (ret)
@@ -1435,27 +1483,35 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct nand_chip *nand,
return 0;
}
-static void sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand,
- u8 *oob, int *cur_off,
- int page)
+static int sunxi_nfc_hw_ecc_write_extra_oob(struct nand_chip *nand,
+ u8 *oob, int *cur_off,
+ int page)
{
struct mtd_info *mtd = nand_to_mtd(nand);
struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps);
int len = mtd->oobsize - offset;
+ int ret;
if (len <= 0)
- return;
+ return 0;
- if (!cur_off || *cur_off != offset)
- nand_change_write_column_op(nand, offset + mtd->writesize,
- NULL, 0, false);
+ if (!cur_off || *cur_off != offset) {
+ ret = nand_change_write_column_op(nand, offset + mtd->writesize,
+ NULL, 0, false);
+ if (ret)
+ return ret;
+ }
- sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page);
+ ret = sunxi_nfc_randomizer_write_buf(nand, oob + offset, len, false, page);
+ if (ret)
+ return ret;
if (cur_off)
*cur_off = mtd->oobsize + mtd->writesize;
+
+ return 0;
}
static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf,
@@ -1494,9 +1550,12 @@ static int sunxi_nfc_hw_ecc_read_page(struct nand_chip *nand, uint8_t *buf,
raw_mode = true;
}
- if (oob_required)
- sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off,
- !raw_mode, page);
+ if (oob_required) {
+ ret = sunxi_nfc_hw_ecc_read_extra_oob(nand, nand->oob_poi, &cur_off,
+ !raw_mode, page);
+ if (ret)
+ goto out;
+ }
ret = max_bitflips;
out:
@@ -1623,8 +1682,8 @@ static int sunxi_nfc_hw_ecc_write_page(struct nand_chip *nand,
}
if (oob_required || (nand->options & NAND_NEED_SCRAMBLING))
- sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
- &cur_off, page);
+ ret = sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
+ &cur_off, page);
out:
sunxi_nfc_hw_ecc_disable(nand);
@@ -1747,10 +1806,13 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct nand_chip *nand,
if (ret)
return ret;
- if (oob_required || (nand->options & NAND_NEED_SCRAMBLING))
+ if (oob_required || (nand->options & NAND_NEED_SCRAMBLING)) {
/* TODO: use DMA to transfer extra OOB bytes ? */
- sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
- NULL, page);
+ ret = sunxi_nfc_hw_ecc_write_extra_oob(nand, nand->oob_poi,
+ NULL, page);
+ if (ret)
+ return ret;
+ }
return nand_prog_page_end_op(nand);