diff options
Diffstat (limited to 'common/state/state.c')
-rw-r--r-- | common/state/state.c | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/common/state/state.c b/common/state/state.c index 469ee62d40..219309d715 100644 --- a/common/state/state.c +++ b/common/state/state.c @@ -21,8 +21,10 @@ #include <fs.h> #include <crc.h> #include <init.h> +#include <block.h> #include <linux/err.h> #include <linux/list.h> +#include <linux/uuid.h> #include <linux/mtd/mtd-abi.h> #include <malloc.h> @@ -101,8 +103,8 @@ static int state_do_load(struct state *state, enum state_flags flags) ret = state_storage_read(&state->storage, state->format, state->magic, &buf, &len, flags); if (ret) { - dev_err(&state->dev, "Failed to read state with format %s, %d\n", - state->format->name, ret); + dev_err_state_init(&state->dev, ret, "format %s read failed\n", + state->format->name); goto out; } @@ -333,8 +335,10 @@ static int state_convert_node_variable(struct state *state, goto out; return 0; - out_free:free(name); - out: return ret; +out_free: + free(name); +out: + return ret; } struct device_node *state_to_node(struct state *state, @@ -361,7 +365,8 @@ struct device_node *state_to_node(struct state *state, } return root; - out: of_delete_node(root); +out: + of_delete_node(root); return ERR_PTR(ret); } @@ -556,12 +561,12 @@ static int of_state_fixup(struct device_node *root, void *ctx) goto out; /* delete existing node */ - if (node) - of_delete_node(node); + of_delete_node(node); return 0; - out: of_delete_node(new_node); +out: + of_delete_node(new_node); return ret; } @@ -578,6 +583,22 @@ void state_release(struct state *state) free(state); } +#ifdef __BAREBOX__ +static char *cdev_to_devpath(struct cdev *cdev, off_t *offset, size_t *size) +{ + /* + * We only accept partitions exactly mapping the barebox-state, + * but dt-utils may need to set non-zero values here + */ + *offset = 0; + *size = 0; + + return basprintf("/dev/%s", cdev->name); +} +#endif + +static guid_t barebox_state_partition_guid = BAREBOX_STATE_PARTITION_GUID; + /* * state_new_from_node - create a new state instance from a device_node * @@ -594,12 +615,13 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) const char *alias; uint32_t stridesize; struct device_node *partition_node; - off_t offset = 0; - size_t size = 0; + struct cdev *cdev; + off_t offset; + size_t size; alias = of_alias_get(node); if (!alias) { - pr_err("State node %s does not have an alias in the /aliases/ node\n", node->full_name); + pr_err("State node %pOF does not have an alias in the /aliases/ node\n", node); return ERR_PTR(-EINVAL); } @@ -614,15 +636,8 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) goto out_release_state; } -#ifdef __BAREBOX__ - ret = of_partition_ensure_probed(partition_node); - if (ret) - goto out_release_state; - - ret = of_find_path_by_node(partition_node, &state->backend_path, 0); -#else - ret = of_get_devicepath(partition_node, &state->backend_path, &offset, &size); -#endif + cdev = of_cdev_find(partition_node); + ret = PTR_ERR_OR_ZERO(cdev); if (ret) { if (ret != -EPROBE_DEFER) dev_err(&state->dev, "state failed to parse path to backend: %s\n", @@ -630,6 +645,22 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) goto out_release_state; } + /* Is the backend referencing an on-disk partitionable block device? */ + if (cdev_is_block_disk(cdev)) { + cdev = cdev_find_child_by_gpt_typeuuid(cdev, &barebox_state_partition_guid); + if (IS_ERR(cdev)) { + ret = -EINVAL; + goto out_release_state; + } + + pr_debug("%pOF: backend GPT partition looked up via PartitionTypeGUID\n", + node); + } + + state->backend_path = cdev_to_devpath(cdev, &offset, &size); + + pr_debug("%pOF: backend resolved to %s\n", node, state->backend_path); + state->backend_reproducible_name = of_get_reproducible_name(partition_node); ret = of_property_read_string(node, "backend-type", &backend_type); @@ -653,14 +684,14 @@ struct state *state_new_from_node(struct device_node *node, bool readonly) if (ret) goto out_release_state; + if (readonly) + state_backend_set_readonly(state); + ret = state_storage_init(state, state->backend_path, offset, size, stridesize, storage_type); if (ret) goto out_release_state; - if (readonly) - state_backend_set_readonly(state); - ret = state_from_node(state, node, 1); if (ret) { goto out_release_state; @@ -704,10 +735,12 @@ struct state *state_by_name(const char *name) * * @node The of node of the state instance */ -struct state *state_by_node(const struct device_node *node) +struct state *state_by_node(struct device_node *node) { struct state *state; + of_device_ensure_probed(node); + list_for_each_entry(state, &state_list, list) { if (!strcmp(state->of_path, node->full_name)) return state; @@ -716,6 +749,22 @@ struct state *state_by_node(const struct device_node *node) return NULL; } +/* + * state_by_alias - find a state instance by alias + * + * @name The DT alias of the state instance + */ +struct state *state_by_alias(const char *alias) +{ + struct device_node *node; + + node = of_find_node_by_alias(NULL, alias); + if (!node) + return NULL; + + return state_by_node(node); +} + int state_read_mac(struct state *state, const char *name, u8 *buf) { struct state_variable *svar; |