Message ID | 20211222192320.21974-3-zajec5@gmail.com |
---|---|
State | Changes Requested |
Headers | show |
Series | [1/3] mtd: core: call devm_of_platform_populate() for MTD devices | expand |
Hi "Rafał, I love your patch! Yet something to improve: [auto build test ERROR on robh/for-next] [also build test ERROR on mtd/mtd/next mtd/mtd/fixes linus/master v5.16-rc7 next-20211224] [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] url: https://github.com/0day-ci/linux/commits/Rafa-Mi-ecki/mtd-core-call-devm_of_platform_populate-for-MTD-devices/20211223-032456 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next config: riscv-randconfig-c006-20211227 (https://download.01.org/0day-ci/archive/20211227/202112271307.07oSwFJV-lkp@intel.com/config) compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 511726c64d3b6cca66f7c54d457d586aa3129f67) 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 riscv cross compiling tool for clang build # apt-get install binutils-riscv64-linux-gnu # https://github.com/0day-ci/linux/commit/43acf8c3e5ac48785826453744a925ff149b1d60 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Rafa-Mi-ecki/mtd-core-call-devm_of_platform_populate-for-MTD-devices/20211223-032456 git checkout 43acf8c3e5ac48785826453744a925ff149b1d60 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash drivers/nvmem/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>): >> drivers/nvmem/u-boot-env.c:126:46: warning: format specifies type 'unsigned int' but the argument has type 'size_t' (aka 'unsigned long') [-Wformat] dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len); ~~~~ ^~~~~~~~~~~~ %08lx include/linux/dev_printk.h:150:67: note: expanded from macro 'dev_info' dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__) ~~~ ^~~~~~~~~~~ include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap' _p_func(dev, fmt, ##__VA_ARGS__); \ ~~~ ^~~~~~~~~~~ drivers/nvmem/u-boot-env.c:126:60: warning: format specifies type 'unsigned int' but the argument has type 'size_t' (aka 'unsigned long') [-Wformat] dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len); ~~~~ ^~~~~~~~~ %08lx include/linux/dev_printk.h:150:67: note: expanded from macro 'dev_info' dev_printk_index_wrap(_dev_info, KERN_INFO, dev, dev_fmt(fmt), ##__VA_ARGS__) ~~~ ^~~~~~~~~~~ include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap' _p_func(dev, fmt, ##__VA_ARGS__); \ ~~~ ^~~~~~~~~~~ >> drivers/nvmem/u-boot-env.c:190:38: error: incompatible pointer types passing 'size_t *' (aka 'unsigned long *') to parameter of type 'u32 *' (aka 'unsigned int *') [-Werror,-Wincompatible-pointer-types] if (of_property_read_u32(np, "reg", &priv->offset) || ^~~~~~~~~~~~~ include/linux/of.h:1255:17: note: passing argument to parameter 'out_value' here u32 *out_value) ^ drivers/nvmem/u-boot-env.c:191:47: error: incompatible pointer types passing 'size_t *' (aka 'unsigned long *') to parameter of type 'u32 *' (aka 'unsigned int *') [-Werror,-Wincompatible-pointer-types] of_property_read_u32_index(np, "reg", 1, &priv->size)) { ^~~~~~~~~~~ include/linux/of.h:311:28: note: passing argument to parameter 'out_value' here u32 index, u32 *out_value); ^ 2 warnings and 2 errors generated. vim +190 drivers/nvmem/u-boot-env.c 99 100 static int u_boot_env_parse(struct u_boot_env *priv) 101 { 102 struct device *dev = priv->dev; 103 struct u_boot_env_image *image; 104 size_t image_offset; 105 size_t image_len; 106 uint32_t crc32; 107 size_t bytes; 108 uint8_t *buf; 109 int err; 110 111 image_offset = 0; 112 image_len = priv->size; 113 if (priv->format == U_BOOT_FORMAT_BRCM) { 114 struct u_boot_brcm_header header; 115 116 err = mtd_read(priv->mtd, priv->offset, sizeof(header), &bytes, 117 (uint8_t *)&header); 118 if (err && !mtd_is_bitflip(err)) { 119 dev_err(dev, "Failed to read from mtd: %d\n", err); 120 return err; 121 } 122 123 image_offset = sizeof(header); 124 image_len = le32_to_cpu(header.len); 125 } > 126 dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len); 127 128 buf = kcalloc(1, image_len, GFP_KERNEL); 129 if (!buf) { 130 err = -ENOMEM; 131 goto err_out; 132 } 133 image = (struct u_boot_env_image *)buf; 134 135 err = mtd_read(priv->mtd, priv->offset + image_offset, image_len, &bytes, buf); 136 if (err && !mtd_is_bitflip(err)) { 137 dev_err(dev, "Failed to read from mtd: %d\n", err); 138 goto err_kfree; 139 } 140 141 crc32 = crc32(~0, buf + 4, image_len - 4) ^ ~0L; 142 if (crc32 != le32_to_cpu(image->crc32)) { 143 dev_err(dev, "Invalid calculated CRC32: 0x%08x\n", crc32); 144 err = -EINVAL; 145 goto err_kfree; 146 } 147 148 buf[image_len - 1] = '\0'; 149 err = u_boot_env_add_cells(priv, image_offset + sizeof(*image), 150 buf + sizeof(*image), 151 image_len - sizeof(*image)); 152 if (err) 153 dev_err(dev, "Failed to add cells: %d\n", err); 154 155 err_kfree: 156 kfree(buf); 157 err_out: 158 return err; 159 } 160 161 static const struct of_device_id u_boot_env_of_match_table[] = { 162 { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_DEFAULT, }, 163 { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BRCM, }, 164 {}, 165 }; 166 167 static int u_boot_env_probe(struct platform_device *pdev) 168 { 169 struct nvmem_config config = { 170 .name = "u-boot-env", 171 .reg_read = u_boot_env_read, 172 }; 173 struct device *dev = &pdev->dev; 174 struct device_node *np = dev->of_node; 175 const struct of_device_id *of_id; 176 struct u_boot_env *priv; 177 const char *label; 178 int err; 179 180 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 181 if (!priv) 182 return -ENOMEM; 183 priv->dev = dev; 184 185 of_id = of_match_device(u_boot_env_of_match_table, dev); 186 if (!of_id) 187 return -EINVAL; 188 priv->format = (uintptr_t)of_id->data; 189 > 190 if (of_property_read_u32(np, "reg", &priv->offset) || 191 of_property_read_u32_index(np, "reg", 1, &priv->size)) { 192 dev_err(dev, "Failed to read \"reg\" property\n"); 193 return -EINVAL; 194 } 195 196 label = of_get_property(np->parent, "label", NULL); 197 if (!label) 198 label = np->parent->name; 199 200 priv->mtd = get_mtd_device_nm(label); 201 if (IS_ERR(priv->mtd)) { 202 dev_err(dev, "Failed to find \"%s\" MTD device: %ld\n", label, PTR_ERR(priv->mtd)); 203 return PTR_ERR(priv->mtd); 204 } 205 206 err = u_boot_env_parse(priv); 207 if (err) 208 return err; 209 210 config.dev = dev; 211 config.cells = priv->cells; 212 config.ncells = priv->ncells; 213 config.priv = priv; 214 config.size = priv->size; 215 216 return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); 217 } 218 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/MAINTAINERS b/MAINTAINERS index 271c29c84c7d..cc9bdeb33b64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19628,6 +19628,7 @@ U-BOOT ENVIRONMENT VARIABLES M: Rafał Miłecki <rafal@milecki.pl> S: Maintained F: Documentation/devicetree/bindings/nvmem/u-boot,env.yaml +F: drivers/nvmem/u-boot-env.c UACCE ACCELERATOR FRAMEWORK M: Zhangfei Gao <zhangfei.gao@linaro.org> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index da414617a54d..af9115852412 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -300,4 +300,14 @@ config NVMEM_BRCM_NVRAM This driver provides support for Broadcom's NVRAM that can be accessed using I/O mapping. +config NVMEM_U_BOOT_ENV + tristate "U-Boot environment variables support" + depends on ARCH_BCM4908 || COMPILE_TEST + depends on OF + help + This driver adds support for parsing U-Boot environment variables + stored on flash partition. + + If compiled as module it will be called nvmem_u-boot-env. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index dcbbde35b6a8..772904cdebdb 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -61,3 +61,5 @@ obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o nvmem-rmem-y := rmem.o obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o nvmem_brcm_nvram-y := brcm_nvram.o +obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o +nvmem_u-boot-env-y := u-boot-env.o diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c new file mode 100644 index 000000000000..a932b3d3c63b --- /dev/null +++ b/drivers/nvmem/u-boot-env.c @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl> + */ + +#include <linux/crc32.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/nvmem-consumer.h> +#include <linux/nvmem-provider.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +enum u_boot_env_format { + U_BOOT_FORMAT_DEFAULT, + U_BOOT_FORMAT_BRCM, +}; + +struct u_boot_env { + struct device *dev; + enum u_boot_env_format format; + struct mtd_info *mtd; + size_t offset; + size_t size; + struct nvmem_cell_info *cells; + int ncells; +}; + +struct u_boot_env_image { + __le32 crc32; + uint8_t data[0]; +} __packed; + +struct u_boot_brcm_header { + __le32 unk; + __le32 len; +} __packed; + +static int u_boot_env_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct u_boot_env *priv = context; + struct device *dev = priv->dev; + size_t bytes_read; + int err; + + err = mtd_read(priv->mtd, priv->offset + offset, bytes, &bytes_read, val); + if (err && !mtd_is_bitflip(err)) { + dev_err(dev, "Failed to read from mtd: %d\n", err); + return err; + } + + if (bytes_read != bytes) { + dev_err(dev, "Failed to read %zd bytes\n", bytes); + return err; + } + + return 0; +} + +static int u_boot_env_add_cells(struct u_boot_env *priv, size_t data_offset, + uint8_t *data, size_t len) +{ + struct device *dev = priv->dev; + char *var, *value, *eq; + int idx; + + priv->ncells = 0; + for (var = data; var < (char *)data + len && *var; var += strlen(var) + 1) + priv->ncells++; + + priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL); + if (!priv->cells) + return -ENOMEM; + + for (var = data, idx = 0; + var < (char *)data + len && *var; + var = value + strlen(value) + 1, idx++) { + eq = strchr(var, '='); + if (!eq) + break; + *eq = '\0'; + value = eq + 1; + + priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL); + if (!priv->cells[idx].name) + return -ENOMEM; + priv->cells[idx].offset = data_offset + value - (char *)data; + priv->cells[idx].bytes = strlen(value); + } + + if (WARN_ON(idx != priv->ncells)) + priv->ncells = idx; + + return 0; +} + +static int u_boot_env_parse(struct u_boot_env *priv) +{ + struct device *dev = priv->dev; + struct u_boot_env_image *image; + size_t image_offset; + size_t image_len; + uint32_t crc32; + size_t bytes; + uint8_t *buf; + int err; + + image_offset = 0; + image_len = priv->size; + if (priv->format == U_BOOT_FORMAT_BRCM) { + struct u_boot_brcm_header header; + + err = mtd_read(priv->mtd, priv->offset, sizeof(header), &bytes, + (uint8_t *)&header); + if (err && !mtd_is_bitflip(err)) { + dev_err(dev, "Failed to read from mtd: %d\n", err); + return err; + } + + image_offset = sizeof(header); + image_len = le32_to_cpu(header.len); + } + dev_info(dev, "offset:0x%08x len:0x%08x\n", image_offset, image_len); + + buf = kcalloc(1, image_len, GFP_KERNEL); + if (!buf) { + err = -ENOMEM; + goto err_out; + } + image = (struct u_boot_env_image *)buf; + + err = mtd_read(priv->mtd, priv->offset + image_offset, image_len, &bytes, buf); + if (err && !mtd_is_bitflip(err)) { + dev_err(dev, "Failed to read from mtd: %d\n", err); + goto err_kfree; + } + + crc32 = crc32(~0, buf + 4, image_len - 4) ^ ~0L; + if (crc32 != le32_to_cpu(image->crc32)) { + dev_err(dev, "Invalid calculated CRC32: 0x%08x\n", crc32); + err = -EINVAL; + goto err_kfree; + } + + buf[image_len - 1] = '\0'; + err = u_boot_env_add_cells(priv, image_offset + sizeof(*image), + buf + sizeof(*image), + image_len - sizeof(*image)); + if (err) + dev_err(dev, "Failed to add cells: %d\n", err); + +err_kfree: + kfree(buf); +err_out: + return err; +} + +static const struct of_device_id u_boot_env_of_match_table[] = { + { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_DEFAULT, }, + { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BRCM, }, + {}, +}; + +static int u_boot_env_probe(struct platform_device *pdev) +{ + struct nvmem_config config = { + .name = "u-boot-env", + .reg_read = u_boot_env_read, + }; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct of_device_id *of_id; + struct u_boot_env *priv; + const char *label; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = dev; + + of_id = of_match_device(u_boot_env_of_match_table, dev); + if (!of_id) + return -EINVAL; + priv->format = (uintptr_t)of_id->data; + + if (of_property_read_u32(np, "reg", &priv->offset) || + of_property_read_u32_index(np, "reg", 1, &priv->size)) { + dev_err(dev, "Failed to read \"reg\" property\n"); + return -EINVAL; + } + + label = of_get_property(np->parent, "label", NULL); + if (!label) + label = np->parent->name; + + priv->mtd = get_mtd_device_nm(label); + if (IS_ERR(priv->mtd)) { + dev_err(dev, "Failed to find \"%s\" MTD device: %ld\n", label, PTR_ERR(priv->mtd)); + return PTR_ERR(priv->mtd); + } + + err = u_boot_env_parse(priv); + if (err) + return err; + + config.dev = dev; + config.cells = priv->cells; + config.ncells = priv->ncells; + config.priv = priv; + config.size = priv->size; + + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); +} + +static struct platform_driver u_boot_env_driver = { + .probe = u_boot_env_probe, + .driver = { + .name = "u_boot_env", + .of_match_table = u_boot_env_of_match_table, + }, +}; + +static int __init u_boot_env_init(void) +{ + return platform_driver_register(&u_boot_env_driver); +} + +subsys_initcall_sync(u_boot_env_init); + +MODULE_AUTHOR("Rafał Miłecki"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table);