[V2,2/6] nvmem: core: allow .read_post_process() callbacks to adjust buffer

Message ID 20230111073102.8147-2-zajec5@gmail.com
State New
Headers
Series [V2,1/6] nvmem: core: add nvmem_dev_size() helper |

Commit Message

Rafał Miłecki Jan. 11, 2023, 7:30 a.m. UTC
  From: Rafał Miłecki <rafal@milecki.pl>

Sometimes reading NVMEM cell value involves some data reformatting. it
may require resizing available buffer. Support that.

It's required e.g. to provide properly formatted MAC address in case
it's stored in a non-binary format (e.g. using ASCII).

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V2: Pass buffer pointer to allow krealloc() if needed
---
 drivers/nvmem/core.c             | 27 ++++++++++++++++-----------
 drivers/nvmem/imx-ocotp.c        |  8 ++++----
 drivers/nvmem/layouts/onie-tlv.c |  5 ++---
 drivers/nvmem/layouts/sl28vpd.c  | 10 +++++-----
 include/linux/nvmem-provider.h   |  5 ++---
 5 files changed, 29 insertions(+), 26 deletions(-)
  

Comments

kernel test robot Jan. 11, 2023, 11:07 a.m. UTC | #1
Hi Rafał,

I love your patch! Yet something to improve:

[auto build test ERROR on next-20230111]
[cannot apply to robh/for-next shawnguo/for-next mtd/mtd/next mtd/mtd/fixes linus/master v6.2-rc3 v6.2-rc2 v6.2-rc1 v6.2-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/Rafa-Mi-ecki/nvmem-core-allow-read_post_process-callbacks-to-adjust-buffer/20230111-153322
patch link:    https://lore.kernel.org/r/20230111073102.8147-2-zajec5%40gmail.com
patch subject: [PATCH V2 2/6] nvmem: core: allow .read_post_process() callbacks to adjust buffer
config: arm64-randconfig-r002-20230110
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 8d9828ef5aa9688500657d36cd2aefbe12bbd162)
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
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/8feca4b80acb7b0d1d460fef6091ff48b54e60c6
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Rafa-Mi-ecki/nvmem-core-allow-read_post_process-callbacks-to-adjust-buffer/20230111-153322
        git checkout 8feca4b80acb7b0d1d460fef6091ff48b54e60c6
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/nvmem/

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

All error/warnings (new ones prefixed by >>):

>> drivers/nvmem/core.c:1916:45: error: incompatible pointer types passing 'int *' to parameter of type 'size_t *' (aka 'unsigned long *') [-Werror,-Wincompatible-pointer-types]
           rc = __nvmem_cell_read(nvmem, &cell, &buf, &cell.bytes, NULL, 0);
                                                      ^~~~~~~~~~~
   drivers/nvmem/core.c:1541:29: note: passing argument to parameter 'len' here
                                void **buf, size_t *len, const char *id, int index)
                                                    ^
>> drivers/nvmem/core.c:1920:9: warning: variable 'len' is uninitialized when used here [-Wuninitialized]
           return len;
                  ^~~
   drivers/nvmem/core.c:1903:13: note: initialize the variable 'len' to silence this warning
           ssize_t len;
                      ^
                       = 0
   1 warning and 1 error generated.


vim +1916 drivers/nvmem/core.c

  1887	
  1888	/**
  1889	 * nvmem_device_cell_read() - Read a given nvmem device and cell
  1890	 *
  1891	 * @nvmem: nvmem device to read from.
  1892	 * @info: nvmem cell info to be read.
  1893	 * @buf: buffer pointer which will be populated on successful read.
  1894	 *
  1895	 * Return: length of successful bytes read on success and negative
  1896	 * error code on error.
  1897	 */
  1898	ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
  1899				   struct nvmem_cell_info *info, void *buf)
  1900	{
  1901		struct nvmem_cell_entry cell;
  1902		int rc;
  1903		ssize_t len;
  1904	
  1905		if (!nvmem)
  1906			return -EINVAL;
  1907	
  1908		/* Cells with read_post_process hook may realloc buffer we can't allow here */
  1909		if (info->read_post_process)
  1910			return -EINVAL;
  1911	
  1912		rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell);
  1913		if (rc)
  1914			return rc;
  1915	
> 1916		rc = __nvmem_cell_read(nvmem, &cell, &buf, &cell.bytes, NULL, 0);
  1917		if (rc)
  1918			return rc;
  1919	
> 1920		return len;
  1921	}
  1922	EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
  1923
  

Patch

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 32f7fb81375a..2c9e4ac8a772 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -1539,29 +1539,26 @@  static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void
 
 static int __nvmem_cell_read(struct nvmem_device *nvmem,
 			     struct nvmem_cell_entry *cell,
-			     void *buf, size_t *len, const char *id, int index)
+			     void **buf, size_t *len, const char *id, int index)
 {
 	int rc;
 
-	rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes);
+	rc = nvmem_reg_read(nvmem, cell->offset, *buf, *len);
 
 	if (rc)
 		return rc;
 
 	/* shift bits in-place */
 	if (cell->bit_offset || cell->nbits)
-		nvmem_shift_read_buffer_in_place(cell, buf);
+		nvmem_shift_read_buffer_in_place(cell, *buf);
 
 	if (cell->read_post_process) {
 		rc = cell->read_post_process(cell->priv, id, index,
-					     cell->offset, buf, cell->bytes);
+					     cell->offset, buf, len);
 		if (rc)
 			return rc;
 	}
 
-	if (len)
-		*len = cell->bytes;
-
 	return 0;
 }
 
@@ -1578,22 +1575,26 @@  static int __nvmem_cell_read(struct nvmem_device *nvmem,
 void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
 {
 	struct nvmem_device *nvmem = cell->entry->nvmem;
-	u8 *buf;
+	size_t bytes = cell->entry->bytes;
+	void *buf;
 	int rc;
 
 	if (!nvmem)
 		return ERR_PTR(-EINVAL);
 
-	buf = kzalloc(cell->entry->bytes, GFP_KERNEL);
+	buf = kzalloc(bytes, GFP_KERNEL);
 	if (!buf)
 		return ERR_PTR(-ENOMEM);
 
-	rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index);
+	rc = __nvmem_cell_read(nvmem, cell->entry, &buf, &bytes, cell->id, cell->index);
 	if (rc) {
 		kfree(buf);
 		return ERR_PTR(rc);
 	}
 
+	if (len)
+		*len = bytes;
+
 	return buf;
 }
 EXPORT_SYMBOL_GPL(nvmem_cell_read);
@@ -1905,11 +1906,15 @@  ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
 	if (!nvmem)
 		return -EINVAL;
 
+	/* Cells with read_post_process hook may realloc buffer we can't allow here */
+	if (info->read_post_process)
+		return -EINVAL;
+
 	rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell);
 	if (rc)
 		return rc;
 
-	rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0);
+	rc = __nvmem_cell_read(nvmem, &cell, &buf, &cell.bytes, NULL, 0);
 	if (rc)
 		return rc;
 
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index ac0edb6398f1..e17500bc0acc 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -223,15 +223,15 @@  static int imx_ocotp_read(void *context, unsigned int offset,
 }
 
 static int imx_ocotp_cell_pp(void *context, const char *id, int index,
-			     unsigned int offset, void *data, size_t bytes)
+			     unsigned int offset, void **data, size_t *bytes)
 {
-	u8 *buf = data;
+	u8 *buf = *data;
 	int i;
 
 	/* Deal with some post processing of nvmem cell data */
 	if (id && !strcmp(id, "mac-address"))
-		for (i = 0; i < bytes / 2; i++)
-			swap(buf[i], buf[bytes - i - 1]);
+		for (i = 0; i < *bytes / 2; i++)
+			swap(buf[i], buf[*bytes - i - 1]);
 
 	return 0;
 }
diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c
index 767f39fff717..f26bcce2a44d 100644
--- a/drivers/nvmem/layouts/onie-tlv.c
+++ b/drivers/nvmem/layouts/onie-tlv.c
@@ -75,10 +75,9 @@  static const char *onie_tlv_cell_name(u8 type)
 }
 
 static int onie_tlv_mac_read_cb(void *priv, const char *id, int index,
-				unsigned int offset, void *buf,
-				size_t bytes)
+				unsigned int offset, void **buf, size_t *bytes)
 {
-	eth_addr_add(buf, index);
+	eth_addr_add(*buf, index);
 
 	return 0;
 }
diff --git a/drivers/nvmem/layouts/sl28vpd.c b/drivers/nvmem/layouts/sl28vpd.c
index a36800f201a3..869cb513d79a 100644
--- a/drivers/nvmem/layouts/sl28vpd.c
+++ b/drivers/nvmem/layouts/sl28vpd.c
@@ -22,19 +22,19 @@  struct sl28vpd_v1 {
 } __packed;
 
 static int sl28vpd_mac_address_pp(void *priv, const char *id, int index,
-				  unsigned int offset, void *buf,
-				  size_t bytes)
+				  unsigned int offset, void **buf,
+				  size_t *bytes)
 {
-	if (bytes != ETH_ALEN)
+	if (*bytes != ETH_ALEN)
 		return -EINVAL;
 
 	if (index < 0)
 		return -EINVAL;
 
-	if (!is_valid_ether_addr(buf))
+	if (!is_valid_ether_addr(*buf))
 		return -EINVAL;
 
-	eth_addr_add(buf, index);
+	eth_addr_add(*buf, index);
 
 	return 0;
 }
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 0cf9f9490514..e70766013f97 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -19,9 +19,8 @@  typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
 typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
 				 void *val, size_t bytes);
 /* used for vendor specific post processing of cell data */
-typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int index,
-					 unsigned int offset, void *buf,
-					 size_t bytes);
+typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int index, unsigned int offset,
+					 void **buf, size_t *bytes);
 
 enum nvmem_type {
 	NVMEM_TYPE_UNKNOWN = 0,