Skip to content

Commit 226d6cb

Browse files
miquelraynalbroonie
authored andcommitted
spi: spi-mem: Estimate the time taken by operations
In the SPI-NAND layer, we currently make list of operation variants from the fastest one to the slowest and there is a bit of logic in the core to go over them and pick the first one that is supported by the controller, ie. the fastest one among the supported ops. This kind of logic only works if all operations run at the same frequency, but as soon as we introduce per operation max frequencies it is not longer as obvious which operation will be faster, especially since it also depends on the PCB/controller frequency limitation. One way to make this choice more clever is to go over all the variants and for each of them derive an indicator which will help derive the theoretical best. In this case, we derive a theoretical duration for the entire operation and we take the smallest one. Add a helper that parses the spi-mem operation and returns this value. Signed-off-by: Miquel Raynal <[email protected]> Link: https://patch.msgid.link/20250110-winbond-6-11-rc1-quad-support-v3-20-7ab4bd56cf6e@bootlin.com Signed-off-by: Mark Brown <[email protected]>
1 parent f000689 commit 226d6cb

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

drivers/spi/spi-mem.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,36 @@ void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
562562
}
563563
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
564564

565+
/**
566+
* spi_mem_calc_op_duration() - Derives the theoretical length (in ns) of an
567+
* operation. This helps finding the best variant
568+
* among a list of possible choices.
569+
* @op: the operation to benchmark
570+
*
571+
* Some chips have per-op frequency limitations, PCBs usually have their own
572+
* limitations as well, and controllers can support dual, quad or even octal
573+
* modes, sometimes in DTR. All these combinations make it impossible to
574+
* statically list the best combination for all situations. If we want something
575+
* accurate, all these combinations should be rated (eg. with a time estimate)
576+
* and the best pick should be taken based on these calculations.
577+
*
578+
* Returns a ns estimate for the time this op would take.
579+
*/
580+
u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
581+
{
582+
u64 ncycles = 0;
583+
u32 ns_per_cycles;
584+
585+
ns_per_cycles = 1000000000 / op->max_freq;
586+
ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1);
587+
ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1);
588+
ncycles += ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
589+
ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
590+
591+
return ncycles * ns_per_cycles;
592+
}
593+
EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
594+
565595
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
566596
u64 offs, size_t len, void *buf)
567597
{

include/linux/spi/spi-mem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
424424

425425
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
426426
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op);
427+
u64 spi_mem_calc_op_duration(struct spi_mem_op *op);
427428

428429
bool spi_mem_supports_op(struct spi_mem *mem,
429430
const struct spi_mem_op *op);

0 commit comments

Comments
 (0)