On 28.09.26 01:57, Mikhail Kshevetskiy wrote:
> From: Miquel Raynal <[email protected]>
>
> In some situations, direct mappings may need to use different
> operation templates.
>
> For instance, when enabling continuous reads, Winbond SPI NANDs no
> longer expect address cycles because they would be ignoring them
> otherwise. Hence, right after the command opcode, they start counting
> dummy cycles, followed by the data cycles as usual.
>
> This breaks the assumptions of "reads from cache" always being done
> identically once the best variant has been picked up, across the
> lifetime of the system.
>
> In order to support this feature, we must give direct mapping more than
> a single operation template to use, in order to switch to using
> secondary operations upon request by the upper layer.
>
> Create the concept of optional secondary operation template, which may
> or may not be fulfilled by the SPI NAND and SPI NOR cores. If the
> underlying SPI controller does not leverage any kind of direct mapping
> acceleration, the feature has no impact and can be freely
> used. Otherwise, the controller driver needs to opt-in for using this
> feature, if supported.
>
> The condition checked to know whether a secondary operation has been
> provided or not is to look for a non zero opcode to limit the creation
> of extra variables. In practice, the opcode 0x00 exist, but is not
> related to any cache related operation.
>
> Acked-by: Mark Brown <[email protected]>
> Signed-off-by: Miquel Raynal <[email protected]>
> [Linux commit: 6f96f2fa152518d93ffeedbea781db50aef7f7dc]
> Signed-off-by: Mikhail Kshevetskiy <[email protected]>
> ---
> drivers/spi/spi-mem.c | 17 +++++++++++++++++
> include/spi-mem.h | 5 +++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> index 351ca725524..ae393ca48bc 100644
> --- a/drivers/spi/spi-mem.c
> +++ b/drivers/spi/spi-mem.c
> @@ -639,6 +639,23 @@ spi_mem_dirmap_create(struct spi_slave *slave,
> if (info->primary_op_tmpl.data.dir == SPI_MEM_NO_DATA)
> return ERR_PTR(-EINVAL);
>
> + /* Apply similar constraints to the secondary template */
> + if (info->secondary_op_tmpl.cmd.opcode) {
> + if (!info->secondary_op_tmpl.addr.nbytes ||
> + info->secondary_op_tmpl.addr.nbytes > 8)
> + return ERR_PTR(-EINVAL);
> +
> + if (info->secondary_op_tmpl.data.dir == SPI_MEM_NO_DATA)
> + return ERR_PTR(-EINVAL);
> +
> + if (!spi_mem_supports_op(desc->slave, &info->secondary_op_tmpl))
You are accessing desc here where it is still uninitialized.
> + return ERR_PTR(-EOPNOTSUPP);
> +
> + if (ops->mem_ops && ops->mem_ops->dirmap_create &&
> + !spi_mem_controller_is_capable(ops, secondary_op_tmpl))
> + return ERR_PTR(-EOPNOTSUPP);
> + }
> +
> desc = kzalloc(sizeof(*desc), GFP_KERNEL);
> if (!desc)
> return ERR_PTR(-ENOMEM);
> diff --git a/include/spi-mem.h b/include/spi-mem.h
> index 81166492da2..08d854b1e52 100644
> --- a/include/spi-mem.h
> +++ b/include/spi-mem.h
> @@ -201,6 +201,8 @@ struct spi_mem_op {
> * struct spi_mem_dirmap_info - Direct mapping information
> * @op_tmpl: operation template that should be used by the direct mapping
> when
> * the memory device is accessed
> + * @secondary_op_tmpl: secondary template, may be used as an alternative to
> the
> + * primary template (decided by the upper layer)
> * @offset: absolute offset this direct mapping is pointing to
> * @length: length in byte of this direct mapping
> *
> @@ -213,6 +215,7 @@ struct spi_mem_op {
> struct spi_mem_dirmap_info {
> struct spi_mem_op *op_tmpl;
> struct spi_mem_op primary_op_tmpl;
> + struct spi_mem_op secondary_op_tmpl;
> u64 offset;
> u64 length;
> };
> @@ -338,11 +341,13 @@ struct spi_controller_mem_ops {
> * @ecc: Supports operations with error correction
> * @swap16: Supports swapping bytes on a 16 bit boundary when configured in
> * Octal DTR
> + * @secondary_op_tmpl: Supports leveraging a secondary memory operation
> template
> */
> struct spi_controller_mem_caps {
> bool dtr;
> bool ecc;
> bool swap16;
> + bool secondary_op_tmpl;
> };
>
> #define spi_mem_controller_is_capable(spi_ops, cap) \