summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2015-06-09 09:26:44 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2015-06-09 09:26:44 +0200
commite349701487198df5d029621f440004b5a46529f5 (patch)
tree7c5f09d2fd85b319e3c65714c9f3e161d4ceae23
parent3a32e7acd4867705f0b2b822f3dd88b25cae987a (diff)
parent2532f5dfbfe5bb995020e542f698c1c1d1e5f213 (diff)
downloadbarebox-e349701487198df5d029621f440004b5a46529f5.tar.gz
barebox-e349701487198df5d029621f440004b5a46529f5.tar.xz
Merge branch 'for-next/state'
-rw-r--r--Documentation/devicetree/bindings/barebox/barebox,state.rst4
-rw-r--r--arch/arm/crypto/.gitignore1
-rw-r--r--common/oftree.c19
-rw-r--r--common/state.c402
-rw-r--r--drivers/misc/state.c72
-rw-r--r--include/habv4.h2
-rw-r--r--include/of.h1
-rw-r--r--include/state.h9
8 files changed, 393 insertions, 117 deletions
diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst
index 42b2a34d3a..7156084c93 100644
--- a/Documentation/devicetree/bindings/barebox/barebox,state.rst
+++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst
@@ -1,4 +1,6 @@
-barebox,state
+.. _barebox,state:
+
+barebox state
=============
Overview
diff --git a/arch/arm/crypto/.gitignore b/arch/arm/crypto/.gitignore
new file mode 100644
index 0000000000..b22a068f76
--- /dev/null
+++ b/arch/arm/crypto/.gitignore
@@ -0,0 +1 @@
+/sha256-core.S
diff --git a/common/oftree.c b/common/oftree.c
index 50fc95b588..f75d7b4bfe 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -160,6 +160,25 @@ int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context)
}
/*
+ * Remove a previously registered fixup. Only the first (if any) is removed.
+ * Returns 0 if a match was found (and removed), -ENOENT otherwise.
+ */
+int of_unregister_fixup(int (*fixup)(struct device_node *, void *),
+ void *context)
+{
+ struct of_fixup *of_fixup;
+
+ list_for_each_entry(of_fixup, &of_fixup_list, list) {
+ if (of_fixup->fixup == fixup && of_fixup->context == context) {
+ list_del(&of_fixup->list);
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+/*
* Apply registered fixups for the given fdt. The fdt must have
* enough free space to apply the fixups.
*/
diff --git a/common/state.c b/common/state.c
index b677a9f01d..7076f5764d 100644
--- a/common/state.c
+++ b/common/state.c
@@ -54,12 +54,14 @@ struct state_backend {
int (*load)(struct state_backend *backend, struct state *state);
int (*save)(struct state_backend *backend, struct state *state);
const char *name;
+ const char *of_path;
const char *path;
};
enum state_variable_type {
STATE_TYPE_INVALID = 0,
STATE_TYPE_ENUM,
+ STATE_TYPE_U8,
STATE_TYPE_U32,
STATE_TYPE_MAC,
};
@@ -74,12 +76,20 @@ struct state_variable {
void *raw;
};
+enum state_convert {
+ STATE_CONVERT_FROM_NODE,
+ STATE_CONVERT_FROM_NODE_CREATE,
+ STATE_CONVERT_TO_NODE,
+ STATE_CONVERT_FIXUP,
+};
+
/* A variable type (uint32, enum32) */
struct variable_type {
enum state_variable_type type;
const char *type_name;
struct list_head list;
- int (*export)(struct state_variable *, struct device_node *);
+ int (*export)(struct state_variable *, struct device_node *,
+ enum state_convert);
int (*import)(struct state_variable *, const struct device_node *);
struct state_variable *(*create)(struct state *state,
const char *name, struct device_node *);
@@ -126,15 +136,15 @@ static inline struct state_uint32 *to_state_uint32(struct state_variable *s)
}
static int state_uint32_export(struct state_variable *var,
- struct device_node *node)
+ struct device_node *node, enum state_convert conv)
{
struct state_uint32 *su32 = to_state_uint32(var);
int ret;
- if (su32->value_default) {
+ if (su32->value_default || conv == STATE_CONVERT_FIXUP) {
ret = of_property_write_u32(node, "default",
su32->value_default);
- if (ret)
+ if (ret || conv == STATE_CONVERT_FIXUP)
return ret;
}
@@ -153,7 +163,7 @@ static int state_uint32_import(struct state_variable *sv,
return 0;
}
-static struct state_variable *state_uint32_create(struct state *state,
+static struct state_variable *state_uint8_create(struct state *state,
const char *name, struct device_node *node)
{
struct state_uint32 *su32;
@@ -169,6 +179,32 @@ static struct state_variable *state_uint32_create(struct state *state,
}
su32->param = param;
+ su32->var.size = sizeof(uint8_t);
+#ifdef __LITTLE_ENDIAN
+ su32->var.raw = &su32->value;
+#else
+ su32->var.raw = &su32->value + 3;
+#endif
+
+ return &su32->var;
+}
+
+static struct state_variable *state_uint32_create(struct state *state,
+ const char *name, struct device_node *node)
+{
+ struct state_uint32 *su32;
+ struct param_d *param;
+
+ su32 = xzalloc(sizeof(*su32));
+
+ param = dev_add_param_int(&state->dev, name, state_set_dirty,
+ NULL, &su32->value, "%u", state);
+ if (IS_ERR(param)) {
+ free(su32);
+ return ERR_CAST(param);
+ }
+
+ su32->param = param;
su32->var.size = sizeof(uint32_t);
su32->var.raw = &su32->value;
@@ -193,16 +229,16 @@ static inline struct state_enum32 *to_state_enum32(struct state_variable *s)
}
static int state_enum32_export(struct state_variable *var,
- struct device_node *node)
+ struct device_node *node, enum state_convert conv)
{
struct state_enum32 *enum32 = to_state_enum32(var);
int ret, i, len;
char *prop, *str;
- if (enum32->value_default) {
+ if (enum32->value_default || conv == STATE_CONVERT_FIXUP) {
ret = of_property_write_u32(node, "default",
enum32->value_default);
- if (ret)
+ if (ret || conv == STATE_CONVERT_FIXUP)
return ret;
}
@@ -309,14 +345,14 @@ static inline struct state_mac *to_state_mac(struct state_variable *s)
}
static int state_mac_export(struct state_variable *var,
- struct device_node *node)
+ struct device_node *node, enum state_convert conv)
{
struct state_mac *mac = to_state_mac(var);
int ret;
ret = of_property_write_u8_array(node, "default", mac->value_default,
ARRAY_SIZE(mac->value_default));
- if (ret)
+ if (ret || conv == STATE_CONVERT_FIXUP)
return ret;
return of_property_write_u8_array(node, "value", mac->value,
@@ -363,6 +399,12 @@ out:
static struct variable_type types[] = {
{
+ .type = STATE_TYPE_U8,
+ .type_name = "uint8",
+ .export = state_uint32_export,
+ .import = state_uint32_import,
+ .create = state_uint8_create,
+ }, {
.type = STATE_TYPE_U32,
.type_name = "uint32",
.export = state_uint32_export,
@@ -426,13 +468,6 @@ static struct state *state_new(const char *name)
return state;
}
-static void state_release(struct state *state)
-{
- list_del(&state->list);
- unregister_device(&state->dev);
- free(state);
-}
-
static struct state_variable *state_find_var(struct state *state,
const char *name)
{
@@ -446,12 +481,6 @@ static struct state_variable *state_find_var(struct state *state,
return ERR_PTR(-ENOENT);
}
-enum state_convert {
- STATE_CONVERT_FROM_NODE,
- STATE_CONVERT_FROM_NODE_CREATE,
- STATE_CONVERT_TO_NODE,
-};
-
static int state_convert_node_variable(struct state *state,
struct device_node *node, struct device_node *parent,
const char *parent_name, enum state_convert conv)
@@ -476,7 +505,8 @@ static int state_convert_node_variable(struct state *state,
parent_name, parent_name[0] ? "." : "", short_name);
free(short_name);
- if (conv == STATE_CONVERT_TO_NODE)
+ if ((conv == STATE_CONVERT_TO_NODE) ||
+ (conv == STATE_CONVERT_FIXUP))
new_node = of_new_node(parent, node->name);
for_each_child_of_node(node, child) {
@@ -489,6 +519,15 @@ static int state_convert_node_variable(struct state *state,
/* parents are allowed to have no type */
ret = of_property_read_string(node, "type", &type_name);
if (!list_empty(&node->children) && ret == -EINVAL) {
+ if (conv == STATE_CONVERT_FIXUP) {
+ ret = of_property_write_u32(new_node, "#address-cells", 1);
+ if (ret)
+ goto out_free;
+
+ ret = of_property_write_u32(new_node, "#size-cells", 1);
+ if (ret)
+ goto out_free;
+ }
ret = 0;
goto out_free;
} else if (ret) {
@@ -512,13 +551,16 @@ static int state_convert_node_variable(struct state *state,
ret = of_property_read_u32_array(node, "reg", start_size,
ARRAY_SIZE(start_size));
- if (ret)
+ if (ret) {
+ dev_err(&state->dev,
+ "%s: reg property not found\n", name);
goto out_free;
+ }
if (start_size[1] != sv->size) {
dev_err(&state->dev,
- "size mismatch: type=%s(size=%u) size=%u\n",
- type_name, sv->size, start_size[1]);
+ "%s: size mismatch: type=%s(size=%u) size=%u\n",
+ name, type_name, sv->size, start_size[1]);
ret = -EOVERFLOW;
goto out_free;
}
@@ -539,7 +581,8 @@ static int state_convert_node_variable(struct state *state,
}
free(name);
- if (conv == STATE_CONVERT_TO_NODE) {
+ if ((conv == STATE_CONVERT_TO_NODE) ||
+ (conv == STATE_CONVERT_FIXUP)) {
ret = of_set_property(new_node, "type",
vtype->type_name,
strlen(vtype->type_name) + 1, 1);
@@ -556,8 +599,9 @@ static int state_convert_node_variable(struct state *state,
}
}
- if (conv == STATE_CONVERT_TO_NODE)
- ret = vtype->export(sv, new_node);
+ if ((conv == STATE_CONVERT_TO_NODE) ||
+ (conv == STATE_CONVERT_FIXUP))
+ ret = vtype->export(sv, new_node, conv);
else
ret = vtype->import(sv, node);
@@ -571,20 +615,21 @@ out:
return ret;
}
-static struct device_node *state_to_node(struct state *state)
+static struct device_node *state_to_node(struct state *state, struct device_node *parent,
+ enum state_convert conv)
{
struct device_node *child;
struct device_node *root;
int ret;
- root = of_new_node(NULL, NULL);
+ root = of_new_node(parent, state->root->name);
ret = of_property_write_u32(root, "magic", state->magic);
if (ret)
goto out;
for_each_child_of_node(state->root, child) {
ret = state_convert_node_variable(state, child, root, "",
- STATE_CONVERT_TO_NODE);
+ conv);
if (ret)
goto out;
}
@@ -657,6 +702,101 @@ static int state_from_node(struct state *state, struct device_node *node,
return ret;
}
+static int of_state_fixup(struct device_node *root, void *ctx)
+{
+ struct state *state = ctx;
+ const char *compatible = "barebox,state";
+ struct device_node *new_node, *node, *parent, *backend_node;
+ struct property *p;
+ int ret;
+ phandle phandle;
+
+ node = of_find_node_by_path_from(root, state->root->full_name);
+ if (node) {
+ /* replace existing node - it will be deleted later */
+ parent = node->parent;
+ } else {
+ char *of_path, *c;
+
+ /* look for parent, remove last '/' from path */
+ of_path = xstrdup(state->root->full_name);
+ c = strrchr(of_path, '/');
+ if (!c)
+ return -ENODEV;
+ *c = '0';
+ parent = of_find_node_by_path(of_path);
+ if (!parent)
+ parent = root;
+
+ free(of_path);
+ }
+
+ /* serialize variable definitions */
+ new_node = state_to_node(state, parent, STATE_CONVERT_FIXUP);
+ if (IS_ERR(new_node))
+ return PTR_ERR(new_node);
+
+ /* compatible */
+ p = of_new_property(new_node, "compatible", compatible,
+ strlen(compatible) + 1);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* backend-type */
+ if (!state->backend) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ p = of_new_property(new_node, "backend-type", state->backend->name,
+ strlen(state->backend->name) + 1);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* backend phandle */
+ backend_node = of_find_node_by_path_from(root, state->backend->of_path);
+ if (!backend_node) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ phandle = of_node_create_phandle(backend_node);
+ ret = of_property_write_u32(new_node, "backend", phandle);
+ if (ret)
+ goto out;
+
+ /* address-cells + size-cells */
+ ret = of_property_write_u32(new_node, "#address-cells", 1);
+ if (ret)
+ goto out;
+
+ ret = of_property_write_u32(new_node, "#size-cells", 1);
+ if (ret)
+ goto out;
+
+ /* delete existing node */
+ if (node)
+ of_delete_node(node);
+
+ return 0;
+
+ out:
+ of_delete_node(new_node);
+ return ret;
+}
+
+void state_release(struct state *state)
+{
+ of_unregister_fixup(of_state_fixup, state);
+ list_del(&state->list);
+ unregister_device(&state->dev);
+ free(state);
+}
+
/*
* state_new_from_node - create a new state instance from a device_node
*
@@ -678,27 +818,11 @@ struct state *state_new_from_node(const char *name, struct device_node *node)
return ERR_PTR(ret);
}
- return state;
-}
-
-/*
- * state_new_from_fdt - create a new state instance from a fdt binary blob
- *
- * @name The name of the new state instance
- * @fdt The fdt binary blob describing the new state instance
- */
-struct state *state_new_from_fdt(const char *name, void *fdt)
-{
- struct state *state;
- struct device_node *root;
-
- root = of_unflatten_dtb(fdt);
- if (!root)
- return ERR_PTR(-EINVAL);
-
- state = state_new_from_node(name, root);
-
- of_delete_node(root);
+ ret = of_register_fixup(of_state_fixup, state);
+ if (ret) {
+ state_release(state);
+ return ERR_PTR(ret);
+ }
return state;
}
@@ -757,10 +881,13 @@ int state_load(struct state *state)
return -ENOSYS;
ret = state->backend->load(state->backend, state);
- if (ret)
+ if (ret) {
+ dev_warn(&state->dev, "load failed\n");
state->dirty = 1;
- else
+ } else {
+ dev_info(&state->dev, "load successful\n");
state->dirty = 0;
+ }
return ret;
}
@@ -809,7 +936,7 @@ static int mtd_get_meminfo(const char *path, struct mtd_info_user *meminfo)
{
int fd, ret;
- fd = open(path, O_RDWR);
+ fd = open(path, O_RDONLY);
if (fd < 0)
return fd;
@@ -863,7 +990,7 @@ static int state_backend_dtb_save(struct state_backend *backend,
struct device_node *root;
struct fdt_header *fdt;
- root = state_to_node(state);
+ root = state_to_node(state, NULL, STATE_CONVERT_TO_NODE);
if (IS_ERR(root))
return PTR_ERR(root);
@@ -906,7 +1033,7 @@ out:
* @state The state instance to work on
* @path The path where the state will be stored to
*/
-int state_backend_dtb_file(struct state *state, const char *path)
+int state_backend_dtb_file(struct state *state, const char *of_path, const char *path)
{
struct state_backend_dtb *backend_dtb;
struct state_backend *backend;
@@ -921,13 +1048,14 @@ int state_backend_dtb_file(struct state *state, const char *path)
backend->load = state_backend_dtb_load;
backend->save = state_backend_dtb_save;
+ backend->of_path = xstrdup(of_path);
backend->path = xstrdup(path);
backend->name = "dtb";
state->backend = backend;
ret = mtd_get_meminfo(backend->path, &meminfo);
- if (!ret && !(meminfo.mtd->flags & MTD_NO_ERASE))
+ if (!ret && !(meminfo.flags & MTD_NO_ERASE))
backend_dtb->need_erase = true;
return 0;
@@ -938,9 +1066,9 @@ int state_backend_dtb_file(struct state *state, const char *path)
*/
struct state_backend_raw {
struct state_backend backend;
- unsigned long size_data; /* The raw data size (without magic and crc) */
- unsigned long size_full;
- unsigned long step; /* The step in bytes between two copies */
+ unsigned long size_data; /* The raw data size (without header) */
+ unsigned long size_full; /* The size header + raw data */
+ unsigned long stride; /* The stride size in bytes of the copies */
off_t offset; /* offset in the storage file */
size_t size; /* size of the storage area */
int num_copy_read; /* The first successfully read copy */
@@ -961,16 +1089,23 @@ static int backend_raw_load_one(struct state_backend_raw *backend_raw,
uint32_t crc;
struct state_variable *sv;
struct backend_raw_header header = {};
+ unsigned long max_len;
int ret;
void *buf;
+ max_len = backend_raw->stride;
+
ret = lseek(fd, offset, SEEK_SET);
if (ret < 0)
return ret;
ret = read_full(fd, &header, sizeof(header));
- if (ret < 0)
+ max_len -= sizeof(header);
+ if (ret < 0) {
+ dev_err(&state->dev,
+ "cannot read header from backend device");
return ret;
+ }
crc = crc32(0, &header, sizeof(header) - sizeof(uint32_t));
if (crc != header.header_crc) {
@@ -987,6 +1122,13 @@ static int backend_raw_load_one(struct state_backend_raw *backend_raw,
return -EINVAL;
}
+ if (header.data_len > max_len) {
+ dev_err(&state->dev,
+ "invalid data_len %u in header, max is %lu\n",
+ header.data_len, max_len);
+ return -EINVAL;
+ }
+
buf = xzalloc(header.data_len);
ret = read_full(fd, buf, header.data_len);
@@ -1024,11 +1166,13 @@ static int state_backend_raw_load(struct state_backend *backend,
int ret = 0, fd, i;
fd = open(backend->path, O_RDONLY);
- if (fd < 0)
+ if (fd < 0) {
+ dev_err(&state->dev, "cannot open %s\n", backend->path);
return fd;
+ }
for (i = 0; i < RAW_BACKEND_COPIES; i++) {
- off_t offset = backend_raw->offset + i * backend_raw->step;
+ off_t offset = backend_raw->offset + i * backend_raw->stride;
ret = backend_raw_load_one(backend_raw, state, fd, offset);
if (!ret) {
@@ -1044,11 +1188,11 @@ static int state_backend_raw_load(struct state_backend *backend,
return ret;
}
-static int backend_raw_write_one(struct state_backend_raw *backend_raw,
+static int backend_raw_save_one(struct state_backend_raw *backend_raw,
struct state *state, int fd, int num, void *buf, size_t size)
{
int ret;
- off_t offset = backend_raw->offset + num * backend_raw->step;
+ off_t offset = backend_raw->offset + num * backend_raw->stride;
dev_dbg(&state->dev, "%s: 0x%08lx 0x%08zx\n",
__func__, offset, size);
@@ -1058,7 +1202,7 @@ static int backend_raw_write_one(struct state_backend_raw *backend_raw,
return ret;
if (backend_raw->need_erase) {
- ret = erase(fd, backend_raw->size_full, offset);
+ ret = erase(fd, backend_raw->stride, offset);
if (ret)
return ret;
}
@@ -1075,14 +1219,12 @@ static int state_backend_raw_save(struct state_backend *backend,
{
struct state_backend_raw *backend_raw = container_of(backend,
struct state_backend_raw, backend);
- int ret = 0, size, fd;
+ int ret = 0, fd, i;
void *buf, *data;
struct backend_raw_header *header;
struct state_variable *sv;
- size = backend_raw->size_data + sizeof(struct backend_raw_header);
-
- buf = xzalloc(size);
+ buf = xzalloc(backend_raw->size_full);
header = buf;
data = buf + sizeof(*header);
@@ -1100,13 +1242,20 @@ static int state_backend_raw_save(struct state_backend *backend,
if (fd < 0)
goto out_free;
- ret = backend_raw_write_one(backend_raw, state, fd,
- !backend_raw->num_copy_read, buf, size);
- if (ret)
- goto out_close;
+ /* save other slots first */
+ for (i = 0; i < RAW_BACKEND_COPIES; i++) {
+ if (i == backend_raw->num_copy_read)
+ continue;
- ret = backend_raw_write_one(backend_raw, state, fd,
- backend_raw->num_copy_read, buf, size);
+ ret = backend_raw_save_one(backend_raw, state, fd,
+ i, buf, backend_raw->size_full);
+ if (ret)
+ goto out_close;
+
+ }
+
+ ret = backend_raw_save_one(backend_raw, state, fd,
+ backend_raw->num_copy_read, buf, backend_raw->size_full);
if (ret)
goto out_close;
@@ -1119,6 +1268,60 @@ out_free:
return ret;
}
+#ifdef __BAREBOX__
+#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode) || S_ISCHR(s.st_mode))
+#define BLKGET_GIVES_SIZE(s) 0
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 -1
+#endif
+#else
+#define STAT_GIVES_SIZE(s) (S_ISREG(s.st_mode))
+#define BLKGET_GIVES_SIZE(s) (S_ISBLK(s.st_mode))
+#endif
+
+static int state_backend_raw_file_get_size(const char *path, size_t *out_size)
+{
+ struct mtd_info_user meminfo;
+ struct stat s;
+ int ret;
+
+ ret = stat(path, &s);
+ if (ret)
+ return -errno;
+
+ /*
+ * under Linux, stat() gives the size only on regular files
+ * under barebox, it works on char dev, too
+ */
+ if (STAT_GIVES_SIZE(s)) {
+ *out_size = s.st_size;
+ return 0;
+ }
+
+ /* this works under Linux on block devs */
+ if (BLKGET_GIVES_SIZE(s)) {
+ int fd;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ ret = ioctl(fd, BLKGETSIZE64, out_size);
+ close(fd);
+ if (!ret)
+ return 0;
+ }
+
+ /* try mtd next */
+ ret = mtd_get_meminfo(path, &meminfo);
+ if (!ret) {
+ *out_size = meminfo.size;
+ return 0;
+ }
+
+ return ret;
+}
+
/*
* state_backend_raw_file - create a raw file backend store for a state instance
*
@@ -1136,32 +1339,34 @@ out_free:
* device @size may be 0. The two copies are spread to different
* eraseblocks if approriate for this device.
*/
-int state_backend_raw_file(struct state *state, const char *path, off_t offset,
- size_t size)
+int state_backend_raw_file(struct state *state, const char *of_path,
+ const char *path, off_t offset, size_t size)
{
struct state_backend_raw *backend_raw;
struct state_backend *backend;
struct state_variable *sv;
- int ret;
- struct stat s;
struct mtd_info_user meminfo;
+ size_t path_size = 0;
+ int ret;
if (state->backend)
return -EBUSY;
- ret = stat(path, &s);
- if (!ret && S_ISCHR(s.st_mode)) {
- if (size == 0)
- size = s.st_size;
- else if (offset + size > s.st_size)
- return -EINVAL;
- }
+ ret = state_backend_raw_file_get_size(path, &path_size);
+ if (ret)
+ return ret;
+
+ if (size == 0)
+ size = path_size;
+ else if (offset + size > path_size)
+ return -EINVAL;
backend_raw = xzalloc(sizeof(*backend_raw));
backend = &backend_raw->backend;
backend->load = state_backend_raw_load;
backend->save = state_backend_raw_save;
+ backend->of_path = xstrdup(of_path);
backend->path = xstrdup(path);
backend->name = "raw";
@@ -1175,18 +1380,21 @@ int state_backend_raw_file(struct state *state, const char *path, off_t offset,
state->backend = backend;
ret = mtd_get_meminfo(backend->path, &meminfo);
- if (!ret && !(meminfo.mtd->flags & MTD_NO_ERASE)) {
+ if (!ret && !(meminfo.flags & MTD_NO_ERASE)) {
backend_raw->need_erase = true;
- backend_raw->step = ALIGN(backend_raw->size_full,
- meminfo.erasesize);
+ backend_raw->size_full = ALIGN(backend_raw->size_full,
+ meminfo.writesize);
+ backend_raw->stride = ALIGN(backend_raw->size_full,
+ meminfo.erasesize);
dev_dbg(&state->dev, "is a mtd, adjust stepsize to %ld\n",
- backend_raw->step);
+ backend_raw->stride);
} else {
- backend_raw->step = backend_raw->size_full;
+ backend_raw->stride = backend_raw->size_full;
}
- if (backend_raw->size / backend_raw->step < RAW_BACKEND_COPIES) {
- dev_err(&state->dev, "not enough space for two copies\n");
+ if (backend_raw->size / backend_raw->stride < RAW_BACKEND_COPIES) {
+ dev_err(&state->dev, "not enough space for two copies (%lu each)\n",
+ backend_raw->stride);
ret = -ENOSPC;
goto err;
}
diff --git a/drivers/misc/state.c b/drivers/misc/state.c
index 3b07bb93d7..f3e366480f 100644
--- a/drivers/misc/state.c
+++ b/drivers/misc/state.c
@@ -24,10 +24,12 @@
static int state_probe(struct device_d *dev)
{
struct device_node *np = dev->device_node;
+ struct device_node *partition_node;
struct state *state;
const char *alias;
const char *backend_type = NULL;
- int ret;
+ int len, ret;
+ const char *of_path;
char *path;
if (!np)
@@ -41,28 +43,70 @@ static int state_probe(struct device_d *dev)
if (IS_ERR(state))
return PTR_ERR(state);
- ret = of_find_path(np, "backend", &path, 0);
- if (ret)
- return ret;
+ of_path = of_get_property(np, "backend", &len);
+ if (!of_path) {
+ ret = -ENODEV;
+ goto out_release;
+ }
+
+ /* guess if of_path is a path, not a phandle */
+ if (of_path[0] == '/' && len > 1) {
+ ret = of_find_path(np, "backend", &path, 0);
+ if (ret)
+ goto out_release;
+ } else {
+ struct device_d *dev;
+ struct cdev *cdev;
+
+ partition_node = of_parse_phandle(np, "backend", 0);
+ if (!partition_node) {
+ ret = -ENODEV;
+ goto out_release;
+ }
+
+ dev = of_find_device_by_node(partition_node);
+ if (!list_is_singular(&dev->cdevs)) {
+ ret = -ENODEV;
+ goto out_release;
+ }
+
+ cdev = list_first_entry(&dev->cdevs, struct cdev, devices_list);
+ if (!cdev) {
+ ret = -ENODEV;
+ goto out_release;
+ }
- dev_info(dev, "outpath: %s\n", path);
+ path = asprintf("/dev/%s", cdev->name);
+ of_path = partition_node->full_name;
+ }
ret = of_property_read_string(np, "backend-type", &backend_type);
- if (ret)
- return ret;
- else if (!strcmp(backend_type, "raw"))
- ret = state_backend_raw_file(state, path, 0, 0);
- else if (!strcmp(backend_type, "dtb"))
- ret = state_backend_dtb_file(state, path);
- else
+ if (ret) {
+ goto out_free;
+ } else if (!strcmp(backend_type, "raw")) {
+ ret = state_backend_raw_file(state, of_path, path, 0, 0);
+ } else if (!strcmp(backend_type, "dtb")) {
+ ret = state_backend_dtb_file(state, of_path, path);
+ } else {
dev_warn(dev, "invalid backend type: %s\n", backend_type);
+ ret = -ENODEV;
+ goto out_free;
+ }
if (ret)
- return ret;
+ goto out_free;
- state_load(state);
+ dev_info(dev, "backend: %s, path: %s, of_path: %s\n", backend_type, path, of_path);
+ free(path);
+ state_load(state);
return 0;
+
+ out_free:
+ free(path);
+ out_release:
+ state_release(state);
+ return ret;
}
static __maybe_unused struct of_device_id state_ids[] = {
diff --git a/include/habv4.h b/include/habv4.h
index fb6ed99d82..f9bf74f3b9 100644
--- a/include/habv4.h
+++ b/include/habv4.h
@@ -21,7 +21,7 @@
#ifdef CONFIG_HABV4
int habv4_get_status(void);
#else
-static inline int habv4_get_status()
+static inline int habv4_get_status(void)
{
return -EPERM;
}
diff --git a/include/of.h b/include/of.h
index e73cd7a446..c02f5f49ab 100644
--- a/include/of.h
+++ b/include/of.h
@@ -243,6 +243,7 @@ struct device_d *of_find_device_by_node_path(const char *path);
#define OF_FIND_PATH_FLAGS_BB 1 /* return .bb device if available */
int of_find_path(struct device_node *node, const char *propname, char **outpath, unsigned flags);
int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context);
+int of_unregister_fixup(int (*fixup)(struct device_node *, void *), void *context);
struct device_node *of_find_node_by_alias(struct device_node *root,
const char *alias);
struct device_node *of_find_node_by_path_or_alias(struct device_node *root,
diff --git a/include/state.h b/include/state.h
index e96d3bfb2e..08c4e8654b 100644
--- a/include/state.h
+++ b/include/state.h
@@ -5,12 +5,13 @@
struct state;
-int state_backend_dtb_file(struct state *state, const char *path);
-int state_backend_raw_file(struct state *state, const char *path,
- off_t offset, size_t size);
+int state_backend_dtb_file(struct state *state, const char *of_path,
+ const char *path);
+int state_backend_raw_file(struct state *state, const char *of_path,
+ const char *path, off_t offset, size_t size);
-struct state *state_new_from_fdt(const char *name, void *fdt);
struct state *state_new_from_node(const char *name, struct device_node *node);
+void state_release(struct state *state);
struct state *state_by_name(const char *name);
struct state *state_by_node(const struct device_node *node);