Skip to content

Commit e888d44

Browse files
brglgregkh
authored andcommitted
nvmem: resolve cells from DT at registration time
Currently we're creating a new cell structure everytime a DT user calls nvmem_cell_get(). Change this behavior by resolving the cells during nvmem provider registration and adding all cells to the provider's list. Make of_nvmem_cell_get() just parse the phandle and look the cell up in the relevant provider's list. Don't drop the cell in nvmem_cell_put(). Signed-off-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Srinivas Kandagatla <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b985f4c commit e888d44

File tree

1 file changed

+75
-48
lines changed

1 file changed

+75
-48
lines changed

drivers/nvmem/core.c

Lines changed: 75 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,73 @@ static int nvmem_add_cells_from_table(struct nvmem_device *nvmem)
456456
return rval;
457457
}
458458

459+
static struct nvmem_cell *
460+
nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index)
461+
{
462+
struct nvmem_cell *cell = NULL;
463+
int i = 0;
464+
465+
mutex_lock(&nvmem_mutex);
466+
list_for_each_entry(cell, &nvmem->cells, node) {
467+
if (index == i++)
468+
break;
469+
}
470+
mutex_unlock(&nvmem_mutex);
471+
472+
return cell;
473+
}
474+
475+
static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
476+
{
477+
struct device_node *parent, *child;
478+
struct device *dev = &nvmem->dev;
479+
struct nvmem_cell *cell;
480+
const __be32 *addr;
481+
int len;
482+
483+
parent = dev->of_node;
484+
485+
for_each_child_of_node(parent, child) {
486+
addr = of_get_property(child, "reg", &len);
487+
if (!addr || (len < 2 * sizeof(u32))) {
488+
dev_err(dev, "nvmem: invalid reg on %pOF\n", child);
489+
return -EINVAL;
490+
}
491+
492+
cell = kzalloc(sizeof(*cell), GFP_KERNEL);
493+
if (!cell)
494+
return -ENOMEM;
495+
496+
cell->nvmem = nvmem;
497+
cell->offset = be32_to_cpup(addr++);
498+
cell->bytes = be32_to_cpup(addr);
499+
cell->name = child->name;
500+
501+
addr = of_get_property(child, "bits", &len);
502+
if (addr && len == (2 * sizeof(u32))) {
503+
cell->bit_offset = be32_to_cpup(addr++);
504+
cell->nbits = be32_to_cpup(addr);
505+
}
506+
507+
if (cell->nbits)
508+
cell->bytes = DIV_ROUND_UP(
509+
cell->nbits + cell->bit_offset,
510+
BITS_PER_BYTE);
511+
512+
if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
513+
dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
514+
cell->name, nvmem->stride);
515+
/* Cells already added will be freed later. */
516+
kfree(cell);
517+
return -EINVAL;
518+
}
519+
520+
nvmem_cell_add(cell);
521+
}
522+
523+
return 0;
524+
}
525+
459526
/**
460527
* nvmem_register() - Register a nvmem device for given nvmem_config.
461528
* Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
@@ -546,6 +613,10 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
546613
if (rval)
547614
goto err_remove_cells;
548615

616+
rval = nvmem_add_cells_from_of(nvmem);
617+
if (rval)
618+
goto err_remove_cells;
619+
549620
return nvmem;
550621

551622
err_remove_cells:
@@ -848,10 +919,8 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
848919
const char *name)
849920
{
850921
struct device_node *cell_np, *nvmem_np;
851-
struct nvmem_cell *cell;
852922
struct nvmem_device *nvmem;
853-
const __be32 *addr;
854-
int rval, len;
923+
struct nvmem_cell *cell;
855924
int index = 0;
856925

857926
/* if cell name exists, find index to the name */
@@ -871,54 +940,13 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
871940
if (IS_ERR(nvmem))
872941
return ERR_CAST(nvmem);
873942

874-
addr = of_get_property(cell_np, "reg", &len);
875-
if (!addr || (len < 2 * sizeof(u32))) {
876-
dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n",
877-
cell_np);
878-
rval = -EINVAL;
879-
goto err_mem;
880-
}
881-
882-
cell = kzalloc(sizeof(*cell), GFP_KERNEL);
943+
cell = nvmem_find_cell_by_index(nvmem, index);
883944
if (!cell) {
884-
rval = -ENOMEM;
885-
goto err_mem;
886-
}
887-
888-
cell->nvmem = nvmem;
889-
cell->offset = be32_to_cpup(addr++);
890-
cell->bytes = be32_to_cpup(addr);
891-
cell->name = cell_np->name;
892-
893-
addr = of_get_property(cell_np, "bits", &len);
894-
if (addr && len == (2 * sizeof(u32))) {
895-
cell->bit_offset = be32_to_cpup(addr++);
896-
cell->nbits = be32_to_cpup(addr);
897-
}
898-
899-
if (cell->nbits)
900-
cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
901-
BITS_PER_BYTE);
902-
903-
if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
904-
dev_err(&nvmem->dev,
905-
"cell %s unaligned to nvmem stride %d\n",
906-
cell->name, nvmem->stride);
907-
rval = -EINVAL;
908-
goto err_sanity;
945+
__nvmem_device_put(nvmem);
946+
return ERR_PTR(-ENOENT);
909947
}
910948

911-
nvmem_cell_add(cell);
912-
913949
return cell;
914-
915-
err_sanity:
916-
kfree(cell);
917-
918-
err_mem:
919-
__nvmem_device_put(nvmem);
920-
921-
return ERR_PTR(rval);
922950
}
923951
EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
924952
#endif
@@ -1024,7 +1052,6 @@ void nvmem_cell_put(struct nvmem_cell *cell)
10241052
struct nvmem_device *nvmem = cell->nvmem;
10251053

10261054
__nvmem_device_put(nvmem);
1027-
nvmem_cell_drop(cell);
10281055
}
10291056
EXPORT_SYMBOL_GPL(nvmem_cell_put);
10301057

0 commit comments

Comments
 (0)