12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295 |
- From a95cc309cf74eed3fc457dec3dcc44d9bf79e0e6 Mon Sep 17 00:00:00 2001
- From: Boris BREZILLON <boris.brezillon@free-electrons.com>
- Date: Mon, 28 Jul 2014 15:01:15 +0200
- Subject: [PATCH] mtd: nand: Add support for NAND partitions
- Add support for NAND partitions, and indirectly for per partition ECC
- config, and also per partiton random seed support for the upcoming
- randomizer support.
- This is necessary to be able to use different ECC / randomizer settings for
- the parts of the NAND which are read directly by a bootrom (which has a
- fixed ECC / random seed setting) and the generic data part of the NAND for
- which we often want a stronger ECC and / or random seed.
- Provide helper functions to add/delete/allocate nand partitions.
- NAND core code now make use of the partition specific nand_ecc_ctrl struct
- (if available) when doing read/write operations.
- Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
- Signed-off-by: Hans de Goede <hdegoede@redhat.com>
- ---
- drivers/mtd/nand/Kconfig | 4 +
- drivers/mtd/nand/Makefile | 2 +
- drivers/mtd/nand/nand_base.c | 712 +++++++++++++++++++++++++++++++++++--------
- drivers/mtd/nand/nand_bch.c | 16 +-
- drivers/mtd/nand/nand_ecc.c | 4 +-
- include/linux/mtd/nand.h | 38 +++
- 6 files changed, 635 insertions(+), 141 deletions(-)
- --- a/drivers/mtd/nand/Kconfig
- +++ b/drivers/mtd/nand/Kconfig
- @@ -22,6 +22,10 @@ menuconfig MTD_NAND
-
- if MTD_NAND
-
- +config MTD_OF_NAND_PARTS
- + tristate
- + default n
- +
- config MTD_NAND_BCH
- tristate
- select BCH
- --- a/drivers/mtd/nand/Makefile
- +++ b/drivers/mtd/nand/Makefile
- @@ -53,4 +53,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) +=
- obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
- obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
-
- +obj-$(CONFIG_MTD_OF_NAND_PARTS) += ofnandpart.o
- +
- nand-objs := nand_base.o nand_bbt.o nand_timings.o
- --- a/drivers/mtd/nand/nand_base.c
- +++ b/drivers/mtd/nand/nand_base.c
- @@ -1134,26 +1134,26 @@ static int nand_read_page_raw_syndrome(s
- struct nand_chip *chip, uint8_t *buf,
- int oob_required, int page)
- {
- - int eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- + int eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- uint8_t *oob = chip->oob_poi;
- int steps, size;
-
- - for (steps = chip->ecc.steps; steps > 0; steps--) {
- + for (steps = chip->cur_ecc->steps; steps > 0; steps--) {
- chip->read_buf(mtd, buf, eccsize);
- buf += eccsize;
-
- - if (chip->ecc.prepad) {
- - chip->read_buf(mtd, oob, chip->ecc.prepad);
- - oob += chip->ecc.prepad;
- + if (chip->cur_ecc->prepad) {
- + chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
- + oob += chip->cur_ecc->prepad;
- }
-
- chip->read_buf(mtd, oob, eccbytes);
- oob += eccbytes;
-
- - if (chip->ecc.postpad) {
- - chip->read_buf(mtd, oob, chip->ecc.postpad);
- - oob += chip->ecc.postpad;
- + if (chip->cur_ecc->postpad) {
- + chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
- + oob += chip->cur_ecc->postpad;
- }
- }
-
- @@ -1175,30 +1175,31 @@ static int nand_read_page_raw_syndrome(s
- static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- uint8_t *ecc_code = chip->buffers->ecccode;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
- unsigned int max_bitflips = 0;
-
- - chip->ecc.read_page_raw(mtd, chip, buf, 1, page);
- + chip->cur_ecc->read_page_raw(mtd, chip, buf, 1, page);
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- - chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- + chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
-
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
- - eccsteps = chip->ecc.steps;
- + eccsteps = chip->cur_ecc->steps;
- p = buf;
-
- for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- + stat = chip->cur_ecc->correct(mtd, p, &ecc_code[i],
- + &ecc_calc[i]);
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- @@ -1223,7 +1224,7 @@ static int nand_read_subpage(struct mtd_
- int page)
- {
- int start_step, end_step, num_steps;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
- uint8_t *p;
- int data_col_addr, i, gaps = 0;
- int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
- @@ -1232,16 +1233,16 @@ static int nand_read_subpage(struct mtd_
- unsigned int max_bitflips = 0;
-
- /* Column address within the page aligned to ECC size (256bytes) */
- - start_step = data_offs / chip->ecc.size;
- - end_step = (data_offs + readlen - 1) / chip->ecc.size;
- + start_step = data_offs / chip->cur_ecc->size;
- + end_step = (data_offs + readlen - 1) / chip->cur_ecc->size;
- num_steps = end_step - start_step + 1;
- - index = start_step * chip->ecc.bytes;
- + index = start_step * chip->cur_ecc->bytes;
-
- /* Data size aligned to ECC ecc.size */
- - datafrag_len = num_steps * chip->ecc.size;
- - eccfrag_len = num_steps * chip->ecc.bytes;
- + datafrag_len = num_steps * chip->cur_ecc->size;
- + eccfrag_len = num_steps * chip->cur_ecc->bytes;
-
- - data_col_addr = start_step * chip->ecc.size;
- + data_col_addr = start_step * chip->cur_ecc->size;
- /* If we read not a page aligned data */
- if (data_col_addr != 0)
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
- @@ -1250,8 +1251,9 @@ static int nand_read_subpage(struct mtd_
- chip->read_buf(mtd, p, datafrag_len);
-
- /* Calculate ECC */
- - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)
- - chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);
- + for (i = 0; i < eccfrag_len;
- + i += chip->cur_ecc->bytes, p += chip->cur_ecc->size)
- + chip->cur_ecc->calculate(mtd, p, &chip->buffers->ecccalc[i]);
-
- /*
- * The performance is faster if we position offsets according to
- @@ -1275,7 +1277,8 @@ static int nand_read_subpage(struct mtd_
- aligned_len = eccfrag_len;
- if (eccpos[index] & (busw - 1))
- aligned_len++;
- - if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
- + if (eccpos[index + (num_steps * chip->cur_ecc->bytes)] &
- + (busw - 1))
- aligned_len++;
-
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
- @@ -1287,11 +1290,13 @@ static int nand_read_subpage(struct mtd_
- chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
-
- p = bufpoi + data_col_addr;
- - for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
- + for (i = 0; i < eccfrag_len;
- + i += chip->cur_ecc->bytes, p += chip->cur_ecc->size) {
- int stat;
-
- - stat = chip->ecc.correct(mtd, p,
- - &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
- + stat = chip->cur_ecc->correct(mtd, p,
- + &chip->buffers->ecccode[i],
- + &chip->buffers->ecccalc[i]);
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- @@ -1315,32 +1320,33 @@ static int nand_read_subpage(struct mtd_
- static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- uint8_t *ecc_code = chip->buffers->ecccode;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
- unsigned int max_bitflips = 0;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- - chip->ecc.hwctl(mtd, NAND_ECC_READ);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
- - chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- + chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
- }
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
- - eccsteps = chip->ecc.steps;
- + eccsteps = chip->cur_ecc->steps;
- p = buf;
-
- for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- - stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- + stat = chip->cur_ecc->correct(mtd, p, &ecc_code[i],
- + &ecc_calc[i]);
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- @@ -1368,12 +1374,12 @@ static int nand_read_page_hwecc(struct m
- static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *p = buf;
- uint8_t *ecc_code = chip->buffers->ecccode;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- unsigned int max_bitflips = 0;
-
- @@ -1382,17 +1388,17 @@ static int nand_read_page_hwecc_oob_firs
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- - chip->ecc.hwctl(mtd, NAND_ECC_READ);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
- - chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- + chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
-
- - stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
- + stat = chip->cur_ecc->correct(mtd, p, &ecc_code[i], NULL);
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- } else {
- @@ -1417,9 +1423,9 @@ static int nand_read_page_hwecc_oob_firs
- static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int oob_required, int page)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *p = buf;
- uint8_t *oob = chip->oob_poi;
- unsigned int max_bitflips = 0;
- @@ -1427,17 +1433,17 @@ static int nand_read_page_syndrome(struc
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- - chip->ecc.hwctl(mtd, NAND_ECC_READ);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
-
- - if (chip->ecc.prepad) {
- - chip->read_buf(mtd, oob, chip->ecc.prepad);
- - oob += chip->ecc.prepad;
- + if (chip->cur_ecc->prepad) {
- + chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
- + oob += chip->cur_ecc->prepad;
- }
-
- - chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_READSYN);
- chip->read_buf(mtd, oob, eccbytes);
- - stat = chip->ecc.correct(mtd, p, oob, NULL);
- + stat = chip->cur_ecc->correct(mtd, p, oob, NULL);
-
- if (stat < 0) {
- mtd->ecc_stats.failed++;
- @@ -1448,9 +1454,9 @@ static int nand_read_page_syndrome(struc
-
- oob += eccbytes;
-
- - if (chip->ecc.postpad) {
- - chip->read_buf(mtd, oob, chip->ecc.postpad);
- - oob += chip->ecc.postpad;
- + if (chip->cur_ecc->postpad) {
- + chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
- + oob += chip->cur_ecc->postpad;
- }
- }
-
- @@ -1480,7 +1486,7 @@ static uint8_t *nand_transfer_oob(struct
- return oob + len;
-
- case MTD_OPS_AUTO_OOB: {
- - struct nand_oobfree *free = chip->ecc.layout->oobfree;
- + struct nand_oobfree *free = chip->cur_ecc->layout->oobfree;
- uint32_t boffs = 0, roffs = ops->ooboffs;
- size_t bytes = 0;
-
- @@ -1600,17 +1606,21 @@ read_retry:
- * the read methods return max bitflips per ecc step.
- */
- if (unlikely(ops->mode == MTD_OPS_RAW))
- - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
- - oob_required,
- - page);
- + ret = chip->cur_ecc->read_page_raw(mtd, chip,
- + bufpoi,
- + oob_required,
- + page);
- else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
- !oob)
- - ret = chip->ecc.read_subpage(mtd, chip,
- - col, bytes, bufpoi,
- - page);
- + ret = chip->cur_ecc->read_subpage(mtd, chip,
- + col, bytes,
- + bufpoi,
- + page);
- else
- - ret = chip->ecc.read_page(mtd, chip, bufpoi,
- - oob_required, page);
- + ret = chip->cur_ecc->read_page(mtd, chip,
- + bufpoi,
- + oob_required,
- + page);
- if (ret < 0) {
- if (use_bufpoi)
- /* Invalidate page cache */
- @@ -1746,6 +1756,39 @@ static int nand_read(struct mtd_info *mt
- }
-
- /**
- + * nand_part_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc
- + * @mtd: MTD device structure
- + * @from: offset to read from
- + * @len: number of bytes to read
- + * @retlen: pointer to variable to store the number of read bytes
- + * @buf: the databuffer to put data
- + *
- + * Get hold of the chip and call nand_do_read.
- + */
- +static int nand_part_read(struct mtd_info *mtd, loff_t from, size_t len,
- + size_t *retlen, uint8_t *buf)
- +{
- + struct nand_chip *chip = mtd->priv;
- + struct nand_part *part = to_nand_part(mtd);
- + struct mtd_oob_ops ops;
- + int ret;
- +
- + from += part->offset;
- + nand_get_device(part->master, FL_READING);
- + if (part->ecc)
- + chip->cur_ecc = part->ecc;
- + ops.len = len;
- + ops.datbuf = buf;
- + ops.oobbuf = NULL;
- + ops.mode = MTD_OPS_PLACE_OOB;
- + ret = nand_do_read_ops(part->master, from, &ops);
- + *retlen = ops.retlen;
- + chip->cur_ecc = &chip->ecc;
- + nand_release_device(part->master);
- + return ret;
- +}
- +
- +/**
- * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- @@ -1770,13 +1813,14 @@ static int nand_read_oob_syndrome(struct
- int page)
- {
- int length = mtd->oobsize;
- - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- - int eccsize = chip->ecc.size;
- + int chunk = chip->cur_ecc->bytes + chip->cur_ecc->prepad +
- + chip->cur_ecc->postpad;
- + int eccsize = chip->cur_ecc->size;
- uint8_t *bufpoi = chip->oob_poi;
- int i, toread, sndrnd = 0, pos;
-
- - chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
- - for (i = 0; i < chip->ecc.steps; i++) {
- + chip->cmdfunc(mtd, NAND_CMD_READ0, chip->cur_ecc->size, page);
- + for (i = 0; i < chip->cur_ecc->steps; i++) {
- if (sndrnd) {
- pos = eccsize + i * (eccsize + chunk);
- if (mtd->writesize > 512)
- @@ -1829,9 +1873,10 @@ static int nand_write_oob_std(struct mtd
- static int nand_write_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
- {
- - int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- - int eccsize = chip->ecc.size, length = mtd->oobsize;
- - int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
- + int chunk = chip->cur_ecc->bytes + chip->cur_ecc->prepad +
- + chip->cur_ecc->postpad;
- + int eccsize = chip->cur_ecc->size, length = mtd->oobsize;
- + int i, len, pos, status = 0, sndcmd = 0, steps = chip->cur_ecc->steps;
- const uint8_t *bufpoi = chip->oob_poi;
-
- /*
- @@ -1839,7 +1884,7 @@ static int nand_write_oob_syndrome(struc
- * or
- * data-pad-ecc-pad-data-pad .... ecc-pad-oob
- */
- - if (!chip->ecc.prepad && !chip->ecc.postpad) {
- + if (!chip->cur_ecc->prepad && !chip->cur_ecc->postpad) {
- pos = steps * (eccsize + chunk);
- steps = 0;
- } else
- @@ -1903,7 +1948,7 @@ static int nand_do_read_oob(struct mtd_i
- stats = mtd->ecc_stats;
-
- if (ops->mode == MTD_OPS_AUTO_OOB)
- - len = chip->ecc.layout->oobavail;
- + len = chip->cur_ecc->layout->oobavail;
- else
- len = mtd->oobsize;
-
- @@ -1931,9 +1976,9 @@ static int nand_do_read_oob(struct mtd_i
-
- while (1) {
- if (ops->mode == MTD_OPS_RAW)
- - ret = chip->ecc.read_oob_raw(mtd, chip, page);
- + ret = chip->cur_ecc->read_oob_raw(mtd, chip, page);
- else
- - ret = chip->ecc.read_oob(mtd, chip, page);
- + ret = chip->cur_ecc->read_oob(mtd, chip, page);
-
- if (ret < 0)
- break;
- @@ -2021,6 +2066,56 @@ out:
- return ret;
- }
-
- +/**
- + * nand_part_read_oob - [MTD Interface] NAND read data and/or out-of-band
- + * @mtd: MTD device structure
- + * @from: offset to read from
- + * @ops: oob operation description structure
- + *
- + * NAND read data and/or out-of-band data.
- + */
- +static int nand_part_read_oob(struct mtd_info *mtd, loff_t from,
- + struct mtd_oob_ops *ops)
- +{
- + struct nand_chip *chip = mtd->priv;
- + struct nand_part *part = to_nand_part(mtd);
- + int ret = -ENOTSUPP;
- +
- + ops->retlen = 0;
- +
- + /* Do not allow reads past end of device */
- + if (ops->datbuf && (from + ops->len) > mtd->size) {
- + pr_debug("%s: attempt to read beyond end of device\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + from += part->offset;
- + nand_get_device(part->master, FL_READING);
- + if (part->ecc)
- + chip->cur_ecc = part->ecc;
- +
- + switch (ops->mode) {
- + case MTD_OPS_PLACE_OOB:
- + case MTD_OPS_AUTO_OOB:
- + case MTD_OPS_RAW:
- + break;
- +
- + default:
- + goto out;
- + }
- +
- + if (!ops->datbuf)
- + ret = nand_do_read_oob(part->master, from, ops);
- + else
- + ret = nand_do_read_ops(part->master, from, ops);
- +
- +out:
- + chip->cur_ecc = &chip->ecc;
- + nand_release_device(part->master);
- + return ret;
- +}
- +
-
- /**
- * nand_write_page_raw - [INTERN] raw page write function
- @@ -2054,26 +2149,26 @@ static int nand_write_page_raw_syndrome(
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
- {
- - int eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- + int eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- uint8_t *oob = chip->oob_poi;
- int steps, size;
-
- - for (steps = chip->ecc.steps; steps > 0; steps--) {
- + for (steps = chip->cur_ecc->steps; steps > 0; steps--) {
- chip->write_buf(mtd, buf, eccsize);
- buf += eccsize;
-
- - if (chip->ecc.prepad) {
- - chip->write_buf(mtd, oob, chip->ecc.prepad);
- - oob += chip->ecc.prepad;
- + if (chip->cur_ecc->prepad) {
- + chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
- + oob += chip->cur_ecc->prepad;
- }
-
- chip->write_buf(mtd, oob, eccbytes);
- oob += eccbytes;
-
- - if (chip->ecc.postpad) {
- - chip->write_buf(mtd, oob, chip->ecc.postpad);
- - oob += chip->ecc.postpad;
- + if (chip->cur_ecc->postpad) {
- + chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
- + oob += chip->cur_ecc->postpad;
- }
- }
-
- @@ -2093,21 +2188,21 @@ static int nand_write_page_raw_syndrome(
- static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- const uint8_t *p = buf;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
-
- /* Software ECC calculation */
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- - chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- + chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
-
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- - return chip->ecc.write_page_raw(mtd, chip, buf, 1);
- + return chip->cur_ecc->write_page_raw(mtd, chip, buf, 1);
- }
-
- /**
- @@ -2120,20 +2215,20 @@ static int nand_write_page_swecc(struct
- static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- const uint8_t *p = buf;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- - chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
- - chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- + chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
- }
-
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
- @@ -2158,10 +2253,10 @@ static int nand_write_subpage_hwecc(stru
- {
- uint8_t *oob_buf = chip->oob_poi;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- - int ecc_size = chip->ecc.size;
- - int ecc_bytes = chip->ecc.bytes;
- - int ecc_steps = chip->ecc.steps;
- - uint32_t *eccpos = chip->ecc.layout->eccpos;
- + int ecc_size = chip->cur_ecc->size;
- + int ecc_bytes = chip->cur_ecc->bytes;
- + int ecc_steps = chip->cur_ecc->steps;
- + uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
- uint32_t start_step = offset / ecc_size;
- uint32_t end_step = (offset + data_len - 1) / ecc_size;
- int oob_bytes = mtd->oobsize / ecc_steps;
- @@ -2169,7 +2264,7 @@ static int nand_write_subpage_hwecc(stru
-
- for (step = 0; step < ecc_steps; step++) {
- /* configure controller for WRITE access */
- - chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
-
- /* write data (untouched subpages already masked by 0xFF) */
- chip->write_buf(mtd, buf, ecc_size);
- @@ -2178,7 +2273,7 @@ static int nand_write_subpage_hwecc(stru
- if ((step < start_step) || (step > end_step))
- memset(ecc_calc, 0xff, ecc_bytes);
- else
- - chip->ecc.calculate(mtd, buf, ecc_calc);
- + chip->cur_ecc->calculate(mtd, buf, ecc_calc);
-
- /* mask OOB of un-touched subpages by padding 0xFF */
- /* if oob_required, preserve OOB metadata of written subpage */
- @@ -2193,7 +2288,7 @@ static int nand_write_subpage_hwecc(stru
- /* copy calculated ECC for whole page to chip->buffer->oob */
- /* this include masked-value(0xFF) for unwritten subpages */
- ecc_calc = chip->buffers->ecccalc;
- - for (i = 0; i < chip->ecc.total; i++)
- + for (i = 0; i < chip->cur_ecc->total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- /* write OOB buffer to NAND device */
- @@ -2217,29 +2312,29 @@ static int nand_write_page_syndrome(stru
- struct nand_chip *chip,
- const uint8_t *buf, int oob_required)
- {
- - int i, eccsize = chip->ecc.size;
- - int eccbytes = chip->ecc.bytes;
- - int eccsteps = chip->ecc.steps;
- + int i, eccsize = chip->cur_ecc->size;
- + int eccbytes = chip->cur_ecc->bytes;
- + int eccsteps = chip->cur_ecc->steps;
- const uint8_t *p = buf;
- uint8_t *oob = chip->oob_poi;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-
- - chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- + chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
-
- - if (chip->ecc.prepad) {
- - chip->write_buf(mtd, oob, chip->ecc.prepad);
- - oob += chip->ecc.prepad;
- + if (chip->cur_ecc->prepad) {
- + chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
- + oob += chip->cur_ecc->prepad;
- }
-
- - chip->ecc.calculate(mtd, p, oob);
- + chip->cur_ecc->calculate(mtd, p, oob);
- chip->write_buf(mtd, oob, eccbytes);
- oob += eccbytes;
-
- - if (chip->ecc.postpad) {
- - chip->write_buf(mtd, oob, chip->ecc.postpad);
- - oob += chip->ecc.postpad;
- + if (chip->cur_ecc->postpad) {
- + chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
- + oob += chip->cur_ecc->postpad;
- }
- }
-
- @@ -2270,7 +2365,7 @@ static int nand_write_page(struct mtd_in
- int status, subpage;
-
- if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
- - chip->ecc.write_subpage)
- + chip->cur_ecc->write_subpage)
- subpage = offset || (data_len < mtd->writesize);
- else
- subpage = 0;
- @@ -2278,13 +2373,15 @@ static int nand_write_page(struct mtd_in
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
- if (unlikely(raw))
- - status = chip->ecc.write_page_raw(mtd, chip, buf,
- - oob_required);
- + status = chip->cur_ecc->write_page_raw(mtd, chip, buf,
- + oob_required);
- else if (subpage)
- - status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
- - buf, oob_required);
- + status = chip->cur_ecc->write_subpage(mtd, chip, offset,
- + data_len, buf,
- + oob_required);
- else
- - status = chip->ecc.write_page(mtd, chip, buf, oob_required);
- + status = chip->cur_ecc->write_page(mtd, chip, buf,
- + oob_required);
-
- if (status < 0)
- return status;
- @@ -2343,7 +2440,7 @@ static uint8_t *nand_fill_oob(struct mtd
- return oob + len;
-
- case MTD_OPS_AUTO_OOB: {
- - struct nand_oobfree *free = chip->ecc.layout->oobfree;
- + struct nand_oobfree *free = chip->cur_ecc->layout->oobfree;
- uint32_t boffs = 0, woffs = ops->ooboffs;
- size_t bytes = 0;
-
- @@ -2539,6 +2636,46 @@ static int panic_nand_write(struct mtd_i
- }
-
- /**
- + * panic_nand_part_write - [MTD Interface] NAND write with ECC
- + * @mtd: MTD device structure
- + * @to: offset to write to
- + * @len: number of bytes to write
- + * @retlen: pointer to variable to store the number of written bytes
- + * @buf: the data to write
- + *
- + * NAND write with ECC. Used when performing writes in interrupt context, this
- + * may for example be called by mtdoops when writing an oops while in panic.
- + */
- +static int panic_nand_part_write(struct mtd_info *mtd, loff_t to, size_t len,
- + size_t *retlen, const uint8_t *buf)
- +{
- + struct nand_chip *chip = mtd->priv;
- + struct nand_part *part = to_nand_part(mtd);
- + struct mtd_oob_ops ops;
- + int ret;
- +
- + to += part->offset;
- + /* Wait for the device to get ready */
- + panic_nand_wait(part->master, chip, 400);
- +
- + /* Grab the device */
- + panic_nand_get_device(chip, part->master, FL_WRITING);
- + if (part->ecc)
- + chip->cur_ecc = part->ecc;
- +
- + ops.len = len;
- + ops.datbuf = (uint8_t *)buf;
- + ops.oobbuf = NULL;
- + ops.mode = MTD_OPS_PLACE_OOB;
- +
- + ret = nand_do_write_ops(part->master, to, &ops);
- +
- + chip->cur_ecc = &chip->ecc;
- + *retlen = ops.retlen;
- + return ret;
- +}
- +
- +/**
- * nand_write - [MTD Interface] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- @@ -2566,6 +2703,39 @@ static int nand_write(struct mtd_info *m
- }
-
- /**
- + * nand_part_write - [MTD Interface] NAND write with ECC
- + * @mtd: MTD device structure
- + * @to: offset to write to
- + * @len: number of bytes to write
- + * @retlen: pointer to variable to store the number of written bytes
- + * @buf: the data to write
- + *
- + * NAND write with ECC.
- + */
- +static int nand_part_write(struct mtd_info *mtd, loff_t to, size_t len,
- + size_t *retlen, const uint8_t *buf)
- +{
- + struct nand_chip *chip = mtd->priv;
- + struct nand_part *part = to_nand_part(mtd);
- + struct mtd_oob_ops ops;
- + int ret;
- +
- + to += part->offset;
- + nand_get_device(part->master, FL_WRITING);
- + if (part->ecc)
- + chip->cur_ecc = part->ecc;
- + ops.len = len;
- + ops.datbuf = (uint8_t *)buf;
- + ops.oobbuf = NULL;
- + ops.mode = MTD_OPS_PLACE_OOB;
- + ret = nand_do_write_ops(part->master, to, &ops);
- + *retlen = ops.retlen;
- + chip->cur_ecc = &chip->ecc;
- + nand_release_device(part->master);
- + return ret;
- +}
- +
- +/**
- * nand_do_write_oob - [MTD Interface] NAND write out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- @@ -2583,7 +2753,7 @@ static int nand_do_write_oob(struct mtd_
- __func__, (unsigned int)to, (int)ops->ooblen);
-
- if (ops->mode == MTD_OPS_AUTO_OOB)
- - len = chip->ecc.layout->oobavail;
- + len = chip->cur_ecc->layout->oobavail;
- else
- len = mtd->oobsize;
-
- @@ -2637,9 +2807,11 @@ static int nand_do_write_oob(struct mtd_
- nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
-
- if (ops->mode == MTD_OPS_RAW)
- - status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
- + status = chip->cur_ecc->write_oob_raw(mtd, chip,
- + page & chip->pagemask);
- else
- - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
- + status = chip->cur_ecc->write_oob(mtd, chip,
- + page & chip->pagemask);
-
- chip->select_chip(mtd, -1);
-
- @@ -2694,6 +2866,54 @@ out:
- }
-
- /**
- + * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- + * @mtd: MTD device structure
- + * @to: offset to write to
- + * @ops: oob operation description structure
- + */
- +static int nand_part_write_oob(struct mtd_info *mtd, loff_t to,
- + struct mtd_oob_ops *ops)
- +{
- + struct nand_chip *chip = mtd->priv;
- + struct nand_part *part = to_nand_part(mtd);
- + int ret = -ENOTSUPP;
- +
- + ops->retlen = 0;
- +
- + /* Do not allow writes past end of device */
- + if (ops->datbuf && (to + ops->len) > mtd->size) {
- + pr_debug("%s: attempt to write beyond end of device\n",
- + __func__);
- + return -EINVAL;
- + }
- +
- + to += part->offset;
- + nand_get_device(part->master, FL_WRITING);
- + if (part->ecc)
- + chip->cur_ecc = part->ecc;
- +
- + switch (ops->mode) {
- + case MTD_OPS_PLACE_OOB:
- + case MTD_OPS_AUTO_OOB:
- + case MTD_OPS_RAW:
- + break;
- +
- + default:
- + goto out;
- + }
- +
- + if (!ops->datbuf)
- + ret = nand_do_write_oob(part->master, to, ops);
- + else
- + ret = nand_do_write_ops(part->master, to, ops);
- +
- +out:
- + chip->cur_ecc = &chip->ecc;
- + nand_release_device(part->master);
- + return ret;
- +}
- +
- +/**
- * single_erase - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
- * @page: the page address of the block which will be erased
- @@ -2723,6 +2943,29 @@ static int nand_erase(struct mtd_info *m
- }
-
- /**
- + * nand_part_erase - [MTD Interface] erase partition block(s)
- + * @mtd: MTD device structure
- + * @instr: erase instruction
- + *
- + * Erase one ore more blocks.
- + */
- +static int nand_part_erase(struct mtd_info *mtd, struct erase_info *instr)
- +{
- + struct nand_part *part = to_nand_part(mtd);
- + int ret;
- +
- + instr->addr += part->offset;
- + ret = nand_erase_nand(part->master, instr, 0);
- + if (ret) {
- + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
- + instr->fail_addr -= part->offset;
- + instr->addr -= part->offset;
- + }
- +
- + return ret;
- +}
- +
- +/**
- * nand_erase_nand - [INTERN] erase block(s)
- * @mtd: MTD device structure
- * @instr: erase instruction
- @@ -2864,6 +3107,18 @@ static int nand_block_isbad(struct mtd_i
- }
-
- /**
- + * nand_part_block_isbad - [MTD Interface] Check if block at offset is bad
- + * @mtd: MTD device structure
- + * @offs: offset relative to mtd start
- + */
- +static int nand_part_block_isbad(struct mtd_info *mtd, loff_t offs)
- +{
- + struct nand_part *part = to_nand_part(mtd);
- +
- + return nand_block_checkbad(part->master, part->offset + offs, 1, 0);
- +}
- +
- +/**
- * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
- * @mtd: MTD device structure
- * @ofs: offset relative to mtd start
- @@ -2884,6 +3139,33 @@ static int nand_block_markbad(struct mtd
- }
-
- /**
- + * nand_part_block_markbad - [MTD Interface] Mark block at the given offset as
- + * bad
- + * @mtd: MTD device structure
- + * @ofs: offset relative to mtd start
- + */
- +static int nand_part_block_markbad(struct mtd_info *mtd, loff_t ofs)
- +{
- + struct nand_part *part = to_nand_part(mtd);
- + int ret;
- +
- + ofs += part->offset;
- + ret = nand_block_isbad(part->master, ofs);
- + if (ret) {
- + /* If it was bad already, return success and do nothing */
- + if (ret > 0)
- + return 0;
- + return ret;
- + }
- +
- + ret = nand_block_markbad_lowlevel(part->master, ofs);
- + if (!ret)
- + mtd->ecc_stats.badblocks++;
- +
- + return ret;
- +}
- +
- +/**
- * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
- * @mtd: MTD device structure
- * @chip: nand chip info structure
- @@ -4099,6 +4381,169 @@ static int nand_ecc_ctrl_init(struct mtd
- }
-
- /**
- + * nand_add_partition - [NAND Interface] Add a NAND partition to a NAND device
- + * @master: MTD device structure representing the NAND device
- + * @part: NAND partition to add to the NAND device
- + *
- + * Adds a NAND partition to a NAND device.
- + * The NAND partition cannot overlap with another existing partition.
- + *
- + * Returns zero in case of success and a negative error code in case of failure.
- + */
- +int nand_add_partition(struct mtd_info *master, struct nand_part *part)
- +{
- + struct nand_chip *chip = master->priv;
- + struct mtd_info *mtd = &part->mtd;
- + struct nand_ecc_ctrl *ecc = part->ecc;
- + struct nand_part *pos;
- + bool inserted = false;
- + int ret;
- +
- + /* set up the MTD object for this partition */
- + mtd->type = master->type;
- + mtd->flags = master->flags & ~mtd->flags;
- + mtd->writesize = master->writesize;
- + mtd->writebufsize = master->writebufsize;
- + mtd->oobsize = master->oobsize;
- + mtd->oobavail = master->oobavail;
- + mtd->subpage_sft = master->subpage_sft;
- + mtd->erasesize = master->erasesize;
- +
- + mtd->priv = chip;
- + mtd->owner = master->owner;
- + mtd->backing_dev_info = master->backing_dev_info;
- +
- + mtd->dev.parent = master->dev.parent;
- +
- + if (ecc) {
- + ret = nand_ecc_ctrl_init(mtd, ecc);
- + if (ret)
- + return ret;
- + } else {
- + ecc = &chip->ecc;
- + }
- +
- + mtd->_erase = nand_part_erase;
- + mtd->_point = NULL;
- + mtd->_unpoint = NULL;
- + mtd->_read = nand_part_read;
- + mtd->_write = nand_part_write;
- + mtd->_panic_write = panic_nand_part_write;
- + mtd->_read_oob = nand_part_read_oob;
- + mtd->_write_oob = nand_part_write_oob;
- + mtd->_sync = nand_sync;
- + mtd->_lock = NULL;
- + mtd->_unlock = NULL;
- + mtd->_suspend = nand_suspend;
- + mtd->_resume = nand_resume;
- + mtd->_block_isbad = nand_part_block_isbad;
- + mtd->_block_markbad = nand_part_block_markbad;
- +
- + /* propagate ecc info to mtd_info */
- + mtd->ecclayout = ecc->layout;
- + mtd->ecc_strength = ecc->strength;
- + mtd->ecc_step_size = ecc->size;
- + /*
- + * Initialize bitflip_threshold to its default prior scan_bbt() call.
- + * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
- + * properly set.
- + */
- + if (!mtd->bitflip_threshold)
- + mtd->bitflip_threshold = mtd->ecc_strength;
- +
- + part->master = master;
- +
- + mutex_lock(&chip->part_lock);
- + list_for_each_entry(pos, &chip->partitions, node) {
- + if (part->offset >= pos->offset + pos->mtd.size) {
- + continue;
- + } else if (part->offset + mtd->size > pos->offset) {
- + ret = -EINVAL;
- + goto out;
- + }
- +
- + list_add(&part->node, pos->node.prev);
- + inserted = true;
- + break;
- + }
- +
- + if (!inserted)
- + list_add_tail(&part->node, &chip->partitions);
- +
- + ret = mtd_device_register(mtd, NULL, 0);
- + if (ret) {
- + list_del(&part->node);
- + goto out;
- + }
- +
- + if (master->_block_isbad) {
- + uint64_t offs = 0;
- +
- + while (offs < mtd->size) {
- + if (mtd_block_isreserved(master, offs + part->offset))
- + mtd->ecc_stats.bbtblocks++;
- + else if (mtd_block_isbad(master, offs + part->offset))
- + mtd->ecc_stats.badblocks++;
- + offs += mtd->erasesize;
- + }
- + }
- +
- +out:
- + mutex_unlock(&chip->part_lock);
- + return ret;
- +}
- +EXPORT_SYMBOL(nand_add_partition);
- +
- +/**
- + * nand_del_partition - [NAND Interface] Delete a NAND part from a NAND dev
- + * @part: NAND partition to delete
- + *
- + * Deletes a NAND partition from a NAND device.
- + */
- +void nand_del_partition(struct nand_part *part)
- +{
- + struct nand_chip *chip = part->mtd.priv;
- +
- + mutex_lock(&chip->part_lock);
- + mtd_device_unregister(&part->mtd);
- + list_del(&part->node);
- + mutex_unlock(&chip->part_lock);
- +
- + if (part->ecc && part->ecc->mode == NAND_ECC_SOFT_BCH)
- + nand_bch_free((struct nand_bch_control *)part->ecc->priv);
- +
- + if (part->release)
- + part->release(part);
- +}
- +EXPORT_SYMBOL(nand_del_partition);
- +
- +/*
- + * NAND part release function. Used by nandpart_alloc as its release function.
- + */
- +static void nandpart_release(struct nand_part *part)
- +{
- + kfree(part);
- +}
- +
- +/**
- + * nandpart_alloc - [NAND Interface] Allocate a NAND part struct
- + *
- + * Allocate a NAND partition and assign the nandpart release function.
- + * This nand_part struct must be filled before passing it to the
- + * nand_add_partition function.
- + */
- +struct nand_part *nandpart_alloc(void)
- +{
- + struct nand_part *part = kzalloc(sizeof(*part), GFP_KERNEL);
- + if (!part)
- + return ERR_PTR(-ENOMEM);
- + part->release = nandpart_release;
- +
- + return part;
- +}
- +EXPORT_SYMBOL(nandpart_alloc);
- +
- +/**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- *
- @@ -4146,6 +4591,11 @@ int nand_scan_tail(struct mtd_info *mtd)
- return ret;
- }
-
- + INIT_LIST_HEAD(&chip->partitions);
- + mutex_init(&chip->part_lock);
- +
- + chip->cur_ecc = &chip->ecc;
- +
- /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
- if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
- switch (ecc->steps) {
- --- a/drivers/mtd/nand/nand_bch.c
- +++ b/drivers/mtd/nand/nand_bch.c
- @@ -53,14 +53,14 @@ int nand_bch_calculate_ecc(struct mtd_in
- unsigned char *code)
- {
- const struct nand_chip *chip = mtd->priv;
- - struct nand_bch_control *nbc = chip->ecc.priv;
- + struct nand_bch_control *nbc = chip->cur_ecc->priv;
- unsigned int i;
-
- - memset(code, 0, chip->ecc.bytes);
- - encode_bch(nbc->bch, buf, chip->ecc.size, code);
- + memset(code, 0, chip->cur_ecc->bytes);
- + encode_bch(nbc->bch, buf, chip->cur_ecc->size, code);
-
- /* apply mask so that an erased page is a valid codeword */
- - for (i = 0; i < chip->ecc.bytes; i++)
- + for (i = 0; i < chip->cur_ecc->bytes; i++)
- code[i] ^= nbc->eccmask[i];
-
- return 0;
- @@ -80,15 +80,15 @@ int nand_bch_correct_data(struct mtd_inf
- unsigned char *read_ecc, unsigned char *calc_ecc)
- {
- const struct nand_chip *chip = mtd->priv;
- - struct nand_bch_control *nbc = chip->ecc.priv;
- + struct nand_bch_control *nbc = chip->cur_ecc->priv;
- unsigned int *errloc = nbc->errloc;
- int i, count;
-
- - count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
- - NULL, errloc);
- + count = decode_bch(nbc->bch, NULL, chip->cur_ecc->size, read_ecc,
- + calc_ecc, NULL, errloc);
- if (count > 0) {
- for (i = 0; i < count; i++) {
- - if (errloc[i] < (chip->ecc.size*8))
- + if (errloc[i] < (chip->cur_ecc->size*8))
- /* error is located in data, correct it */
- buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
- /* else error in ecc, no action needed */
- --- a/drivers/mtd/nand/nand_ecc.c
- +++ b/drivers/mtd/nand/nand_ecc.c
- @@ -424,7 +424,7 @@ int nand_calculate_ecc(struct mtd_info *
- unsigned char *code)
- {
- __nand_calculate_ecc(buf,
- - ((struct nand_chip *)mtd->priv)->ecc.size, code);
- + ((struct nand_chip *)mtd->priv)->cur_ecc->size, code);
-
- return 0;
- }
- @@ -524,7 +524,7 @@ int nand_correct_data(struct mtd_info *m
- unsigned char *read_ecc, unsigned char *calc_ecc)
- {
- return __nand_correct_data(buf, read_ecc, calc_ecc,
- - ((struct nand_chip *)mtd->priv)->ecc.size);
- + ((struct nand_chip *)mtd->priv)->cur_ecc->size);
- }
- EXPORT_SYMBOL(nand_correct_data);
-
- --- a/include/linux/mtd/nand.h
- +++ b/include/linux/mtd/nand.h
- @@ -708,6 +708,7 @@ struct nand_chip {
- struct nand_hw_control *controller;
-
- struct nand_ecc_ctrl ecc;
- + struct nand_ecc_ctrl *cur_ecc;
- struct nand_buffers *buffers;
- struct nand_hw_control hwcontrol;
-
- @@ -717,9 +718,46 @@ struct nand_chip {
-
- struct nand_bbt_descr *badblock_pattern;
-
- + struct list_head partitions;
- + struct mutex part_lock;
- +
- void *priv;
- };
-
- +/**
- + * struct nand_part - NAND partition structure
- + * @node: list node used to attach the partition to its NAND dev
- + * @mtd: MTD partiton info
- + * @master: MTD device representing the NAND chip
- + * @offset: partition offset
- + * @ecc: partition specific ECC struct
- + * @release: function used to release this nand_part struct
- + *
- + * NAND partitions work as standard MTD partitions except it can override
- + * NAND chip ECC handling.
- + * This is particularly useful for SoCs that need specific ECC configs to boot
- + * from NAND while these ECC configs do not fit the NAND chip ECC requirements.
- + */
- +struct nand_part {
- + struct list_head node;
- + struct mtd_info mtd;
- + struct mtd_info *master;
- + uint64_t offset;
- + struct nand_ecc_ctrl *ecc;
- + void (*release)(struct nand_part *part);
- +};
- +
- +static inline struct nand_part *to_nand_part(struct mtd_info *mtd)
- +{
- + return container_of(mtd, struct nand_part, mtd);
- +}
- +
- +int nand_add_partition(struct mtd_info *master, struct nand_part *part);
- +
- +void nand_del_partition(struct nand_part *part);
- +
- +struct nand_part *nandpart_alloc(void);
- +
- /*
- * NAND Flash Manufacturer ID Codes
- */
|