[linux-yocto] [PATCH 34/70] lsi/ubootenv: add read access to the uboot env
Paul Butler
butler.paul at gmail.com
Mon Jun 10 18:45:57 PDT 2013
From: Jiang Lu <lu.jiang at windriver.com>
Extracted from lsi.patch in lsi_acp_linux_6.8.1.18 tarball.
Add the support to read the env value in env-0 and env-1
partitions. This function is needed by some drivers.
[Jiang: change file name to lsi_ubootenv.c]
Signed-off-by: Jiang Lu <lu.jiang at windriver.com>
---
drivers/mtd/nand/Kconfig | 6 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/lsi_ubootenv.c | 568 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 575 insertions(+)
create mode 100644 drivers/mtd/nand/lsi_ubootenv.c
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 102ad83..44c1d75 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -534,4 +534,10 @@ config MTD_NAND_EP501X
Enables NAND flash support for the Eureka EP501, EP501G1
and EP501G3 controllers.
+config MTD_NAND_EP501X_UBOOTENV
+ tristate "U-Boot Environment Access for LSI's APP and ACP"
+ depends on ( MTD_NAND_EP501X && CRC32 )
+ help
+ Add U-Boot environment access on LSI's APP/ACP boards.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 01a11f8..035b353 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -52,5 +52,6 @@ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_EP501X) += lsi_acp_nand.o
+obj-$(CONFIG_MTD_NAND_EP501X_UBOOTENV) += lsi_ubootenv.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/lsi_ubootenv.c b/drivers/mtd/nand/lsi_ubootenv.c
new file mode 100644
index 0000000..d9ad283
--- /dev/null
+++ b/drivers/mtd/nand/lsi_ubootenv.c
@@ -0,0 +1,568 @@
+/*
+ * drivers/lsi/acp/ubootenv.c
+ *
+ * Copyright (C) 2009 LSI
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021.1.1_pre.17 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/crc32.h>
+#include <linux/io.h>
+
+/*
+ ======================================================================
+ Data types and Macros
+ ======================================================================
+*/
+#include <asm/lsi/debug.h>
+
+/*
+ ======================================================================
+ Global Variables
+ ======================================================================
+*/
+
+static struct kobject *ubootenv_kobj;
+
+
+static unsigned long uboot_env_size = (128 * 1024);
+static unsigned long uboot_env_cs_size = (128 * 1024);
+static int uboot_env_current = -1;
+
+#define ENVIRONMENT_DATA_SIZE(size) (size - (2 * sizeof(unsigned long)))
+
+typedef struct environment {
+
+ unsigned long crc32;
+ unsigned long flags;
+ unsigned char data[];
+
+} __packed environment_t;
+
+static environment_t *environment = (environment_t *) 0;
+
+static unsigned long crc32_lut[256] = {
+
+ /* 0 -- */ 0u, 1996959894u, 3993919788u, 2567524794u,
+ /* 4 -- */ 124634137u, 1886057615u, 3915621685u, 2657392035u,
+ /* 8 -- */ 249268274u, 2044508324u, 3772115230u, 2547177864u,
+ /* 12 -- */ 162941995u, 2125561021u, 3887607047u, 2428444049u,
+ /* 16 -- */ 498536548u, 1789927666u, 4089016648u, 2227061214u,
+ /* 20 -- */ 450548861u, 1843258603u, 4107580753u, 2211677639u,
+ /* 24 -- */ 325883990u, 1684777152u, 4251122042u, 2321926636u,
+ /* 28 -- */ 335633487u, 1661365465u, 4195302755u, 2366115317u,
+ /* 32 -- */ 997073096u, 1281953886u, 3579855332u, 2724688242u,
+ /* 36 -- */ 1006888145u, 1258607687u, 3524101629u, 2768942443u,
+ /* 40 -- */ 901097722u, 1119000684u, 3686517206u, 2898065728u,
+ /* 44 -- */ 853044451u, 1172266101u, 3705015759u, 2882616665u,
+ /* 48 -- */ 651767980u, 1373503546u, 3369554304u, 3218104598u,
+ /* 52 -- */ 565507253u, 1454621731u, 3485111705u, 3099436303u,
+ /* 56 -- */ 671266974u, 1594198024u, 3322730930u, 2970347812u,
+ /* 60 -- */ 795835527u, 1483230225u, 3244367275u, 3060149565u,
+ /* 64 -- */ 1994146192u, 31158534u, 2563907772u, 4023717930u,
+ /* 68 -- */ 1907459465u, 112637215u, 2680153253u, 3904427059u,
+ /* 72 -- */ 2013776290u, 251722036u, 2517215374u, 3775830040u,
+ /* 76 -- */ 2137656763u, 141376813u, 2439277719u, 3865271297u,
+ /* 80 -- */ 1802195444u, 476864866u, 2238001368u, 4066508878u,
+ /* 84 -- */ 1812370925u, 453092731u, 2181625025u, 4111451223u,
+ /* 88 -- */ 1706088902u, 314042704u, 2344532202u, 4240017532u,
+ /* 92 -- */ 1658658271u, 366619977u, 2362670323u, 4224994405u,
+ /* 96 -- */ 1303535960u, 984961486u, 2747007092u, 3569037538u,
+ /* 100 -- */ 1256170817u, 1037604311u, 2765210733u, 3554079995u,
+ /* 104 -- */ 1131014506u, 879679996u, 2909243462u, 3663771856u,
+ /* 108 -- */ 1141124467u, 855842277u, 2852801631u, 3708648649u,
+ /* 112 -- */ 1342533948u, 654459306u, 3188396048u, 3373015174u,
+ /* 116 -- */ 1466479909u, 544179635u, 3110523913u, 3462522015u,
+ /* 120 -- */ 1591671054u, 702138776u, 2966460450u, 3352799412u,
+ /* 124 -- */ 1504918807u, 783551873u, 3082640443u, 3233442989u,
+ /* 128 -- */ 3988292384u, 2596254646u, 62317068u, 1957810842u,
+ /* 132 -- */ 3939845945u, 2647816111u, 81470997u, 1943803523u,
+ /* 136 -- */ 3814918930u, 2489596804u, 225274430u, 2053790376u,
+ /* 140 -- */ 3826175755u, 2466906013u, 167816743u, 2097651377u,
+ /* 144 -- */ 4027552580u, 2265490386u, 503444072u, 1762050814u,
+ /* 148 -- */ 4150417245u, 2154129355u, 426522225u, 1852507879u,
+ /* 152 -- */ 4275313526u, 2312317920u, 282753626u, 1742555852u,
+ /* 156 -- */ 4189708143u, 2394877945u, 397917763u, 1622183637u,
+ /* 160 -- */ 3604390888u, 2714866558u, 953729732u, 1340076626u,
+ /* 164 -- */ 3518719985u, 2797360999u, 1068828381u, 1219638859u,
+ /* 168 -- */ 3624741850u, 2936675148u, 906185462u, 1090812512u,
+ /* 172 -- */ 3747672003u, 2825379669u, 829329135u, 1181335161u,
+ /* 176 -- */ 3412177804u, 3160834842u, 628085408u, 1382605366u,
+ /* 180 -- */ 3423369109u, 3138078467u, 570562233u, 1426400815u,
+ /* 184 -- */ 3317316542u, 2998733608u, 733239954u, 1555261956u,
+ /* 188 -- */ 3268935591u, 3050360625u, 752459403u, 1541320221u,
+ /* 192 -- */ 2607071920u, 3965973030u, 1969922972u, 40735498u,
+ /* 196 -- */ 2617837225u, 3943577151u, 1913087877u, 83908371u,
+ /* 200 -- */ 2512341634u, 3803740692u, 2075208622u, 213261112u,
+ /* 204 -- */ 2463272603u, 3855990285u, 2094854071u, 198958881u,
+ /* 208 -- */ 2262029012u, 4057260610u, 1759359992u, 534414190u,
+ /* 212 -- */ 2176718541u, 4139329115u, 1873836001u, 414664567u,
+ /* 216 -- */ 2282248934u, 4279200368u, 1711684554u, 285281116u,
+ /* 220 -- */ 2405801727u, 4167216745u, 1634467795u, 376229701u,
+ /* 224 -- */ 2685067896u, 3608007406u, 1308918612u, 956543938u,
+ /* 228 -- */ 2808555105u, 3495958263u, 1231636301u, 1047427035u,
+ /* 232 -- */ 2932959818u, 3654703836u, 1088359270u, 936918000u,
+ /* 236 -- */ 2847714899u, 3736837829u, 1202900863u, 817233897u,
+ /* 240 -- */ 3183342108u, 3401237130u, 1404277552u, 615818150u,
+ /* 244 -- */ 3134207493u, 3453421203u, 1423857449u, 601450431u,
+ /* 248 -- */ 3009837614u, 3294710456u, 1567103746u, 711928724u,
+ /* 252 -- */ 3020668471u, 3272380065u, 1510334235u, 755167117u
+
+};
+
+/*
+ ======================================================================
+ Prototypes
+ ======================================================================
+*/
+
+static unsigned long ubootenv_crc32(unsigned char *, unsigned long);
+static int ubootenv_initialize(void);
+static void ubootenv_finalize(void);
+static int ubootenv_read(struct mtd_info *, size_t, void *);
+static void create_env_sysfs(void);
+/*
+ ======================================================================
+ ======================================================================
+*/
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_crc32
+*/
+
+static unsigned long
+ubootenv_crc32(unsigned char *start, unsigned long size)
+{
+ unsigned long crc = (unsigned long)0xffffffff, index;
+
+ DEBUG_PRINT("start=0x%lx size=0x%lx\n", (unsigned long)start, size);
+
+ for (index = 0; index < size; index++) {
+ unsigned long temp = (crc ^ *(start++)) & 0x000000ff;
+ crc = ((crc >> 8) & 0x00ffffff) ^ crc32_lut[temp];
+ }
+ return ~crc;
+}
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_read
+*/
+
+static int
+ubootenv_read(struct mtd_info *mtd, size_t size, void *buffer)
+{
+ int read = 0;
+ loff_t offset = 0;
+
+ DEBUG_PRINT("size=0x%x mtd->erasesize=0x%x mtd->size=0x%llx\n",
+ size, mtd->erasesize, mtd->size);
+
+ if (0 != size % mtd->erasesize) {
+ ERROR_PRINT("size=%u/%llu is not a multiple of erasesize=%u\n",
+ size, mtd->size, mtd->erasesize);
+ return -1;
+ }
+
+ if (size > mtd->size) {
+ ERROR_PRINT("size=%llu can't contain size=%u\n",
+ mtd->size, size);
+ return -1;
+ }
+
+ while ((read < size) && (offset < mtd->size)) {
+ int return_code;
+ size_t bytes_read;
+
+ DEBUG_PRINT("read=0x%x size=0x%x offset=0x%llx\n",
+ read, size, offset);
+
+ if (0 != mtd_block_isbad(mtd, offset)) {
+ offset += mtd->erasesize;
+ continue;
+ }
+
+ return_code = mtd_read(mtd, offset, mtd->erasesize,
+ &bytes_read, (u_char *) buffer);
+
+ if (mtd->erasesize != bytes_read) {
+ ERROR_PRINT("Error Reading Environment!\n");
+ return -1;
+ }
+
+ offset += mtd->erasesize;
+ read += mtd->erasesize;
+ buffer += mtd->erasesize;
+ }
+
+ return 0;
+}
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_initialize
+*/
+
+static int
+ubootenv_initialize(void)
+{
+ environment_t *env0;
+ environment_t *env1;
+ unsigned long crc32_env0;
+ unsigned long crc32_env1;
+ struct mtd_info *mtd_env0;
+ struct mtd_info *mtd_env1;
+
+ DEBUG_PRINT("Getting MTD Devices.\n");
+
+ mtd_env0 = get_mtd_device_nm("env-0");
+ if ((struct mtd_info *)-ENODEV == mtd_env0) {
+ ERROR_PRINT(" --> Couldn't get MTD device by name!\n");
+ return -1;
+ }
+
+ mtd_env1 = get_mtd_device_nm("env-1");
+ if ((struct mtd_info *)-ENODEV == mtd_env1) {
+ ERROR_PRINT(" --> Couldn't get MTD device by name!\n");
+ return -1;
+ }
+
+ /*
+ * If the erasesize is larger than the size of the environment,
+ * change the environment size (so reading and writing will
+ * work as expected) but use the original environment size to
+ * calculate the checksum.
+ */
+
+ if (mtd_env0->erasesize > uboot_env_size)
+ uboot_env_size = mtd_env0->erasesize;
+
+ DEBUG_PRINT("Allocating Environment Buffers.\n");
+
+ env0 = vmalloc(uboot_env_size);
+ if ((environment_t *)0 == env0) {
+ ERROR_PRINT("Unable to allocate %lu bytes\n", uboot_env_size);
+ return -1;
+ }
+
+ env1 = vmalloc(uboot_env_size);
+ if ((environment_t *) 0 == env1) {
+ ERROR_PRINT("Unable to allocate %lu bytes\n", uboot_env_size);
+ vfree((void *) env0);
+ return -1;
+ }
+
+ DEBUG_PRINT("Reading Environments.\n");
+
+ if (0 != ubootenv_read(mtd_env0, uboot_env_size, env0))
+ return -1;
+
+ if (0 != ubootenv_read(mtd_env1, uboot_env_size, env1))
+ return -1;
+
+ DEBUG_PRINT("Calculating CRC values.\n");
+ crc32_env0 = ubootenv_crc32((unsigned char *)env0->data,
+ ENVIRONMENT_DATA_SIZE(uboot_env_cs_size));
+ crc32_env1 = ubootenv_crc32((unsigned char *)env1->data,
+ ENVIRONMENT_DATA_SIZE(uboot_env_cs_size));
+ DEBUG_PRINT("crc32_env0=0x%lx env0->crc32=0x%lx\n",
+ crc32_env0, env0->crc32);
+ DEBUG_PRINT("crc32_env2=0x%lx env1->crc32=0x%lx\n",
+ crc32_env1, env1->crc32);
+ DEBUG_PRINT("Picking a Copy.\n");
+
+ if ((crc32_env0 == env0->crc32) &&
+ (crc32_env1 != env1->crc32)) {
+ /* Use env0 */
+ DEBUG_PRINT("Using Copy 0.\n");
+ uboot_env_current = 0;
+ vfree((void *) env1);
+ environment = env0;
+ } else if ((crc32_env0 != env0->crc32) &&
+ (crc32_env1 == env1->crc32)) {
+ /* Use env1 */
+ DEBUG_PRINT("Using Copy 1.\n");
+ uboot_env_current = 1;
+ vfree((void *) env0);
+ environment = env1;
+ } else if ((crc32_env0 != env0->crc32) &&
+ (crc32_env1 != env1->crc32)) {
+ /* No Environment Available */
+ uboot_env_current = -1;
+ vfree((void *) env0);
+ vfree((void *) env1);
+ ERROR_PRINT("Bad CRCs: No Valid U-Boot Environment Found!\n");
+ return -1;
+ } else if (env0->flags > env1->flags) {
+ /* Use env0 */
+ DEBUG_PRINT("Using Copy 0.\n");
+ uboot_env_current = 0;
+ vfree((void *) env1);
+ environment = env0;
+ } else if (env0->flags < env1->flags) {
+ /* Use env1 */
+ DEBUG_PRINT("Using Copy 1.\n");
+ uboot_env_current = 1;
+ vfree((void *) env0);
+ environment = env1;
+ } else if (env0->flags == env1->flags) {
+ /* Use Either */
+ DEBUG_PRINT("Using Copy 0.\n");
+ uboot_env_current = 0;
+ vfree((void *) env1);
+ environment = env0;
+ } else {
+ /* No Environment Available */
+ uboot_env_current = -1;
+ vfree((void *) env0);
+ vfree((void *) env1);
+ ERROR_PRINT("Bad Flags: No Valid U-Boot Environment Found!\n");
+ return -1;
+ }
+
+ DEBUG_PRINT("Done...\n");
+ create_env_sysfs();
+
+ return 0;
+}
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_finalize
+*/
+
+static void
+ubootenv_finalize(void)
+{
+ DEBUG_PRINT("Freeing the environment.\n");
+
+ if ((void *)0 != environment)
+ vfree((void *)environment);
+
+ environment = (environment_t *)0;
+}
+
+/*
+ ======================================================================
+ Public Interface
+ ======================================================================
+*/
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_get
+*/
+
+int
+ubootenv_get(const char *key, char *value)
+{
+ int return_code = -1;
+ char *string;
+
+ if (NULL == environment) {
+ ERROR_PRINT("Environment Isn't Available!\n");
+ return -1;
+ }
+
+ string = environment->data;
+
+ while (0x00 != string[0]) {
+ if (0 == strncmp(key, string, strlen(key))) {
+ char *value_ = strchr(string, '=');
+ ++value_;
+ strcpy(value, value_);
+ return_code = 0;
+ break;
+ }
+
+ string += (strlen(string) + 1);
+ }
+
+ return return_code;
+}
+EXPORT_SYMBOL(ubootenv_get);
+
+/*
+ ======================================================================
+ ======================================================================
+ Sysfs Stuff
+ ======================================================================
+ ======================================================================
+*/
+
+struct bin_attribute uboot_env[100];
+
+static ssize_t read_env(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t size)
+{
+ int retsize = -1;
+ char *string;
+
+ if (size <= 1)
+ return 0;
+
+ if (NULL == environment) {
+ ERROR_PRINT("Environment Isn't Available!\n");
+ return -1;
+ }
+
+ string = environment->data;
+
+ while (0x00 != string[0]) {
+ if (0 == strncmp(bin_attr->attr.name,
+ string, strlen(bin_attr->attr.name))) {
+ char *value_ = strchr(string, '=');
+ ++value_;
+
+ retsize = 1 + strlcpy(buf, value_, size);
+ break;
+ }
+
+ string += (strlen(string) + 1);
+ }
+
+ return retsize;
+}
+
+static void create_env_sysfs(void)
+{
+ char *string;
+ int i = 0;
+
+ if (NULL == environment) {
+ ERROR_PRINT("Environment Isn't Available!\n");
+ return;
+ }
+
+ string = environment->data;
+
+ while (0x00 != string[0]) {
+ char *value_ = strchr(string, '=');
+ char *name = vmalloc(1 + value_ - string);
+ strlcpy(name, string, 1 + value_ - string);
+
+ uboot_env[i].attr.name = name;
+ uboot_env[i].attr.mode = 0400;
+ uboot_env[i].size = strlen(string) - (value_ - string) ;
+ uboot_env[i].read = read_env;
+
+ if (sysfs_create_bin_file(ubootenv_kobj, &uboot_env[i]))
+ ERROR_PRINT("unable to add uboot-env sysfs file\n");
+
+ string += (strlen(string) + 1);
+ i++;
+ if (i > 99) {
+ ERROR_PRINT("More than 100 uboot env variables.\n");
+ return;
+ }
+ }
+}
+
+
+static ssize_t list_env(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 1;
+ while (i < uboot_env_size - 2) {
+ if (environment->data[i-1] == 0)
+ if (environment->data[i] == 0)
+ if (environment->data[i+1] == 0)
+ break;
+ i++;
+ }
+ memcpy(buf, environment->data, i);
+ return i;
+}
+
+static DEVICE_ATTR(list_env, 0444, list_env, NULL);
+
+static struct attribute *attrs[] = {
+ &dev_attr_list_env.attr,
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+
+/*
+ ======================================================================
+ ======================================================================
+ Linux Module Stuff
+ ======================================================================
+ ======================================================================
+*/
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_module_init
+*/
+
+int __init
+ubootenv_module_init(void)
+{
+ int retval;
+
+ DEBUG_PRINT("\n");
+ ubootenv_kobj = kobject_create_and_add("uboot-env", kernel_kobj);
+ if (!ubootenv_kobj)
+ return -ENOMEM;
+
+ /* Create the files associated with this kobject */
+ retval = sysfs_create_group(ubootenv_kobj, &attr_group);
+ if (retval)
+ goto fail;
+
+ retval = ubootenv_initialize();
+ if (retval)
+ goto fail;
+
+ return 0;
+fail:
+ kobject_put(ubootenv_kobj);
+
+ return retval;
+}
+
+module_init(ubootenv_module_init);
+
+/*
+ ----------------------------------------------------------------------
+ ubootenv_module_exit
+*/
+
+void __exit
+ubootenv_module_exit(void)
+{
+ DEBUG_PRINT("\n");
+ kobject_put(ubootenv_kobj);
+ ubootenv_finalize();
+ return;
+}
+
+module_exit(ubootenv_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Jacques <john.jacques at lsi.com>");
+MODULE_DESCRIPTION("Read Access of the U-Boot Environment");
--
1.8.3
More information about the linux-yocto
mailing list