aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRobert Jarzmik <robert.jarzmik@free.fr>2011-11-19 10:02:47 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-01-09 13:07:17 -0500
commit32a50b3a457fda9606fd0946eb77ba28a520cd7f (patch)
tree43df59205d0b08e3257249df581f3202d44c8d02 /drivers
parent34db8a5a72c5c5eb5d2811f237dcc9bf3c6425a9 (diff)
mtd: docg3: fix reading oob+data without correction
Fix the docg3 reads to be able to cope with all possible data buffer / oob buffer / file mode combinations from docg3_read_oob(). This especially ensures that raw reads do not use ECC corrections, and AUTOOOB and PLACEOOB do use ECC correction. The approach is to empty docg3_read() and make it a wrapper to docg3_read_oob(). As docg3_read_oob() handles all the funny cases (no data buffer but oob buffer, data buffer but no oob buffer, ...), docg3_read() is just a special use of docg3_read_oob(). Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr> Reviewed-by: Ivan Djelic <ivan.djelic@parrot.com> Reviewed-by: Mike Dunn <mikedunn@newsguy.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/devices/docg3.c194
1 files changed, 95 insertions, 99 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 5834e6e65d1c..1c2f54d23c7e 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -196,8 +196,8 @@ static int doc_reset_seq(struct docg3 *docg3)
196/** 196/**
197 * doc_read_data_area - Read data from data area 197 * doc_read_data_area - Read data from data area
198 * @docg3: the device 198 * @docg3: the device
199 * @buf: the buffer to fill in 199 * @buf: the buffer to fill in (might be NULL is dummy reads)
200 * @len: the lenght to read 200 * @len: the length to read
201 * @first: first time read, DOC_READADDRESS should be set 201 * @first: first time read, DOC_READADDRESS should be set
202 * 202 *
203 * Reads bytes from flash data. Handles the single byte / even bytes reads. 203 * Reads bytes from flash data. Handles the single byte / even bytes reads.
@@ -218,8 +218,10 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len,
218 dst16 = buf; 218 dst16 = buf;
219 for (i = 0; i < len4; i += 2) { 219 for (i = 0; i < len4; i += 2) {
220 data16 = doc_readw(docg3, DOC_IOSPACE_DATA); 220 data16 = doc_readw(docg3, DOC_IOSPACE_DATA);
221 *dst16 = data16; 221 if (dst16) {
222 dst16++; 222 *dst16 = data16;
223 dst16++;
224 }
223 } 225 }
224 226
225 if (cdr) { 227 if (cdr) {
@@ -229,8 +231,10 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len,
229 dst8 = (u8 *)dst16; 231 dst8 = (u8 *)dst16;
230 for (i = 0; i < cdr; i++) { 232 for (i = 0; i < cdr; i++) {
231 data8 = doc_readb(docg3, DOC_IOSPACE_DATA); 233 data8 = doc_readb(docg3, DOC_IOSPACE_DATA);
232 *dst8 = data8; 234 if (dst8) {
233 dst8++; 235 *dst8 = data8;
236 dst8++;
237 }
234 } 238 }
235 } 239 }
236} 240}
@@ -542,96 +546,109 @@ static void calc_block_sector(loff_t from, int *block0, int *block1, int *page,
542} 546}
543 547
544/** 548/**
545 * doc_read - Read bytes from flash 549 * doc_read_oob - Read out of band bytes from flash
546 * @mtd: the device 550 * @mtd: the device
547 * @from: the offset from first block and first page, in bytes, aligned on page 551 * @from: the offset from first block and first page, in bytes, aligned on page
548 * size 552 * size
549 * @len: the number of bytes to read (must be a multiple of 4) 553 * @ops: the mtd oob structure
550 * @retlen: the number of bytes actually read
551 * @buf: the filled in buffer
552 * 554 *
553 * Reads flash memory pages. This function does not read the OOB chunk, but only 555 * Reads flash memory OOB area of pages.
554 * the page data.
555 * 556 *
556 * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured 557 * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
557 */ 558 */
558static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, 559static int doc_read_oob(struct mtd_info *mtd, loff_t from,
559 size_t *retlen, u_char *buf) 560 struct mtd_oob_ops *ops)
560{ 561{
561 struct docg3 *docg3 = mtd->priv; 562 struct docg3 *docg3 = mtd->priv;
562 int block0, block1, page, readlen, ret, ofs = 0; 563 int block0, block1, page, ret, ofs = 0;
563 int syn[DOC_ECC_BCH_SIZE], eccconf1; 564 u8 *oobbuf = ops->oobbuf;
564 u8 oob[DOC_LAYOUT_OOB_SIZE]; 565 u8 *buf = ops->datbuf;
566 size_t len, ooblen, nbdata, nboob;
567 u8 calc_ecc[DOC_ECC_BCH_SIZE], eccconf1;
568
569 if (buf)
570 len = ops->len;
571 else
572 len = 0;
573 if (oobbuf)
574 ooblen = ops->ooblen;
575 else
576 ooblen = 0;
577
578 if (oobbuf && ops->mode == MTD_OPS_PLACE_OOB)
579 oobbuf += ops->ooboffs;
580
581 doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n",
582 from, ops->mode, buf, len, oobbuf, ooblen);
583 if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) ||
584 (from % DOC_LAYOUT_PAGE_SIZE))
585 return -EINVAL;
565 586
566 ret = -EINVAL; 587 ret = -EINVAL;
567 doc_dbg("doc_read(from=%lld, len=%zu, buf=%p)\n", from, len, buf); 588 calc_block_sector(from + len, &block0, &block1, &page, &ofs);
568 if (from % DOC_LAYOUT_PAGE_SIZE)
569 goto err;
570 if (len % 4)
571 goto err;
572 calc_block_sector(from, &block0, &block1, &page, &ofs);
573 if (block1 > docg3->max_block) 589 if (block1 > docg3->max_block)
574 goto err; 590 goto err;
575 591
576 *retlen = 0; 592 ops->oobretlen = 0;
593 ops->retlen = 0;
577 ret = 0; 594 ret = 0;
578 readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); 595 while (!ret && (len > 0 || ooblen > 0)) {
579 while (!ret && len > 0) { 596 calc_block_sector(from, &block0, &block1, &page, &ofs);
580 readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); 597 nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE);
598 nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
581 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); 599 ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
582 if (ret < 0) 600 if (ret < 0)
583 goto err; 601 goto err;
584 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); 602 ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES);
585 if (ret < 0) 603 if (ret < 0)
586 goto err_in_read; 604 goto err_in_read;
587 ret = doc_read_page_getbytes(docg3, readlen, buf, 1); 605 ret = doc_read_page_getbytes(docg3, nbdata, buf, 1);
588 if (ret < readlen) 606 if (ret < nbdata)
589 goto err_in_read; 607 goto err_in_read;
590 ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, 608 doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata,
591 oob, 0); 609 NULL, 0);
592 if (ret < DOC_LAYOUT_OOB_SIZE) 610 ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0);
611 if (ret < nboob)
593 goto err_in_read; 612 goto err_in_read;
613 doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob,
614 NULL, 0);
594 615
595 *retlen += readlen; 616 doc_get_hw_bch_syndroms(docg3, calc_ecc);
596 buf += readlen;
597 len -= readlen;
598
599 ofs ^= DOC_LAYOUT_PAGE_OOB_SIZE;
600 if (ofs == 0)
601 page += 2;
602 if (page > DOC_ADDR_PAGE_MASK) {
603 page = 0;
604 block0 += 2;
605 block1 += 2;
606 }
607
608 /*
609 * There should be a BCH bitstream fixing algorithm here ...
610 * By now, a page read failure is triggered by BCH error
611 */
612 doc_get_hw_bch_syndroms(docg3, syn);
613 eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); 617 eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1);
614 618
615 doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 619 if (nboob >= DOC_LAYOUT_OOB_SIZE) {
616 oob[0], oob[1], oob[2], oob[3], oob[4], 620 doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
617 oob[5], oob[6]); 621 oobbuf[0], oobbuf[1], oobbuf[2], oobbuf[3],
618 doc_dbg("OOB - HAMMING: %02x\n", oob[7]); 622 oobbuf[4], oobbuf[5], oobbuf[6]);
619 doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 623 doc_dbg("OOB - HAMMING: %02x\n", oobbuf[7]);
620 oob[8], oob[9], oob[10], oob[11], oob[12], 624 doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
621 oob[13], oob[14]); 625 oobbuf[8], oobbuf[9], oobbuf[10], oobbuf[11],
622 doc_dbg("OOB - UNUSED: %02x\n", oob[15]); 626 oobbuf[12], oobbuf[13], oobbuf[14]);
627 doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]);
628 }
623 doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); 629 doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1);
624 doc_dbg("ECC BCH syndrom: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 630 doc_dbg("ECC CALC_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
625 syn[0], syn[1], syn[2], syn[3], syn[4], syn[5], syn[6]); 631 calc_ecc[0], calc_ecc[1], calc_ecc[2],
632 calc_ecc[3], calc_ecc[4], calc_ecc[5],
633 calc_ecc[6]);
626 634
627 ret = -EBADMSG; 635 ret = -EBADMSG;
628 if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) { 636 if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) {
629 if (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) 637 if ((eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) &&
638 (eccconf1 & DOC_ECCCONF1_PAGE_IS_WRITTEN))
630 goto err_in_read; 639 goto err_in_read;
631 if (is_prot_seq_error(docg3)) 640 if (is_prot_seq_error(docg3))
632 goto err_in_read; 641 goto err_in_read;
633 } 642 }
643
634 doc_read_page_finish(docg3); 644 doc_read_page_finish(docg3);
645 ops->retlen += nbdata;
646 ops->oobretlen += nboob;
647 buf += nbdata;
648 oobbuf += nboob;
649 len -= nbdata;
650 ooblen -= nboob;
651 from += DOC_LAYOUT_PAGE_SIZE;
635 } 652 }
636 653
637 return 0; 654 return 0;
@@ -642,54 +659,33 @@ err:
642} 659}
643 660
644/** 661/**
645 * doc_read_oob - Read out of band bytes from flash 662 * doc_read - Read bytes from flash
646 * @mtd: the device 663 * @mtd: the device
647 * @from: the offset from first block and first page, in bytes, aligned on page 664 * @from: the offset from first block and first page, in bytes, aligned on page
648 * size 665 * size
649 * @ops: the mtd oob structure 666 * @len: the number of bytes to read (must be a multiple of 4)
667 * @retlen: the number of bytes actually read
668 * @buf: the filled in buffer
650 * 669 *
651 * Reads flash memory OOB area of pages. 670 * Reads flash memory pages. This function does not read the OOB chunk, but only
671 * the page data.
652 * 672 *
653 * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured 673 * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
654 */ 674 */
655static int doc_read_oob(struct mtd_info *mtd, loff_t from, 675static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
656 struct mtd_oob_ops *ops) 676 size_t *retlen, u_char *buf)
657{ 677{
658 struct docg3 *docg3 = mtd->priv; 678 struct mtd_oob_ops ops;
659 int block0, block1, page, ofs, ret; 679 size_t ret;
660 u8 *buf = ops->oobbuf;
661 size_t len = ops->ooblen;
662 680
663 doc_dbg("doc_read_oob(from=%lld, buf=%p, len=%zu)\n", from, buf, len); 681 memset(&ops, 0, sizeof(ops));
664 if (len != DOC_LAYOUT_OOB_SIZE) 682 ops.datbuf = buf;
665 return -EINVAL; 683 ops.len = len;
684 ops.mode = MTD_OPS_AUTO_OOB;
666 685
667 switch (ops->mode) { 686 ret = doc_read_oob(mtd, from, &ops);
668 case MTD_OPS_PLACE_OOB: 687 *retlen = ops.retlen;
669 buf += ops->ooboffs; 688 return ret;
670 break;
671 default:
672 break;
673 }
674
675 calc_block_sector(from, &block0, &block1, &page, &ofs);
676 if (block1 > docg3->max_block)
677 return -EINVAL;
678
679 ret = doc_read_page_prepare(docg3, block0, block1, page,
680 ofs + DOC_LAYOUT_PAGE_SIZE);
681 if (!ret)
682 ret = doc_read_page_ecc_init(docg3, DOC_LAYOUT_OOB_SIZE);
683 if (!ret)
684 ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE,
685 buf, 1);
686 doc_read_page_finish(docg3);
687
688 if (ret > 0)
689 ops->oobretlen = ret;
690 else
691 ops->oobretlen = 0;
692 return (ret > 0) ? 0 : ret;
693} 689}
694 690
695static int doc_reload_bbt(struct docg3 *docg3) 691static int doc_reload_bbt(struct docg3 *docg3)