UPSTREAM: nvmem: remove the global cell list

Nvmem subsystem keeps a global list of cells that, for non-DT systems,
can only be referenced by cell name, which makes it impossible to have
more than one nvmem device with cells named the same.

This patch makes every nvmem device the owner of the list of its cells.
This effectively removes the support for non-DT systems, but it will
be reintroduced following a different approach in subsequent patches.

This isn't a problem as support for board files in nvmem is currently
broken anyway: any user that would try to get an nvmem cell from the
global cell list would remove the cell after the calling
nvmem_cell_put(). This can cause anything from a subsequent user not
being able to get the cell to double free errors if more users hold
reference to the same cell at the same time.

Fortunately there are no such users which allows us to rework this part.

Bug: 154188491
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit c7235ee3f4b86a01507a12e96a4875ba9b4be842)
Signed-off-by: Will McVicker <willmcvicker@google.com>
[willmcvicker: fix trivial merge conflicts]
Change-Id: Ibedab956757f5eb94c3c6ff3a1476121624a9234
This commit is contained in:
Bartosz Golaszewski 2018-09-21 06:40:14 -07:00 committed by Will McVicker
parent 38697b7c72
commit ea3f6572ec

View file

@ -39,6 +39,7 @@ struct nvmem_device {
int flags;
struct bin_attribute eeprom;
struct device *base_dev;
struct list_head cells;
nvmem_reg_read_t reg_read;
nvmem_reg_write_t reg_write;
void *priv;
@ -60,9 +61,6 @@ struct nvmem_cell {
static DEFINE_MUTEX(nvmem_mutex);
static DEFINE_IDA(nvmem_ida);
static LIST_HEAD(nvmem_cells);
static DEFINE_MUTEX(nvmem_cells_mutex);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key eeprom_lock_key;
#endif
@ -284,28 +282,11 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
return to_nvmem_device(d);
}
static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
{
struct nvmem_cell *p;
mutex_lock(&nvmem_cells_mutex);
list_for_each_entry(p, &nvmem_cells, node)
if (!strcmp(p->name, cell_id)) {
mutex_unlock(&nvmem_cells_mutex);
return p;
}
mutex_unlock(&nvmem_cells_mutex);
return NULL;
}
static void nvmem_cell_drop(struct nvmem_cell *cell)
{
mutex_lock(&nvmem_cells_mutex);
mutex_lock(&nvmem_mutex);
list_del(&cell->node);
mutex_unlock(&nvmem_cells_mutex);
mutex_unlock(&nvmem_mutex);
of_node_put(cell->np);
kfree(cell);
}
@ -314,16 +295,15 @@ static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem)
{
struct nvmem_cell *cell, *p;
list_for_each_entry_safe(cell, p, &nvmem_cells, node)
if (cell->nvmem == nvmem)
nvmem_cell_drop(cell);
list_for_each_entry_safe(cell, p, &nvmem->cells, node)
nvmem_cell_drop(cell);
}
static void nvmem_cell_add(struct nvmem_cell *cell)
{
mutex_lock(&nvmem_cells_mutex);
list_add_tail(&cell->node, &nvmem_cells);
mutex_unlock(&nvmem_cells_mutex);
mutex_lock(&nvmem_mutex);
list_add_tail(&cell->node, &cell->nvmem->cells);
mutex_unlock(&nvmem_mutex);
}
static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
@ -527,6 +507,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
}
kref_init(&nvmem->refcnt);
INIT_LIST_HEAD(&nvmem->cells);
nvmem->id = rval;
nvmem->owner = config->owner;
@ -697,29 +678,14 @@ static struct nvmem_device *__nvmem_device_get(struct device_node *np,
{
struct nvmem_device *nvmem = NULL;
if (!np)
return ERR_PTR(-ENOENT);
mutex_lock(&nvmem_mutex);
if (np) {
nvmem = of_nvmem_find(np);
if (!nvmem) {
mutex_unlock(&nvmem_mutex);
return ERR_PTR(-EPROBE_DEFER);
}
} else {
struct nvmem_cell *cell = nvmem_find_cell(cell_id);
if (cell) {
nvmem = cell->nvmem;
*cellp = cell;
}
if (!nvmem) {
mutex_unlock(&nvmem_mutex);
return ERR_PTR(-ENOENT);
}
}
nvmem = of_nvmem_find(np);
mutex_unlock(&nvmem_mutex);
if (!nvmem)
return ERR_PTR(-EPROBE_DEFER);
if (!try_module_get(nvmem->owner)) {
dev_err(&nvmem->dev,
@ -897,7 +863,7 @@ nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np)
struct nvmem_cell *cell = NULL;
mutex_lock(&nvmem_mutex);
list_for_each_entry(cell, &nvmem_cells, node) {
list_for_each_entry(cell, &nvmem->cells, node) {
if (np == cell->np)
break;
}