linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
To: Boris Brezillon <boris.brezillon@free-electrons.com>
Cc: dwmw2@infradead.org, computersforpeace@gmail.com,
	matthias.bgg@gmail.com, robh@kernel.org,
	linux-mtd@lists.infradead.org, xiaolei.li@mediatek.com,
	daniel.thompson@linaro.org, erin.lo@mediatek.com,
	linux-mediatek@lists.infradead.org
Subject: Re: [PATCH v3 2/2] mtd: mediatek: driver for MTK Smart Device Gen1 NAND
Date: Tue, 19 Apr 2016 18:39:17 -0400	[thread overview]
Message-ID: <5716B395.8000805@linaro.org> (raw)
In-Reply-To: <20160419184237.62646214@bbrezillon>

On 04/19/2016 12:42 PM, Boris Brezillon wrote:
> Hi Jorge,
>
> On Tue, 19 Apr 2016 10:26:55 -0400
> Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org> wrote:
>
>>>> +static irqreturn_t mtk_ecc_irq(int irq, void *id)
>>>> +{
>>>> +	struct mtk_ecc *ecc = id;
>>>> +	u32 dec, enc;
>>>> +
>>>> +	dec = readw(ecc->regs + ECC_DECIRQ_STA) & DEC_IRQEN;
>>>> +	enc = readl(ecc->regs + ECC_ENCIRQ_STA) & ENC_IRQEN;
>>>> +
>>>> +	if (!(dec || enc))
>>>> +		return IRQ_NONE;
>>>> +
>>>> +	if (dec) {
>>>> +		dec = readw(ecc->regs + ECC_DECDONE);
>>>> +		if (dec & ecc->sec_mask) {
>>>> +			ecc->sec_mask = 0;
>>>> +			complete(&ecc->done);
>>> If you can really do enc and dec in parallel, then you should have two
>>> waitqueues.
>>
>> unfortunately no, we can't do parallel operations.
> That's not a problem, as long a you get exclusive access to the engine
> when launching an operation.
>
> Given this new input, I'd suggest reworking a bit the ECC interface.
> How about providing an mtk_ecc_enable() function where you'll pass the
> direction, or even better, the config which would contain the direction
> (encoding or decoding), the ECC strength and step-size (maybe we
> should also pass the ECC_MODE: NFI, DMA or whatever).

OK. that is simple enough (having said that, the mtk_ecc_irq will not change)


>
> Similarly to the mtk_ecc_enable() function you would have an
> mtk_ecc_disable() which would disable everything.

ok

>
> [...]
>>>> +{
>>> Not sure this is needed right now, since the NAND driver is the only
>>> user of the ECC engine (not even sure you can use the ECC engine
>>> independently), and we do not support accessing chips in parallel, but
>>> it may be more future proof to take a lock before using the ECC
>>> encoder/decoder, and release it when the operation is finished.
>> Since it is not required per the current architecture (no parallel chip
>> accesses) I do have doubts about it.
> Hm, given that your engine can possibly be used outside of the NAND
> pipeline, I'd recommend introducing a lock and using it.

I dont think it will ever will but I'll do the lock (just like jz4780_bch.c does)

> BTW, I see ECC_NFI_MODE (where NFI probably means Nand Flash
> Interface) and ECC_DMA_MODE, but the ECC_ENC_MODE mask is (3 << 5). I'm
> just curious, what are the other modes (if any)?

b11: reserved mode
b10: PIO mode
b01: NFI mode
b00: DMA mode


>
>>> This your controller seems capable of doing ECC encoding/decoding in
>>> parallel, it might be worth having 2 different locks.
>> I did double check with the design team and it can't.
> Then having a single lock is fine.
>
>>> If you decide to not use any lock, please add something in the
>>> documentation, stating that it's the ECC engine user responsibility to
>>> ensure serialization, and forbid several mtk_ecc_get() on the same
>>> device.
>> ok.
> Honestly, it wouldn't be a blocking aspect if you decide to skip the
> locking part, but given that implementing it seems quite easy and more
> future proof, I'd prefer if you do it.

ok.

>
>>>> +{
>>>> +	dma_addr_t addr;
>>>> +	u32 *p, len;
>>>> +	u32 reg, i;
>>>> +	int rc, ret = 0;
>>>> +
>>>> +	addr = dma_map_single(ecc->dev, d->data, d->len, DMA_TO_DEVICE);
>>>> +	rc = dma_mapping_error(ecc->dev, addr);
>>>> +	if (rc) {
>>>> +		dev_err(ecc->dev, "dma mapping error\n");
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	/* enable the encoder in DMA mode to calculate the ECC bytes  */
>>>> +	reg = readl(ecc->regs + ECC_ENCCNFG) & ~ECC_ENC_MODE_MASK;
>>>> +	reg |= ECC_DMA_MODE;
>>> When I compare the start_encode() to the start_decode() function I see
>>> one big difference: the former is clearly operating in non-pipeline
>>> mode (the data are retrieved using DMA and returned values are kept in
>>> PARX registers), while, IFAICS, the latter is operating in pipeline
>>> mode (data are directly retrieved from the NAND engine stream).
>> yes
>>
>>> I'm perfectly fine supporting those 2 modes (at least it gives an
>>> answer to one of my question: the ECC engine can be used independently
>>> of the NAND engine), but the function names should reflect this.
>> sure: ecc_prepare_decoder() and ecc_encode().
> Maybe something mode explicit, like mtd_ecc_prepare_pipeline().

what is wrong with prepare decoder?

> BTW, I had a second look at your implementation, and I wonder why
> you're not putting the operations done in the prepare function directly
> in the enable one.

No reason - this was the sequence of register writes provided by the design team 
so we kept them this way.
I'll try to reorganize.

>
>
>
>>>> +
>>>> +static int mtk_nfc_block_markbad(struct mtd_info *mtd, loff_t ofs)
>>>> +{
>>>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>>>> +	u8 *buf = chip->buffers->databuf;
>>>> +	int page, rc, i;
>>>> +
>>>> +	memset(buf, 0x00, mtd->writesize + mtd->oobsize);
>>>> +
>>>> +	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
>>>> +		ofs += mtd->erasesize - mtd->writesize;
>>>> +
>>>> +	i = 0;
>>>> +	do {
>>>> +		page = (int)(ofs >> chip->page_shift);
>>>> +		chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
>>>> +		rc = mtk_nfc_write_page(mtd, chip, buf, 0, page, 1);
>>>> +		if (rc < 0)
>>>> +			return rc;
>>>> +
>>>> +		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
>>>> +		rc = chip->waitfunc(mtd, chip);
>>>> +		rc = rc & NAND_STATUS_FAIL ? -EIO : 0;
>>>> +		if (rc < 0)
>>>> +			return rc;
>>>> +
>>>> +		ofs += mtd->writesize;
>>>> +		i++;
>>>> +
>>>> +	} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
>>>> +
>>>> +	return 0;
>>>> +}
>>> Why do you need this custom implementation?
>> the reason it our page layout: if we need to mark a bad block it is not possible
>> for us to access the spare area (our layout is: sector + oob + sector + oob ...)
>> so we just mark the whole page.
>>
>> is this acceptable?
> Oh, this means you're loosing the BBM as soon as you start using the
> NAND. Don't you have a mechanism switching one or 2 bytes of in-band
> with OOB data, so that the BBM remains intact and you can still mark
> them as bad when needed?
> I'd strongly suggest to do this (I know other drivers, like the GPMI
> one, use the same trick).
>
> BTW, how do you detect bad blocks marked by the NAND vendor. Those BBMs
> will be in what you consider your in-band region.

let me come back to you on this. I realize it is important.

>
>
>>>> +
>>>> +	if (ret < mtd->bitflip_threshold)
>>>> +		mtd->ecc_stats.corrected = stats.corrected;
>>> Hm, ->corrected has already been updated by mtk_nfc_read_page_hwecc(),
>>> or am I missing something?
>>> Moreover, you should have mtd->ecc_stats.corrected += stats.corrected.
>> sorry, yes it might be a bit convoluted due to the inverted logic.
>> unless the number of bitflips returned by the read_page_hwecc is equal or over
>> the threshold we don't update the corrected stats (so we just reset it to the
>> previous value at this point, hence the = instead of the +=).
> What's the point? I mean, ->corrected should be updated each time you
> read a page, even if the number of bitflips does not exceed the
> bitflips_threshold.

ack

>
>
>>>> +
>>>> +static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
>>>> +				struct mtd_oob_region *oob_region)
>>>> +{
>>>> +	struct nand_chip *chip = mtd_to_nand(mtd);
>>>> +
>>>> +	if (section)
>>>> +		return -ERANGE;
>>>> +
>>>> +	oob_region->length = NFI_FDM_REG_SIZE * chip->ecc.steps;
>>> Is NFI_FDM_REG_SIZE really fixed to 8, or does it depend on the
>>> spare_per_sector and ecc->bytes information?
>> Its value can range between 0 and 8 and it depends on the spare area size and
>> the ecc level.
>> each sector spare is: FDM + ECC parity + dummy (if there is dummy, the
>> controller pads it)
>> ECC parity = 14 * ecc level (bits)
>>
>> So we could do:
>>
>> FDM size = spare size - (14 * ecc level + 7) / 8;
>> if (FDM size > 8)
>> FDM size = 8;
> Looks good to me.

ok

>
>>
>> for SLC and MLC nand we do fix it to 8 in all cases.
>> for TLC nand, since we have less spare, we can only use 3 bytes.
>>
>> do you think it is worth adding the FDM size as a function?
> Not necessarily a function, it can be a field somewhere in your private
> mtk_nand_chip struct.

ok.

>
>

  reply	other threads:[~2016-04-19 22:39 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-11 16:56 [PATCH v3 0/2] MTK Smart Device Gen1 NAND Driver Jorge Ramirez-Ortiz
2016-04-11 16:56 ` [PATCH v3 1/2] mtd: mediatek: device tree docs for MTK Smart Device Gen1 NAND Jorge Ramirez-Ortiz
2016-04-11 23:15   ` Boris Brezillon
2016-04-12  1:17     ` Jorge Ramirez-Ortiz
2016-04-11 16:56 ` [PATCH v3 2/2] mtd: mediatek: driver " Jorge Ramirez-Ortiz
2016-04-17 22:17   ` Boris Brezillon
2016-04-19 14:26     ` Jorge Ramirez-Ortiz
2016-04-19 16:42       ` Boris Brezillon
2016-04-19 22:39         ` Jorge Ramirez-Ortiz [this message]
2016-04-18  8:01   ` Boris Brezillon
2016-04-19 20:24   ` Boris Brezillon
2016-04-19 21:16     ` Jorge Ramirez-Ortiz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5716B395.8000805@linaro.org \
    --to=jorge.ramirez-ortiz@linaro.org \
    --cc=boris.brezillon@free-electrons.com \
    --cc=computersforpeace@gmail.com \
    --cc=daniel.thompson@linaro.org \
    --cc=dwmw2@infradead.org \
    --cc=erin.lo@mediatek.com \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=robh@kernel.org \
    --cc=xiaolei.li@mediatek.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).