Re: [PATCH v2 1/2] mtd: spi-nor: Move m25p80 code in spi-nor.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, Boris,

On 07/25/2019 03:37 PM, Boris Brezillon wrote:
> External E-Mail
> 
> 
> On Thu, 25 Jul 2019 11:19:06 +0000
> <Tudor.Ambarus@xxxxxxxxxxxxx> wrote:
> 
>>> + */
>>> +static int spi_nor_exec_op(struct spi_nor *nor, struct spi_mem_op *op,
>>> +			   u64 *addr, void *buf, size_t len)
>>> +{
>>> +	int ret;
>>> +	bool usebouncebuf = false;  
>>
>> I don't think we need a bounce buffer for regs. What is the maximum size that we
>> read/write regs, SPI_NOR_MAX_CMD_SIZE(8)?
>>
>> In spi-nor.c the maximum length that we pass to nor->read_reg()/write_reg() is
>> SPI_NOR_MAX_ID_LEN(6).
>>
>> I can provide a patch to always use nor->cmd_buf when reading/writing regs so
>> you respin the series on top of it, if you feel the same.
>>
>> With nor->cmd_buf this function will be reduced to the following:
>>
>> static int spi_nor_spimem_xfer_reg(struct spi_nor *nor, struct spi_mem_op *op)
>> {
>> 	if (!op || (op->data.nbytes && !nor->cmd_buf))
>> 		return -EINVAL;
>>
>> 	return spi_mem_exec_op(nor->spimem, op);
>> }
> 
> Well, I don't think that's a good idea. ->cmd_buf is an array in the
> middle of the spi_nor struct, which means it won't be aligned on a
> cache line and you'll have to be extra careful not to touch the spi_nor
> fields when calling spi_mem_exec_op(). Might work, but I wouldn't take
> the risk if I were you.
> 

u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE] ____cacheline_aligned;

Does this help?

> Another option would be to allocate ->cmd_buf with kmalloc() instead of
> having it defined as a static array.
> 
>>
>> spi_nor_exec_op() always received a NULL addr, let's get rid of it. We won't
>> need buf anymore and you can retrieve the length from op->data.nbytes. Now that
>> we trimmed the arguments, I think I would get rid of the
>> spi_nor_data/nodata_op() wrappers and use spi_nor_spimem_xfer_reg() directly.
> 
> I think I added the addr param for a good reason (probably to support
> Octo mode cmds that take an address parameter). This being said, I
> agree with you, we should just pass everything through the op parameter
> (including the address if we ever need to add one).
> 
> 
>>> +
>>> +/**
>>> + * spi_nor_spimem_xfer_data() - helper function to read/write data to
>>> + *                              flash's memory region
>>> + * @nor:        pointer to 'struct spi_nor'
>>> + * @op:         pointer to 'struct spi_mem_op' template for transfer
>>> + * @proto:      protocol to be used for transfer
>>> + *
>>> + * Return: number of bytes transferred on success, -errno otherwise
>>> + */
>>> +static ssize_t spi_nor_spimem_xfer_data(struct spi_nor *nor,
>>> +					struct spi_mem_op *op,
>>> +					enum spi_nor_protocol proto)
>>> +{
>>> +	bool usebouncebuf = false;  
>>
>> declare bool at the end to avoid stack padding.
> 
> But it breaks the reverse-xmas-tree formatting :-).
> 
>>
>>> +	void *rdbuf = NULL;
>>> +	const void *buf;  
>>
>> you can get rid of rdbuf and buf if you pass buf as argument.
> 
> Hm, passing the buffer to send data from/receive data into is already
> part of the spi_mem_op definition process (which is done in the caller
> of this func) so why bother passing an extra arg to the function.
> Note that you had the exact opposite argument for the
> spi_nor_spimem_xfer_reg() prototype you suggested above (which I
> agree with BTW) :P.

In order to avoid if clauses like "if (op->data.dir == SPI_MEM_DATA_IN)". You
can't use op->data.buf directly, the *out const qualifier can be discarded.

pointer to buf was not needed in spi_nor_spimem_xfer_reg(), we could use
nor->cmd_buf.

> 
>>
>>> +	int ret;
>>> +
>>> +	/* get transfer protocols. */
>>> +	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
>>> +	op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto);
>>> +	op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
>>> +
>>> +	if (op->data.dir == SPI_MEM_DATA_IN)
>>> +		buf = op->data.buf.in;
>>> +	else
>>> +		buf = op->data.buf.out;
>>> +
>>> +	if (object_is_on_stack(buf) || !virt_addr_valid(buf))
>>> +		usebouncebuf = true;
>>> +
>>> +	if (usebouncebuf) {
>>> +		if (op->data.nbytes > nor->bouncebuf_size)
>>> +			op->data.nbytes = nor->bouncebuf_size;
>>> +
>>> +		if (op->data.dir == SPI_MEM_DATA_IN) {
>>> +			rdbuf = op->data.buf.in;
>>> +			op->data.buf.in = nor->bouncebuf;
>>> +		} else {
>>> +			op->data.buf.out = nor->bouncebuf;
>>> +			memcpy(nor->bouncebuf, buf,
>>> +			       op->data.nbytes);
>>> +		}
>>> +	}
>>> +
>>> +	ret = spi_mem_adjust_op_size(nor->spimem, op);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = spi_mem_exec_op(nor->spimem, op);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	if (usebouncebuf && op->data.dir == SPI_MEM_DATA_IN)
>>> +		memcpy(rdbuf, nor->bouncebuf, op->data.nbytes);
>>> +
>>> +	return op->data.nbytes;
>>> +}
>>> +
>>> +/**
>>> + * spi_nor_spimem_read_data() - read data from flash's memory region via
>>> + *                              spi-mem
>>> + * @nor:        pointer to 'struct spi_nor'
>>> + * @ofs:        offset to read from
>>> + * @len:        number of bytes to read
>>> + * @buf:        pointer to dst buffer
>>> + *
>>> + * Return: number of bytes read successfully, -errno otherwise
>>> + */
>>> +static ssize_t spi_nor_spimem_read_data(struct spi_nor *nor, loff_t ofs,  
>>
>> s/ofs/from? both flash and buf may have offsets, "from" better indicates that
>> the offset is associated with the flash.
> 
> The semantic is well documented in the doc just above the function, but
> I have the feeling that you're in 'nitpick' mode, so I'll just let you
> pick the one you prefer :).

Not my intention. struct mtd_info and struct spi_nor use "from" when referring
to the offset from where to read in the read() calls. Just consistency reasons.

Cheers,
ta
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/



[Index of Archives]     [LARTC]     [Bugtraq]     [Yosemite Forum]     [Photo]

  Powered by Linux