[PATCH 17/21] nd: write pmem label set
After 'uuid', 'size', and optionally 'alt_name' have been set to valid values the labels on the dimms can be updated. Write procedure is: 1/ Allocate and write new labels in the "next" index 2/ Free the old labels in the working copy 3/ Write the bitmap and the label space on the dimm 4/ Write the index to make the update valid Label ranges directly mirror the dpa resource values for the given label_id of the namespace. Signed-off-by: Dan Williams --- drivers/block/nd/dimm_devs.c | 49 ++ drivers/block/nd/label.c | 327 + drivers/block/nd/label.h |6 + drivers/block/nd/namespace_devs.c | 82 - drivers/block/nd/nd.h |3 5 files changed, 453 insertions(+), 14 deletions(-) diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c index ae77bf4a5188..a1685c01a2bb 100644 --- a/drivers/block/nd/dimm_devs.c +++ b/drivers/block/nd/dimm_devs.c @@ -134,6 +134,55 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd) return rc; } +int nd_dimm_set_config_data(struct nd_dimm_drvdata *ndd, size_t offset, + void *buf, size_t len) +{ + int rc = validate_dimm(ndd); + size_t max_cmd_size, buf_offset; + struct nfit_cmd_set_config_hdr *cmd; + struct nd_bus *nd_bus = walk_to_nd_bus(ndd->dev); + struct nfit_bus_descriptor *nfit_desc = nd_bus->nfit_desc; + + if (rc) + return rc; + + if (!ndd->data) + return -ENXIO; + + if (offset + len > ndd->nsarea.config_size) + return -ENXIO; + + max_cmd_size = min_t(u32, PAGE_SIZE, len); + max_cmd_size = min_t(u32, max_cmd_size, ndd->nsarea.max_xfer); + cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + for (buf_offset = 0; len; len -= cmd->in_length, + buf_offset += cmd->in_length) { + size_t cmd_size; + u32 *status; + + cmd->in_offset = offset + buf_offset; + cmd->in_length = min(max_cmd_size, len); + memcpy(cmd->in_buf, buf + buf_offset, cmd->in_length); + + /* status is output in the last 4-bytes of the command buffer */ + cmd_size = sizeof(*cmd) + cmd->in_length + sizeof(u32); + status = ((void *) cmd) + cmd_size - sizeof(u32); + + rc = nfit_desc->nfit_ctl(nfit_desc, to_nd_dimm(ndd->dev), + NFIT_CMD_SET_CONFIG_DATA, cmd, cmd_size); + if (rc || *status) { + rc = rc ? rc : -ENXIO; + break; + } + } + kfree(cmd); + + return rc; +} + static void nd_dimm_release(struct device *dev) { struct nd_dimm *nd_dimm = to_nd_dimm(dev); diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c index b55fa2a6f872..78898b642191 100644 --- a/drivers/block/nd/label.c +++ b/drivers/block/nd/label.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include "nd-private.h" @@ -57,6 +58,11 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd) return ndd->nsindex_size; } +static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd) +{ + return ndd->nsarea.config_size / 129; +} + int nd_label_validate(struct nd_dimm_drvdata *ndd) { /* @@ -202,23 +208,30 @@ static struct nd_namespace_label __iomem *nd_label_base(struct nd_dimm_drvdata * return base + 2 * sizeof_namespace_index(ndd); } +static int to_slot(struct nd_dimm_drvdata *ndd, + struct nd_namespace_label __iomem *nd_label) +{ + return nd_label - nd_label_base(ndd); +} + #define for_each_clear_bit_le(bit, addr, size) \ for ((bit) = find_next_zero_bit_le((addr), (size), 0); \ (bit) < (size);\ (bit) = find_next_zero_bit_le((addr), (size), (bit) + 1)) /** - * preamble_current - common variable initialization for nd_label_* routines + * preamble_index - common variable initialization for nd_label_* routines * @nd_dimm: dimm container for the relevant label set + * @idx: namespace_index index * @nsindex: on return set to the currently active namespace index * @free: on return set to the free label bitmap in the index * @nslot: on return set to the number of slots in the label space */ -static bool preamble_current(struct nd_dimm_drvdata *ndd, +static bool preamble_index(struct nd_dimm_drvdata *ndd, int idx, struct nd_namespace_index **nsindex, unsigned long **free, u32 *nslot) { - *nsindex = to_current_namespace_index(ndd); + *nsindex = to_namespace_index(ndd, idx); if (*nsindex == NULL) return false; @@ -237,6 +250,22 @@ char *nd_label_gen_id(struct nd_label_id *label_id, u8 *uuid, u32 flags)
[PATCH 17/21] nd: write pmem label set
After 'uuid', 'size', and optionally 'alt_name' have been set to valid values the labels on the dimms can be updated. Write procedure is: 1/ Allocate and write new labels in the next index 2/ Free the old labels in the working copy 3/ Write the bitmap and the label space on the dimm 4/ Write the index to make the update valid Label ranges directly mirror the dpa resource values for the given label_id of the namespace. Signed-off-by: Dan Williams dan.j.willi...@intel.com --- drivers/block/nd/dimm_devs.c | 49 ++ drivers/block/nd/label.c | 327 + drivers/block/nd/label.h |6 + drivers/block/nd/namespace_devs.c | 82 - drivers/block/nd/nd.h |3 5 files changed, 453 insertions(+), 14 deletions(-) diff --git a/drivers/block/nd/dimm_devs.c b/drivers/block/nd/dimm_devs.c index ae77bf4a5188..a1685c01a2bb 100644 --- a/drivers/block/nd/dimm_devs.c +++ b/drivers/block/nd/dimm_devs.c @@ -134,6 +134,55 @@ int nd_dimm_init_config_data(struct nd_dimm_drvdata *ndd) return rc; } +int nd_dimm_set_config_data(struct nd_dimm_drvdata *ndd, size_t offset, + void *buf, size_t len) +{ + int rc = validate_dimm(ndd); + size_t max_cmd_size, buf_offset; + struct nfit_cmd_set_config_hdr *cmd; + struct nd_bus *nd_bus = walk_to_nd_bus(ndd-dev); + struct nfit_bus_descriptor *nfit_desc = nd_bus-nfit_desc; + + if (rc) + return rc; + + if (!ndd-data) + return -ENXIO; + + if (offset + len ndd-nsarea.config_size) + return -ENXIO; + + max_cmd_size = min_t(u32, PAGE_SIZE, len); + max_cmd_size = min_t(u32, max_cmd_size, ndd-nsarea.max_xfer); + cmd = kzalloc(max_cmd_size + sizeof(*cmd) + sizeof(u32), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + for (buf_offset = 0; len; len -= cmd-in_length, + buf_offset += cmd-in_length) { + size_t cmd_size; + u32 *status; + + cmd-in_offset = offset + buf_offset; + cmd-in_length = min(max_cmd_size, len); + memcpy(cmd-in_buf, buf + buf_offset, cmd-in_length); + + /* status is output in the last 4-bytes of the command buffer */ + cmd_size = sizeof(*cmd) + cmd-in_length + sizeof(u32); + status = ((void *) cmd) + cmd_size - sizeof(u32); + + rc = nfit_desc-nfit_ctl(nfit_desc, to_nd_dimm(ndd-dev), + NFIT_CMD_SET_CONFIG_DATA, cmd, cmd_size); + if (rc || *status) { + rc = rc ? rc : -ENXIO; + break; + } + } + kfree(cmd); + + return rc; +} + static void nd_dimm_release(struct device *dev) { struct nd_dimm *nd_dimm = to_nd_dimm(dev); diff --git a/drivers/block/nd/label.c b/drivers/block/nd/label.c index b55fa2a6f872..78898b642191 100644 --- a/drivers/block/nd/label.c +++ b/drivers/block/nd/label.c @@ -12,6 +12,7 @@ */ #include linux/device.h #include linux/ndctl.h +#include linux/slab.h #include linux/io.h #include linux/nd.h #include nd-private.h @@ -57,6 +58,11 @@ size_t sizeof_namespace_index(struct nd_dimm_drvdata *ndd) return ndd-nsindex_size; } +static int nd_dimm_num_label_slots(struct nd_dimm_drvdata *ndd) +{ + return ndd-nsarea.config_size / 129; +} + int nd_label_validate(struct nd_dimm_drvdata *ndd) { /* @@ -202,23 +208,30 @@ static struct nd_namespace_label __iomem *nd_label_base(struct nd_dimm_drvdata * return base + 2 * sizeof_namespace_index(ndd); } +static int to_slot(struct nd_dimm_drvdata *ndd, + struct nd_namespace_label __iomem *nd_label) +{ + return nd_label - nd_label_base(ndd); +} + #define for_each_clear_bit_le(bit, addr, size) \ for ((bit) = find_next_zero_bit_le((addr), (size), 0); \ (bit) (size);\ (bit) = find_next_zero_bit_le((addr), (size), (bit) + 1)) /** - * preamble_current - common variable initialization for nd_label_* routines + * preamble_index - common variable initialization for nd_label_* routines * @nd_dimm: dimm container for the relevant label set + * @idx: namespace_index index * @nsindex: on return set to the currently active namespace index * @free: on return set to the free label bitmap in the index * @nslot: on return set to the number of slots in the label space */ -static bool preamble_current(struct nd_dimm_drvdata *ndd, +static bool preamble_index(struct nd_dimm_drvdata *ndd, int idx, struct nd_namespace_index **nsindex, unsigned long **free, u32 *nslot) { - *nsindex = to_current_namespace_index(ndd); + *nsindex = to_namespace_index(ndd, idx); if (*nsindex == NULL) return false; @@ -237,6 +250,22 @@ char