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 <bgolaszewski@baylibre.com> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									b985f4cba6
								
							
						
					
					
						commit
						e888d445ac
					
				| @ -456,6 +456,73 @@ out: | |||||||
| 	return rval; | 	return rval; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct nvmem_cell * | ||||||
|  | nvmem_find_cell_by_index(struct nvmem_device *nvmem, int index) | ||||||
|  | { | ||||||
|  | 	struct nvmem_cell *cell = NULL; | ||||||
|  | 	int i = 0; | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&nvmem_mutex); | ||||||
|  | 	list_for_each_entry(cell, &nvmem->cells, node) { | ||||||
|  | 		if (index == i++) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	mutex_unlock(&nvmem_mutex); | ||||||
|  | 
 | ||||||
|  | 	return cell; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) | ||||||
|  | { | ||||||
|  | 	struct device_node *parent, *child; | ||||||
|  | 	struct device *dev = &nvmem->dev; | ||||||
|  | 	struct nvmem_cell *cell; | ||||||
|  | 	const __be32 *addr; | ||||||
|  | 	int len; | ||||||
|  | 
 | ||||||
|  | 	parent = dev->of_node; | ||||||
|  | 
 | ||||||
|  | 	for_each_child_of_node(parent, child) { | ||||||
|  | 		addr = of_get_property(child, "reg", &len); | ||||||
|  | 		if (!addr || (len < 2 * sizeof(u32))) { | ||||||
|  | 			dev_err(dev, "nvmem: invalid reg on %pOF\n", child); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		cell = kzalloc(sizeof(*cell), GFP_KERNEL); | ||||||
|  | 		if (!cell) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 		cell->nvmem = nvmem; | ||||||
|  | 		cell->offset = be32_to_cpup(addr++); | ||||||
|  | 		cell->bytes = be32_to_cpup(addr); | ||||||
|  | 		cell->name = child->name; | ||||||
|  | 
 | ||||||
|  | 		addr = of_get_property(child, "bits", &len); | ||||||
|  | 		if (addr && len == (2 * sizeof(u32))) { | ||||||
|  | 			cell->bit_offset = be32_to_cpup(addr++); | ||||||
|  | 			cell->nbits = be32_to_cpup(addr); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (cell->nbits) | ||||||
|  | 			cell->bytes = DIV_ROUND_UP( | ||||||
|  | 					cell->nbits + cell->bit_offset, | ||||||
|  | 					BITS_PER_BYTE); | ||||||
|  | 
 | ||||||
|  | 		if (!IS_ALIGNED(cell->offset, nvmem->stride)) { | ||||||
|  | 			dev_err(dev, "cell %s unaligned to nvmem stride %d\n", | ||||||
|  | 				cell->name, nvmem->stride); | ||||||
|  | 			/* Cells already added will be freed later. */ | ||||||
|  | 			kfree(cell); | ||||||
|  | 			return -EINVAL; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		nvmem_cell_add(cell); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * nvmem_register() - Register a nvmem device for given nvmem_config. |  * nvmem_register() - Register a nvmem device for given nvmem_config. | ||||||
|  * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem |  * 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) | |||||||
| 	if (rval) | 	if (rval) | ||||||
| 		goto err_remove_cells; | 		goto err_remove_cells; | ||||||
| 
 | 
 | ||||||
|  | 	rval = nvmem_add_cells_from_of(nvmem); | ||||||
|  | 	if (rval) | ||||||
|  | 		goto err_remove_cells; | ||||||
|  | 
 | ||||||
| 	return nvmem; | 	return nvmem; | ||||||
| 
 | 
 | ||||||
| err_remove_cells: | err_remove_cells: | ||||||
| @ -848,10 +919,8 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, | |||||||
| 					    const char *name) | 					    const char *name) | ||||||
| { | { | ||||||
| 	struct device_node *cell_np, *nvmem_np; | 	struct device_node *cell_np, *nvmem_np; | ||||||
| 	struct nvmem_cell *cell; |  | ||||||
| 	struct nvmem_device *nvmem; | 	struct nvmem_device *nvmem; | ||||||
| 	const __be32 *addr; | 	struct nvmem_cell *cell; | ||||||
| 	int rval, len; |  | ||||||
| 	int index = 0; | 	int index = 0; | ||||||
| 
 | 
 | ||||||
| 	/* if cell name exists, find index to the name */ | 	/* if cell name exists, find index to the name */ | ||||||
| @ -871,54 +940,13 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, | |||||||
| 	if (IS_ERR(nvmem)) | 	if (IS_ERR(nvmem)) | ||||||
| 		return ERR_CAST(nvmem); | 		return ERR_CAST(nvmem); | ||||||
| 
 | 
 | ||||||
| 	addr = of_get_property(cell_np, "reg", &len); | 	cell = nvmem_find_cell_by_index(nvmem, index); | ||||||
| 	if (!addr || (len < 2 * sizeof(u32))) { |  | ||||||
| 		dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", |  | ||||||
| 			cell_np); |  | ||||||
| 		rval  = -EINVAL; |  | ||||||
| 		goto err_mem; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	cell = kzalloc(sizeof(*cell), GFP_KERNEL); |  | ||||||
| 	if (!cell) { | 	if (!cell) { | ||||||
| 		rval = -ENOMEM; | 		__nvmem_device_put(nvmem); | ||||||
| 		goto err_mem; | 		return ERR_PTR(-ENOENT); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cell->nvmem = nvmem; |  | ||||||
| 	cell->offset = be32_to_cpup(addr++); |  | ||||||
| 	cell->bytes = be32_to_cpup(addr); |  | ||||||
| 	cell->name = cell_np->name; |  | ||||||
| 
 |  | ||||||
| 	addr = of_get_property(cell_np, "bits", &len); |  | ||||||
| 	if (addr && len == (2 * sizeof(u32))) { |  | ||||||
| 		cell->bit_offset = be32_to_cpup(addr++); |  | ||||||
| 		cell->nbits = be32_to_cpup(addr); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (cell->nbits) |  | ||||||
| 		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, |  | ||||||
| 					   BITS_PER_BYTE); |  | ||||||
| 
 |  | ||||||
| 	if (!IS_ALIGNED(cell->offset, nvmem->stride)) { |  | ||||||
| 			dev_err(&nvmem->dev, |  | ||||||
| 				"cell %s unaligned to nvmem stride %d\n", |  | ||||||
| 				cell->name, nvmem->stride); |  | ||||||
| 		rval  = -EINVAL; |  | ||||||
| 		goto err_sanity; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	nvmem_cell_add(cell); |  | ||||||
| 
 |  | ||||||
| 	return cell; | 	return cell; | ||||||
| 
 |  | ||||||
| err_sanity: |  | ||||||
| 	kfree(cell); |  | ||||||
| 
 |  | ||||||
| err_mem: |  | ||||||
| 	__nvmem_device_put(nvmem); |  | ||||||
| 
 |  | ||||||
| 	return ERR_PTR(rval); |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(of_nvmem_cell_get); | EXPORT_SYMBOL_GPL(of_nvmem_cell_get); | ||||||
| #endif | #endif | ||||||
| @ -1024,7 +1052,6 @@ void nvmem_cell_put(struct nvmem_cell *cell) | |||||||
| 	struct nvmem_device *nvmem = cell->nvmem; | 	struct nvmem_device *nvmem = cell->nvmem; | ||||||
| 
 | 
 | ||||||
| 	__nvmem_device_put(nvmem); | 	__nvmem_device_put(nvmem); | ||||||
| 	nvmem_cell_drop(cell); |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(nvmem_cell_put); | EXPORT_SYMBOL_GPL(nvmem_cell_put); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user