forked from Minki/linux
devres: allow adding custom actions to the stack
Sometimes drivers need to execute one-off actions in their error handling or device teardown paths. An example would be toggling a GPIO line to reset the controlled device into predefined state. To allow performing such actions when using managed resources let's allow adding them to stack/group of devres resources. Acked-by: Tejun Heo <tj@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
7241443f67
commit
d6b0c58048
@ -670,6 +670,80 @@ int devres_release_group(struct device *dev, void *id)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devres_release_group);
|
||||
|
||||
/*
|
||||
* Custom devres actions allow inserting a simple function call
|
||||
* into the teadown sequence.
|
||||
*/
|
||||
|
||||
struct action_devres {
|
||||
void *data;
|
||||
void (*action)(void *);
|
||||
};
|
||||
|
||||
static int devm_action_match(struct device *dev, void *res, void *p)
|
||||
{
|
||||
struct action_devres *devres = res;
|
||||
struct action_devres *target = p;
|
||||
|
||||
return devres->action == target->action &&
|
||||
devres->data == target->data;
|
||||
}
|
||||
|
||||
static void devm_action_release(struct device *dev, void *res)
|
||||
{
|
||||
struct action_devres *devres = res;
|
||||
|
||||
devres->action(devres->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_add_action() - add a custom action to list of managed resources
|
||||
* @dev: Device that owns the action
|
||||
* @action: Function that should be called
|
||||
* @data: Pointer to data passed to @action implementation
|
||||
*
|
||||
* This adds a custom action to the list of managed resources so that
|
||||
* it gets executed as part of standard resource unwinding.
|
||||
*/
|
||||
int devm_add_action(struct device *dev, void (*action)(void *), void *data)
|
||||
{
|
||||
struct action_devres *devres;
|
||||
|
||||
devres = devres_alloc(devm_action_release,
|
||||
sizeof(struct action_devres), GFP_KERNEL);
|
||||
if (!devres)
|
||||
return -ENOMEM;
|
||||
|
||||
devres->data = data;
|
||||
devres->action = action;
|
||||
|
||||
devres_add(dev, devres);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_add_action);
|
||||
|
||||
/**
|
||||
* devm_remove_action() - removes previously added custom action
|
||||
* @dev: Device that owns the action
|
||||
* @action: Function implementing the action
|
||||
* @data: Pointer to data passed to @action implementation
|
||||
*
|
||||
* Removes instance of @action previously added by devm_add_action().
|
||||
* Both action and data should match one of the existing entries.
|
||||
*/
|
||||
void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
|
||||
{
|
||||
struct action_devres devres = {
|
||||
.data = data,
|
||||
.action = action,
|
||||
};
|
||||
|
||||
WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match,
|
||||
&devres));
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_remove_action);
|
||||
|
||||
/*
|
||||
* Managed kzalloc/kfree
|
||||
*/
|
||||
|
@ -567,6 +567,10 @@ extern void devm_kfree(struct device *dev, void *p);
|
||||
void __iomem *devm_request_and_ioremap(struct device *dev,
|
||||
struct resource *res);
|
||||
|
||||
/* allows to add/remove a custom action to devres stack */
|
||||
int devm_add_action(struct device *dev, void (*action)(void *), void *data);
|
||||
void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
|
||||
|
||||
struct device_dma_parameters {
|
||||
/*
|
||||
* a low level driver may set these to teach IOMMU code about
|
||||
|
Loading…
Reference in New Issue
Block a user