forked from mirrors/linux
		
	reset: Share struct reset_control between reset_control_get calls
Now that struct reset_control no longer stores the device pointer for the device calling reset_control_get we can share a single struct reset_control when multiple calls to reset_control_get are made for the same reset line (same id / index). This is a preparation patch for adding support for shared reset lines. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
This commit is contained in:
		
							parent
							
								
									6c96f05c8b
								
							
						
					
					
						commit
						c15ddec2ca
					
				
					 2 changed files with 65 additions and 21 deletions
				
			
		|  | @ -18,19 +18,23 @@ | |||
| #include <linux/reset-controller.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| static DEFINE_MUTEX(reset_controller_list_mutex); | ||||
| static DEFINE_MUTEX(reset_list_mutex); | ||||
| static LIST_HEAD(reset_controller_list); | ||||
| 
 | ||||
| /**
 | ||||
|  * struct reset_control - a reset control | ||||
|  * @rcdev: a pointer to the reset controller device | ||||
|  *         this reset control belongs to | ||||
|  * @list: list entry for the rcdev's reset controller list | ||||
|  * @id: ID of the reset controller in the reset | ||||
|  *      controller device | ||||
|  * @refcnt: Number of gets of this reset_control | ||||
|  */ | ||||
| struct reset_control { | ||||
| 	struct reset_controller_dev *rcdev; | ||||
| 	struct list_head list; | ||||
| 	unsigned int id; | ||||
| 	unsigned int refcnt; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -62,9 +66,11 @@ int reset_controller_register(struct reset_controller_dev *rcdev) | |||
| 		rcdev->of_xlate = of_reset_simple_xlate; | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&reset_controller_list_mutex); | ||||
| 	INIT_LIST_HEAD(&rcdev->reset_control_head); | ||||
| 
 | ||||
| 	mutex_lock(&reset_list_mutex); | ||||
| 	list_add(&rcdev->list, &reset_controller_list); | ||||
| 	mutex_unlock(&reset_controller_list_mutex); | ||||
| 	mutex_unlock(&reset_list_mutex); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -76,9 +82,9 @@ EXPORT_SYMBOL_GPL(reset_controller_register); | |||
|  */ | ||||
| void reset_controller_unregister(struct reset_controller_dev *rcdev) | ||||
| { | ||||
| 	mutex_lock(&reset_controller_list_mutex); | ||||
| 	mutex_lock(&reset_list_mutex); | ||||
| 	list_del(&rcdev->list); | ||||
| 	mutex_unlock(&reset_controller_list_mutex); | ||||
| 	mutex_unlock(&reset_list_mutex); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(reset_controller_unregister); | ||||
| 
 | ||||
|  | @ -136,6 +142,48 @@ int reset_control_status(struct reset_control *rstc) | |||
| } | ||||
| EXPORT_SYMBOL_GPL(reset_control_status); | ||||
| 
 | ||||
| static struct reset_control *__reset_control_get( | ||||
| 				struct reset_controller_dev *rcdev, | ||||
| 				unsigned int index) | ||||
| { | ||||
| 	struct reset_control *rstc; | ||||
| 
 | ||||
| 	lockdep_assert_held(&reset_list_mutex); | ||||
| 
 | ||||
| 	list_for_each_entry(rstc, &rcdev->reset_control_head, list) { | ||||
| 		if (rstc->id == index) { | ||||
| 			rstc->refcnt++; | ||||
| 			return rstc; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); | ||||
| 	if (!rstc) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 
 | ||||
| 	try_module_get(rcdev->owner); | ||||
| 
 | ||||
| 	rstc->rcdev = rcdev; | ||||
| 	list_add(&rstc->list, &rcdev->reset_control_head); | ||||
| 	rstc->id = index; | ||||
| 	rstc->refcnt = 1; | ||||
| 
 | ||||
| 	return rstc; | ||||
| } | ||||
| 
 | ||||
| static void __reset_control_put(struct reset_control *rstc) | ||||
| { | ||||
| 	lockdep_assert_held(&reset_list_mutex); | ||||
| 
 | ||||
| 	if (--rstc->refcnt) | ||||
| 		return; | ||||
| 
 | ||||
| 	module_put(rstc->rcdev->owner); | ||||
| 
 | ||||
| 	list_del(&rstc->list); | ||||
| 	kfree(rstc); | ||||
| } | ||||
| 
 | ||||
| struct reset_control *__of_reset_control_get(struct device_node *node, | ||||
| 					     const char *id, int index) | ||||
| { | ||||
|  | @ -160,7 +208,7 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
| 	if (ret) | ||||
| 		return ERR_PTR(ret); | ||||
| 
 | ||||
| 	mutex_lock(&reset_controller_list_mutex); | ||||
| 	mutex_lock(&reset_list_mutex); | ||||
| 	rcdev = NULL; | ||||
| 	list_for_each_entry(r, &reset_controller_list, list) { | ||||
| 		if (args.np == r->of_node) { | ||||
|  | @ -171,32 +219,25 @@ struct reset_control *__of_reset_control_get(struct device_node *node, | |||
| 	of_node_put(args.np); | ||||
| 
 | ||||
| 	if (!rcdev) { | ||||
| 		mutex_unlock(&reset_controller_list_mutex); | ||||
| 		mutex_unlock(&reset_list_mutex); | ||||
| 		return ERR_PTR(-EPROBE_DEFER); | ||||
| 	} | ||||
| 
 | ||||
| 	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { | ||||
| 		mutex_unlock(&reset_controller_list_mutex); | ||||
| 		mutex_unlock(&reset_list_mutex); | ||||
| 		return ERR_PTR(-EINVAL); | ||||
| 	} | ||||
| 
 | ||||
| 	rstc_id = rcdev->of_xlate(rcdev, &args); | ||||
| 	if (rstc_id < 0) { | ||||
| 		mutex_unlock(&reset_controller_list_mutex); | ||||
| 		mutex_unlock(&reset_list_mutex); | ||||
| 		return ERR_PTR(rstc_id); | ||||
| 	} | ||||
| 
 | ||||
| 	try_module_get(rcdev->owner); | ||||
| 	mutex_unlock(&reset_controller_list_mutex); | ||||
| 	/* reset_list_mutex also protects the rcdev's reset_control list */ | ||||
| 	rstc = __reset_control_get(rcdev, rstc_id); | ||||
| 
 | ||||
| 	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL); | ||||
| 	if (!rstc) { | ||||
| 		module_put(rcdev->owner); | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 	} | ||||
| 
 | ||||
| 	rstc->rcdev = rcdev; | ||||
| 	rstc->id = rstc_id; | ||||
| 	mutex_unlock(&reset_list_mutex); | ||||
| 
 | ||||
| 	return rstc; | ||||
| } | ||||
|  | @ -212,8 +253,9 @@ void reset_control_put(struct reset_control *rstc) | |||
| 	if (IS_ERR(rstc)) | ||||
| 		return; | ||||
| 
 | ||||
| 	module_put(rstc->rcdev->owner); | ||||
| 	kfree(rstc); | ||||
| 	mutex_lock(&reset_list_mutex); | ||||
| 	__reset_control_put(rstc); | ||||
| 	mutex_unlock(&reset_list_mutex); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(reset_control_put); | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ struct of_phandle_args; | |||
|  * @ops: a pointer to device specific struct reset_control_ops | ||||
|  * @owner: kernel module of the reset controller driver | ||||
|  * @list: internal list of reset controller devices | ||||
|  * @reset_control_head: head of internal list of requested reset controls | ||||
|  * @of_node: corresponding device tree node as phandle target | ||||
|  * @of_reset_n_cells: number of cells in reset line specifiers | ||||
|  * @of_xlate: translation function to translate from specifier as found in the | ||||
|  | @ -41,6 +42,7 @@ struct reset_controller_dev { | |||
| 	const struct reset_control_ops *ops; | ||||
| 	struct module *owner; | ||||
| 	struct list_head list; | ||||
| 	struct list_head reset_control_head; | ||||
| 	struct device_node *of_node; | ||||
| 	int of_reset_n_cells; | ||||
| 	int (*of_xlate)(struct reset_controller_dev *rcdev, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Hans de Goede
						Hans de Goede