summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-07-11 07:58:34 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-07-11 07:58:34 +0200
commit202cda9475558213cf799206caf0130d45164d7f (patch)
treeabe9c88fbf8336e9c89aa22cd1b7ad8cfbf23ed1
parentbb73cb9427cdef4bb3a45ccfa10e30a50940ff09 (diff)
parent699b4f80254de45a6ff45dff0a863e457dea7d89 (diff)
downloadbarebox-202cda9475558213cf799206caf0130d45164d7f.tar.gz
barebox-202cda9475558213cf799206caf0130d45164d7f.tar.xz
Merge branch 'for-next/nvdevvars'
-rw-r--r--Documentation/user/variables.rst18
-rw-r--r--common/globalvar.c151
-rw-r--r--include/globalvar.h6
-rw-r--r--lib/parameter.c3
4 files changed, 154 insertions, 24 deletions
diff --git a/Documentation/user/variables.rst b/Documentation/user/variables.rst
index 0abc25d98a..89aadf58fd 100644
--- a/Documentation/user/variables.rst
+++ b/Documentation/user/variables.rst
@@ -66,6 +66,24 @@ examples:
model: myboard
barebox@yourboard:/
+Non volatile device variables
+-----------------------------
+
+Non volatile device variables are used to make device parameters persistent. They
+are regular nv variables but are linked with other devices instead of the global
+device. Every nv variable in the form nv.dev.<devname>.<paramname> will be mirrored
+to the corresponding <devname>.<paramname> variable.
+
+This example changes the partitioning of the nand0 device:
+
+.. code-block:: sh
+ barebox@Phytec phyCARD-i.MX27:/ nv dev.nand0.partitions: 4M(barebox),1M(barebox-environment),-(root)
+ barebox@Phytec phyCARD-i.MX27:/ devinfo nand0
+ Parameters:
+ [...]
+ partitions: 4M(barebox),1M(barebox-environment),8M(kernel),1011M(root)
+ [...]
+
.. _magicvars:
Magic variables
diff --git a/common/globalvar.c b/common/globalvar.c
index 75e4d43afb..c0958e11ea 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -68,22 +68,115 @@ static int nv_save(const char *name, const char *val)
return 0;
}
+/**
+ * dev_param_init_from_nv - initialize a device parameter from nv variable
+ * @dev: The device
+ * @name: The parameter name
+ *
+ * This function initializes a newly created device parameter from the corresponding
+ * nv.dev.<devname>.<paramname> variable.
+ */
+void dev_param_init_from_nv(struct device_d *dev, const char *name)
+{
+ char *nvname;
+ const char *val;
+ int ret = 0;
+
+ if (dev == &nv_device)
+ return;
+ if (dev == &global_device)
+ return;
+
+ nvname = basprintf("dev.%s.%s", dev_name(dev), name);
+ val = dev_get_param(&nv_device, nvname);
+ if (val) {
+ ret = dev_set_param(dev, name, val);
+ if (ret)
+ pr_err("Cannot init param from nv: %s.%s=%s: %s\n",
+ dev_name(dev), name, val, strerror(-ret));
+ }
+
+ free(nvname);
+}
+
+/**
+ * nvvar_device_dispatch - dispatch dev.<dev>.<param> name into device and parameter name
+ * @name: The incoming name in the form dev.<dev>.<param>
+ * @dev: The returned device_d * belonging to <dev>
+ * @pname: the parameter name
+ *
+ * Given a dev.<dev>.<param> string this function finds the device_d * belonging to
+ * <dev> and the parameter name from <param>.
+ *
+ * Return: When incoming string does not belong to the device namespace (does not begin
+ * with "dev." this function returns 0. A value > 0 is returned when the incoming string
+ * is in the device namespace and the string can be dispatched into a device_d * and a
+ * parameter name. A negative error code is returned when the incoming string belongs to
+ * the device namespace, but cannot be dispatched.
+ */
+static int nvvar_device_dispatch(const char *name, struct device_d **dev,
+ const char **pname)
+{
+ char *devname;
+ const char *dot;
+ int dotpos;
+
+ *dev = NULL;
+
+ if (strncmp(name, "dev.", 4))
+ return 0;
+
+ name += 4;
+
+ dot = strchr(name, '.');
+ if (!dot)
+ return -EINVAL;
+
+ dotpos = dot - name;
+
+ devname = xstrndup(name, dotpos);
+ *dev = get_device_by_name(devname);
+ free(devname);
+
+ if (*dev == &nv_device || *dev == &global_device)
+ return -EINVAL;
+
+ *pname = dot + 1;
+
+ return 1;
+}
+
static int nv_set(struct device_d *dev, struct param_d *p, const char *val)
{
- struct param_d *gp;
int ret;
+ int devspace;
+ struct device_d *rdev;
+ const char *pname;
if (!val)
val = "";
- gp = get_param_by_name(&global_device, p->name);
- if (!gp)
- return -EINVAL;
-
- ret = gp->set(&global_device, gp, val);
- if (ret)
+ ret = nvvar_device_dispatch(p->name, &rdev, &pname);
+ if (ret < 0)
return ret;
+ devspace = ret;
+
+ if (devspace) {
+ if (rdev) {
+ ret = dev_set_param(rdev, pname, val);
+ if (ret) {
+ pr_err("Cannot init param from nv: %s.%s=%s: %s\n",
+ dev_name(rdev), pname, val, strerror(-ret));
+ return ret;
+ }
+ }
+ } else {
+ ret = dev_set_param(&global_device, p->name, val);
+ if (ret)
+ return ret;
+ }
+
free(p->value);
p->value = xstrdup(val);
@@ -99,15 +192,26 @@ int nvvar_add(const char *name, const char *value)
{
struct param_d *p, *gp;
int ret;
+ int devspace;
+ struct device_d *dev;
+ const char *pname;
if (!IS_ENABLED(CONFIG_NVVAR))
return -ENOSYS;
+ ret = nvvar_device_dispatch(name, &dev, &pname);
+ if (ret < 0)
+ return ret;
+
+ devspace = ret;
+
gp = get_param_by_name(&nv_device, name);
if (gp) {
- ret = dev_set_param(&global_device, name, value);
- if (ret)
- return ret;
+ if (!devspace) {
+ ret = dev_set_param(&global_device, name, value);
+ if (ret)
+ return ret;
+ }
ret = dev_set_param(&nv_device, name, value);
if (ret)
@@ -116,27 +220,26 @@ int nvvar_add(const char *name, const char *value)
return 0;
}
- ret = globalvar_add_simple(name, value);
- if (ret && ret != -EEXIST)
- return ret;
+ if (!devspace) {
+ ret = globalvar_add_simple(name, value);
+ if (ret && ret != -EEXIST)
+ return ret;
+ }
p = dev_add_param(&nv_device, name, nv_set, nv_get, 0);
if (IS_ERR(p))
return PTR_ERR(p);
- if (value) {
- ret = dev_set_param(&global_device, name, value);
- if (ret)
- return ret;
- } else {
- value = dev_get_param(&global_device, name);
- if (!value)
- value = "";
+ if (!value) {
+ if (devspace) {
+ if (dev)
+ value = dev_get_param(dev, pname);
+ } else {
+ value = dev_get_param(&global_device, name);
+ }
}
- p->value = xstrdup(value);
-
- return nv_save(p->name, value);
+ return nv_set(&nv_device, p, value);
}
int nvvar_remove(const char *name)
diff --git a/include/globalvar.h b/include/globalvar.h
index 5dfa371409..67b97de486 100644
--- a/include/globalvar.h
+++ b/include/globalvar.h
@@ -94,6 +94,8 @@ int nvvar_add(const char *name, const char *value);
int nvvar_remove(const char *name);
void globalvar_print(void);
+void dev_param_init_from_nv(struct device_d *dev, const char *name);
+
#else
static inline int globalvar_add_simple(const char *name, const char *value)
{
@@ -165,6 +167,10 @@ static inline int nvvar_remove(const char *name)
return 0;
}
+static inline void dev_param_init_from_nv(struct device_d *dev, const char *name)
+{
+}
+
#endif
#endif /* __GLOBALVAR_H */
diff --git a/lib/parameter.c b/lib/parameter.c
index 3d356fb972..656a6037c6 100644
--- a/lib/parameter.c
+++ b/lib/parameter.c
@@ -28,6 +28,7 @@
#include <malloc.h>
#include <driver.h>
#include <string.h>
+#include <globalvar.h>
#include <linux/err.h>
struct param_d *get_param_by_name(struct device_d *dev, const char *name)
@@ -156,6 +157,8 @@ static int __dev_add_param(struct param_d *param, struct device_d *dev, const ch
param->dev = dev;
list_add_sort(&param->list, &dev->parameters, compare);
+ dev_param_init_from_nv(dev, name);
+
return 0;
}