All of lore.kernel.org
 help / color / mirror / Atom feed
From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Naga Sureshkumar Relli <nagasure@xilinx.com>
Cc: "nagasureshkumarrelli@gmail.com" <nagasureshkumarrelli@gmail.com>,
	"boris.brezillon@bootlin.com" <boris.brezillon@bootlin.com>,
	"richard@nod.at" <richard@nod.at>,
	"dwmw2@infradead.org" <dwmw2@infradead.org>,
	"computersforpeace@gmail.com" <computersforpeace@gmail.com>,
	"marek.vasut@gmail.com" <marek.vasut@gmail.com>,
	"cyrille.pitchen@wedev4u.fr" <cyrille.pitchen@wedev4u.fr>,
	"linux-mtd@lists.infradead.org" <linux-mtd@lists.infradead.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	Michal Simek <michals@xilinx.com>,
	"Punnaiah Choudary Kalluri" <punnaia@xilinx.com>
Subject: Re: [LINUX PATCH v8 2/2] mtd: rawnand: pl353: Add basic driver for arm pl353 smc nand interface
Date: Mon, 26 Mar 2018 23:53:59 +0200	[thread overview]
Message-ID: <20180326235359.39825dfd@xps13> (raw)
In-Reply-To: <BY2PR02MB14114DD144070E22CEB8FC07AFA80@BY2PR02MB1411.namprd02.prod.outlook.com>

Hi Naga,

> > > +/**
> > > + * pl353_nand_read_buf_l - read chip data into buffer
> > > + * @chip:	Pointer to the NAND chip info structure
> > > + * @in:		Pointer to the buffer to store read data
> > > + * @len:	Number of bytes to read
> > > + * Return:	Always return zero
> > > + */
> > > +static int pl353_nand_read_buf_l(struct nand_chip *chip,
> > > +				     uint8_t *in,
> > > +				     unsigned int len)
> > > +{
> > > +	int i;
> > > +	unsigned long *ptr = (unsigned long *)in;
> > > +
> > > +	len >>= 2;
> > 
> > Can you please let the compiler optimize things? I don't find this very readable, I
> > would prefer a division here. And if this division by 4 is related to the size of *ptr,
> > please use the sizeof() macro. Otherwise please document this value.
> At a time, we are reading 4bytes. Hence >> 2.
> I didn't get your point.
> Are you saying instead of shifting, just use divide by 4?

I do.

> 
> > 
> > > +	for (i = 0; i < len; i++)
> > > +		ptr[i] = readl(chip->IO_ADDR_R);
> > 
> > Space
> Ok, I will update it
> > 
> > > +	return 0;
> > > +}
> > > +
> > > +static void pl353_nand_write_buf_l(struct nand_chip *chip, const uint8_t
> > *buf,
> > > +				int len)
> > > +{
> > > +	int i;
> > > +	unsigned long *ptr = (unsigned long *)buf;
> > > +
> > > +	for (i = 0; i < len; i++)
> > > +		writeb(ptr[i], chip->IO_ADDR_W);
> > 
> > Here you use writeb (as opposed to readl previously). Then, I guess you can also
> > read byte per byte. If so, you can drop both helpers and let the core use its
> > defaults ones: nand_read/write_buf().
> May be the function name I have written wrongly.
> When using writel, it should be nand_write_buf_l.
> But the thing is, when using exec_op, core is not calling chip->read_byte(), hence I added
> Byte reading.

Well, the point of using ->exec_op() is to forget about these hooks.
->exec_op() will ask you to read one byte if needed. You should forget
about ->read/write_byte/word/buf() hooks and delete them entirely.

> > 
> > Same for the next functions. Plus, if you don't use them inside
> > ->exec_op() implementation, they have to be removed anyway.
> The name of the function should change to buf_l, to do 4byte writes.
> The name is creating confusion.
> > 
> > > +}
> > > +
> > > +/**
> > > + * pl353_nand_write_buf - write buffer to chip
> > > + * @mtd:	Pointer to the mtd info structure
> > > + * @buf:	Pointer to the buffer to store read data
> > > + * @len:	Number of bytes to write
> > > + */
> > > +static void pl353_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
> > > +				int len)
> > > +{
> > > +	int i;
> > > +	struct nand_chip *chip = mtd_to_nand(mtd);
> > > +	unsigned long *ptr = (unsigned long *)buf;
> > > +
> > > +	len >>= 2;
> > > +
> > > +	for (i = 0; i < len; i++)
> > > +		writel(ptr[i], chip->IO_ADDR_W);
> > > +}
> > > +
> > > +/**
> > > + * pl353_nand_read_buf - read chip data into buffer
> > > + * @chip:	Pointer to the NAND chip info structure
> > > + * @in:	Pointer to the buffer to store read data
> > > + * @len:	Number of bytes to read
> > > + * Return:	0 on success or error value on failure
> > > + */
> > > +static int pl353_nand_read_buf(struct nand_chip *chip,
> > > +				     uint8_t *in,
> > > +				     unsigned int len)
> > > +{
> > > +	int i;
> > > +
> > > +	for (i = 0; i < len; i++)
> > > +		in[i] = readb(chip->IO_ADDR_R);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +/**
> > > + * pl353_nand_calculate_hwecc - Calculate Hardware ECC
> > > + * @mtd:	Pointer to the mtd_info structure
> > > + * @data:	Pointer to the page data
> > > + * @ecc_code:	Pointer to the ECC buffer where ECC data needs to be
> > stored
> > 
> > You store ECC in a variable called "code", can you please make it consistent?
> Miquel, I am not using any variable called "code"

I see "ecc_code", and ECC already stands for "Error Correcting Code".

> > 
> > > + *
> > > + * This function retrieves the Hardware ECC data from the controller
> > > +and returns
> > > + * ECC data back to the MTD subsystem.
> > > + *
> > > + * Return:	0 on success or error value on failure
> > > + */
> > > +static int pl353_nand_calculate_hwecc(struct mtd_info *mtd,
> > > +				const u8 *data, u8 *ecc_code)
> > > +{
> > > +	u32 ecc_value, ecc_status;
> > > +	u8 ecc_reg, ecc_byte;
> > > +	unsigned long timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT;
> > > +	/* Wait till the ECC operation is complete or timeout */
> > > +	do {
> > > +		if (pl353_smc_ecc_is_busy())
> > 
> > Where does this function come from?
> The pl353 SMC has memory controller driver and this NAND driver is using those APIs.
> I sent patches to add the memory controller driver for pl353.
> https://www.spinics.net/lists/kernel/msg2748832.html
> https://www.spinics.net/lists/kernel/msg2748834.html
> https://www.spinics.net/lists/kernel/msg2748840.html
> 

ok, please add a reference in your cover letter to the functions that
are not yet merged and you would use in this series.


> > > +
> > > +	cmd_phase_addr = (unsigned long __force)xnand->nand_base + (
> > > +			 (((xnand->row_addr_cycles) + (xnand-
> > >col_addr_cycles))
> > > +			 << ADDR_CYCLES_SHIFT) |
> > > +			 (end_cmd_valid << END_CMD_VALID_SHIFT)
> > 	|
> > > +			 (COMMAND_PHASE)				|
> > > +			 (end_cmd << END_CMD_SHIFT)			|
> > 
> > Please don't align the '|'
> You mean, tabbing? 

Yes

> > 
> > > +			 (start_cmd << START_CMD_SHIFT));
> > > +	cmd_addr = (void __iomem * __force)cmd_phase_addr;
> > > +
> > > +	/* Get the data phase address */
> > > +	data_phase_addr = (unsigned long __force)xnand->nand_base + (
> > > +			  (0x0 << CLEAR_CS_SHIFT)			|
> > > +			  (0 << END_CMD_VALID_SHIFT)	|
> > > +			  (DATA_PHASE)					|
> > > +			  (end_cmd << END_CMD_SHIFT)			|
> > > +			  (0x0 << ECC_LAST_SHIFT));
> > > +
> > > +	chip->IO_ADDR_R = (void __iomem * __force)data_phase_addr;
> > > +	chip->IO_ADDR_W = chip->IO_ADDR_R;
> > > +	if (chip->options & NAND_BUSWIDTH_16)
> > > +		column >>= 1;
> > 
> >  / 2
> > 
> > > +	cmd_data = column;
> > > +	if (mtd->writesize > PL353_NAND_ECC_SIZE) {
> > > +		cmd_data |= page << 16;
> > > +		/* Another address cycle for devices > 128MiB */
> > > +		if (chip->chipsize > (128 << 20)) {
> > 
> > Now there is a flag for that in the core, called NAND_ROW_ADDR_3.
> I will check and update.
> > 
> > > +			pl353_nand_write32(cmd_addr, cmd_data);
> > > +			cmd_data = (page >> 16);
> > > +		}
> > > +	} else {
> > > +		cmd_data |= page << 8;
> > > +	}
> > 
> > Space
> Ok, I will update.
> > 
> > > +	pl353_nand_write32(cmd_addr, cmd_data); }
> > > +
> > > +/**
> > > + * pl353_nand_read_oob - [REPLACEABLE] the most common OOB data read
> > function
> > > + * @mtd:	Pointer to the mtd info structure
> > > + * @chip:	Pointer to the NAND chip info structure
> > > + * @page:	Page number to read
> > > + *
> > > + * Return:	Always return zero
> > > + */
> > > +static int pl353_nand_read_oob(struct mtd_info *mtd, struct nand_chip
> > *chip,
> > > +			    int page)
> > > +{
> > > +
> > > +	unsigned long data_phase_addr;
> > > +	uint8_t *p;
> > > +
> > > +	chip->pagebuf = -1;
> > > +	if (mtd->writesize < PL353_NAND_ECC_SIZE)
> > > +		return 0;
> > > +
> > > +	pl353_prepare_cmd(mtd, chip, page, mtd->writesize,
> > NAND_CMD_READ0,
> > > +		NAND_CMD_READSTART, 1);
> > 
> > Alignment
> Are you running any script apart from checkpatch?
> Any way I will correct it.

All my comments have been made "manually" without tool but you should
definitively run checkpatch.pl --strict on all your patches before
sending them.


> > > +
> > > +	return (status & NAND_STATUS_FAIL) ? -EIO : 0; }
> > > +
> > > +/**
> > > + * pl353_nand_read_page_raw - [Intern] read raw page data without ecc
> > > + * @mtd:		Pointer to the mtd info structure
> > > + * @chip:		Pointer to the NAND chip info structure
> > > + * @buf:		Pointer to the data buffer
> > > + * @oob_required:	Caller requires OOB data read to chip->oob_poi
> > > + * @page:		Page number to read
> > > + *
> > > + * Return:	Always return zero
> > > + */
> > > +static int pl353_nand_read_page_raw(struct mtd_info *mtd,
> > > +				struct nand_chip *chip,
> > > +				uint8_t *buf, int oob_required, int page)
> > 
> > Do you really need raw accessors?
> Yes, when using on-die ecc, this function is getting called.
> i.e. nand_micron.c is calling nand_set_features_op, with DATA_OUT_INSTR, and there
> we are using this.

I don't see any link between doing a nad_set_features_op and calling a
raw accessor. It's almost like the ->read_byte() hook, if there is
nothing specific to implement, just forget about it, ->exec_op() is
probably enough.

> > > +/**
> > > + * pl353_nand_select_chip - Select the flash device
> > > + * @mtd:	Pointer to the mtd info structure
> > > + * @chip:	Pointer to the NAND chip info structure
> > > + *
> > > + * This function is empty as the NAND controller handles chip select
> > > +line
> > > + * internally based on the chip address passed in command and data phase.
> > > + */
> > > +static void pl353_nand_select_chip(struct mtd_info *mtd, int chip) {
> > > +}
> > > +
> > > +/* NAND framework ->exec_op() hooks and related helpers */ static
> > > +void pl353_nfc_parse_instructions(struct nand_chip *chip,
> > > +					   const struct nand_subop *subop,
> > > +					   struct pl353_nfc_op *nfc_op)
> > > +{
> > > +	const struct nand_op_instr *instr = NULL;
> > > +	unsigned int op_id, offset, naddrs;
> > > +	int i;
> > > +	const u8 *addrs;
> > > +
> > > +	memset(nfc_op, 0, sizeof(struct pl353_nfc_op));
> > > +	for (op_id = 0; op_id < subop->ninstrs; op_id++) {
> > > +
> > 
> > What is this for-loop for? I don't get it as you break the switch in every case?
> I think, breaking switch case only not for loop.

My bad, ok.

> > 
> > > +		nfc_op->len = nand_subop_get_data_len(subop, op_id);
> > > +
> > > +		instr = &subop->instrs[op_id];
> > > +		if (subop->ninstrs == 1)
> > > +			nfc_op->cmnds[0] = -1;
> > > +		switch (instr->type) {
> > > +		case NAND_OP_CMD_INSTR:
> > > +			nfc_op->type = NAND_OP_CMD_INSTR;
> > > +			nfc_op->end_cmd = op_id - 1;
> > > +			if (op_id)
> > 
> > You should put { } on the if also if the else statement needs braces.
> Ok, but I didn't see any warning from checkpatch.

Maybe with the --strict option?
Otherwise this is clearly stated in the kernel coding style
documentation.


> > > +static const struct nand_op_parser pl353_nfc_op_parser =
> > NAND_OP_PARSER(
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
> > > +		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
> > > +	 NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 8)),
> > > +	 NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
> > > +		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_ADDR_ELEM(false, 8),
> > > +		NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, 2048),
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(true),
> > > +		NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false),
> > > +		NAND_OP_PARSER_PAT_WAITRDY_ELEM(false)),
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_DATA_IN_ELEM(false, 2048)),
> > > +	NAND_OP_PARSER_PATTERN(
> > > +		pl353_nand_cmd_function,
> > > +		NAND_OP_PARSER_PAT_CMD_ELEM(false)),
> > 
> > I am pretty sure you can factorize all these patterns now. Use the "optional"
> > parameter for that.
> Can you explain little bit?  I didn't get.

All the patterns refer to the same function. This is fine.
But maybe you can factorize the parents using the "optional" parameter.
For example, if you have
* CMD + ADDR + DATA_IN
* CMD + DATA_IN
Maybe you can just state:
* CMD + [ADDR] + DATA_IN
With "[]" meaning the element is optional.


Thanks for addressing these comments.

Regards,
Miquèl

-- 
Miquel Raynal, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

  reply	other threads:[~2018-03-26 21:54 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-14 10:48 [LINUX PATCH v8 2/2] mtd: rawnand: pl353: Add basic driver for arm pl353 smc nand interface nagasureshkumarrelli
2018-03-19 22:37 ` Miquel Raynal
2018-03-23 14:58   ` Naga Sureshkumar Relli
2018-03-26 21:53     ` Miquel Raynal [this message]
2018-03-27  4:02       ` Naga Sureshkumar Relli
2018-04-06 19:22     ` Haris Okanovic
2018-04-22 15:17       ` Miquel Raynal
2018-04-24 10:18         ` Naga Sureshkumar Relli
2018-05-03 12:56 ` [LINUX, v8, " Helmut Grohne
2018-05-03 14:25   ` Miquel Raynal
2018-05-04  6:46     ` Naga Sureshkumar Relli
2018-05-17 13:24       ` Miquel Raynal
2018-05-18  7:33         ` Naga Sureshkumar Relli

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=20180326235359.39825dfd@xps13 \
    --to=miquel.raynal@bootlin.com \
    --cc=boris.brezillon@bootlin.com \
    --cc=computersforpeace@gmail.com \
    --cc=cyrille.pitchen@wedev4u.fr \
    --cc=dwmw2@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=marek.vasut@gmail.com \
    --cc=michals@xilinx.com \
    --cc=nagasure@xilinx.com \
    --cc=nagasureshkumarrelli@gmail.com \
    --cc=punnaia@xilinx.com \
    --cc=richard@nod.at \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.