diff mbox series

[8/8] spi: wpcm-fiu: Add direct map support

Message ID 20221105185911.1547847-9-j.neuschaefer@gmx.net
State New
Headers show
Series Nuvoton WPCM450 FIU SPI flash controller | expand

Commit Message

J. Neuschäfer Nov. 5, 2022, 6:59 p.m. UTC
Besides software controlled SPI transfers (UMA, "user mode access"), FIU
also supports a 16 MiB mapping window per attached flash chip.

This patch implements direct mapped read access, to speed up flash reads.


Without direct mapping:

	# time dd if=/dev/mtd0ro of=dump bs=1M
	16+0 records in
	16+0 records out
	real    1m 47.74s
	user    0m 0.00s
	sys     1m 47.75s


With direct mapping:

	# time dd if=/dev/mtd0ro of=dump bs=1M
	16+0 records in
	16+0 records out
	real    0m 30.81s
	user    0m 0.00s
	sys     0m 30.81s

Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
---
 drivers/spi/spi-wpcm-fiu.c | 64 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

--
2.35.1

Comments

kernel test robot Nov. 5, 2022, 9:35 p.m. UTC | #1
Hi Jonathan,

I love your patch! Yet something to improve:

[auto build test ERROR on next-20221104]
[cannot apply to broonie-spi/for-next linusw-pinctrl/devel robh/for-next v6.1-rc3 v6.1-rc2 v6.1-rc1 linus/master v6.1-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Jonathan-Neusch-fer/Nuvoton-WPCM450-FIU-SPI-flash-controller/20221106-030021
patch link:    https://lore.kernel.org/r/20221105185911.1547847-9-j.neuschaefer%40gmx.net
patch subject: [PATCH 8/8] spi: wpcm-fiu: Add direct map support
config: alpha-allyesconfig
compiler: alpha-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/8f83cce55d2b39c9b8934c262a8d01eeebfc5ccc
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Jonathan-Neusch-fer/Nuvoton-WPCM450-FIU-SPI-flash-controller/20221106-030021
        git checkout 8f83cce55d2b39c9b8934c262a8d01eeebfc5ccc
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/spi/spi-wpcm-fiu.c:424:24: error: initialization of 'ssize_t (*)(struct spi_mem_dirmap_desc *, u64,  size_t,  void *)' {aka 'long int (*)(struct spi_mem_dirmap_desc *, long long unsigned int,  long unsigned int,  void *)'} from incompatible pointer type 'int (*)(struct spi_mem_dirmap_desc *, u64,  size_t,  void *)' {aka 'int (*)(struct spi_mem_dirmap_desc *, long long unsigned int,  long unsigned int,  void *)'} [-Werror=incompatible-pointer-types]
     424 |         .dirmap_read = wpcm_fiu_direct_read,
         |                        ^~~~~~~~~~~~~~~~~~~~
   drivers/spi/spi-wpcm-fiu.c:424:24: note: (near initialization for 'wpcm_fiu_mem_ops.dirmap_read')
   cc1: some warnings being treated as errors


vim +424 drivers/spi/spi-wpcm-fiu.c

   418	
   419	static const struct spi_controller_mem_ops wpcm_fiu_mem_ops = {
   420		.adjust_op_size = wpcm_fiu_adjust_op_size,
   421		.supports_op = wpcm_fiu_supports_op,
   422		.exec_op = wpcm_fiu_exec_op,
   423		.dirmap_create = wpcm_fiu_dirmap_create,
 > 424		.dirmap_read = wpcm_fiu_direct_read,
   425	};
   426
J. Neuschäfer Nov. 6, 2022, 2:49 p.m. UTC | #2
On Sun, Nov 06, 2022 at 05:35:24AM +0800, kernel test robot wrote:
> >> drivers/spi/spi-wpcm-fiu.c:424:24: error: initialization of 'ssize_t (*)(struct spi_mem_dirmap_desc *, u64,  size_t,  void *)' {aka 'long int (*)(struct spi_mem_dirmap_desc *, long long unsigned int,  long unsigned int,  void *)'} from incompatible pointer type 'int (*)(struct spi_mem_dirmap_desc *, u64,  size_t,  void *)' {aka 'int (*)(struct spi_mem_dirmap_desc *, long long unsigned int,  long unsigned int,  void *)'} [-Werror=incompatible-pointer-types]
>      424 |         .dirmap_read = wpcm_fiu_direct_read,
>          |                        ^~~~~~~~~~~~~~~~~~~~
>    drivers/spi/spi-wpcm-fiu.c:424:24: note: (near initialization for 'wpcm_fiu_mem_ops.dirmap_read')
>    cc1: some warnings being treated as errors

Indeed. I'll fix it.
diff mbox series

Patch

diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c
index d68693d4cd8bd..eda46c766ad9d 100644
--- a/drivers/spi/spi-wpcm-fiu.c
+++ b/drivers/spi/spi-wpcm-fiu.c
@@ -51,10 +51,16 @@ 
  */
 #define UMA_WAIT_ITERATIONS 100

+/* The memory-mapped view of flash is 16 MiB long */
+#define MAX_MEMORY_SIZE_PER_CS	(16 << 20)
+#define MAX_MEMORY_SIZE_TOTAL	(4 * MAX_MEMORY_SIZE_PER_CS)
+
 struct wpcm_fiu_spi {
 	struct device *dev;
 	struct clk *clk;
 	void __iomem *regs;
+	void __iomem *memory;
+	size_t memory_size;
 	struct regmap *shm_regmap;
 };

@@ -367,14 +373,64 @@  static int wpcm_fiu_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
 	return 0;
 }

+static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller);
+	int cs = desc->mem->spi->chip_select;
+
+	if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+		return -ENOTSUPP;
+
+	/*
+	 * Unfortunately, FIU only supports a 16 MiB direct mapping window (per
+	 * attached flash chip), but the SPI MEM core doesn't support partial
+	 * direct mappings. This means that we can't support direct mapping on
+	 * flashes that are bigger than 16 MiB.
+	 */
+	if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS)
+		return -ENOTSUPP;
+
+	/* Don't read past the memory window */
+	if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size)
+		return -ENOTSUPP;
+
+	return 0;
+}
+
+static int wpcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf)
+{
+	struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller);
+	int cs = desc->mem->spi->chip_select;
+
+	if (offs >= MAX_MEMORY_SIZE_PER_CS)
+		return -ENOTSUPP;
+
+	offs += cs * MAX_MEMORY_SIZE_PER_CS;
+
+	if (!fiu->memory || offs >= fiu->memory_size)
+		return -ENOTSUPP;
+
+	len = min_t(size_t, len, fiu->memory_size - offs);
+	memcpy_fromio(buf, fiu->memory + offs, len);
+
+	return len;
+}
+
 static const struct spi_controller_mem_ops wpcm_fiu_mem_ops = {
 	.adjust_op_size = wpcm_fiu_adjust_op_size,
 	.supports_op = wpcm_fiu_supports_op,
 	.exec_op = wpcm_fiu_exec_op,
+	.dirmap_create = wpcm_fiu_dirmap_create,
+	.dirmap_read = wpcm_fiu_direct_read,
 };

 static void wpcm_fiu_hw_init(struct wpcm_fiu_spi *fiu)
 {
+	/* Configure memory-mapped flash access */
+	writeb(FIU_BURST_CFG_R16, fiu->regs + FIU_BURST_BFG);
+	writeb(MAX_MEMORY_SIZE_TOTAL / (512 << 10), fiu->regs + FIU_CFG);
+	writeb(MAX_MEMORY_SIZE_PER_CS / (512 << 10) | BIT(6), fiu->regs + FIU_SPI_FL_CFG);
+
 	/* Deassert all manually asserted chip selects */
 	writeb(0x0f, fiu->regs + FIU_UMA_ECTS);
 }
@@ -404,6 +460,14 @@  static int wpcm_fiu_probe(struct platform_device *pdev)
 	if (IS_ERR(fiu->clk))
 		return PTR_ERR(fiu->clk);

+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
+	fiu->memory = devm_ioremap_resource(dev, res);
+	fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
+	if (IS_ERR(fiu->regs)) {
+		dev_err(dev, "Failed to map flash memory window\n");
+		return PTR_ERR(fiu->memory);
+	}
+
 	fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm");

 	wpcm_fiu_hw_init(fiu);