lib: devres: Introduce devm_ioremap_resource()
The devm_request_and_ioremap() function is very useful and helps avoid a whole lot of boilerplate. However, one issue that keeps popping up is its lack of a specific error code to determine which of the steps that it performs failed. Furthermore, while the function gives an example and suggests what error code to return on failure, a wide variety of error codes are used throughout the tree. In an attempt to fix these problems, this patch adds a new function that drivers can transition to. The devm_ioremap_resource() returns a pointer to the remapped I/O memory on success or an ERR_PTR() encoded error code on failure. Callers can check for failure using IS_ERR() and determine its cause by extracting the error code using PTR_ERR(). devm_request_and_ioremap() is implemented as a wrapper around the new API and return NULL on failure as before. This ensures that backwards compatibility is maintained until all users have been converted to the new API, at which point the old devm_request_and_ioremap() function should be removed. A semantic patch is included which can be used to convert from the old devm_request_and_ioremap() API to the new devm_ioremap_resource() API. Some non-trivial cases may require manual intervention, though. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> Cc: Arnd Bergmann <arnd@arndb.de> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
771d394fbd
commit
75096579c3
4 changed files with 151 additions and 28 deletions
|
@ -266,7 +266,8 @@ IOMAP
|
|||
devm_ioremap()
|
||||
devm_ioremap_nocache()
|
||||
devm_iounmap()
|
||||
devm_request_and_ioremap() : checks resource, requests region, ioremaps
|
||||
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
|
||||
devm_request_and_ioremap() : obsoleted by devm_ioremap_resource()
|
||||
pcim_iomap()
|
||||
pcim_iounmap()
|
||||
pcim_iomap_table() : array of mapped addresses indexed by BAR
|
||||
|
|
|
@ -573,6 +573,7 @@ extern int devres_release_group(struct device *dev, void *id);
|
|||
extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp);
|
||||
extern void devm_kfree(struct device *dev, void *p);
|
||||
|
||||
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
|
||||
void __iomem *devm_request_and_ioremap(struct device *dev,
|
||||
struct resource *res);
|
||||
|
||||
|
|
85
lib/devres.c
85
lib/devres.c
|
@ -85,6 +85,60 @@ void devm_iounmap(struct device *dev, void __iomem *addr)
|
|||
}
|
||||
EXPORT_SYMBOL(devm_iounmap);
|
||||
|
||||
/**
|
||||
* devm_ioremap_resource() - check, request region, and ioremap resource
|
||||
* @dev: generic device to handle the resource for
|
||||
* @res: resource to be handled
|
||||
*
|
||||
* Checks that a resource is a valid memory region, requests the memory region
|
||||
* and ioremaps it either as cacheable or as non-cacheable memory depending on
|
||||
* the resource's flags. All operations are managed and will be undone on
|
||||
* driver detach.
|
||||
*
|
||||
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
|
||||
* on failure. Usage example:
|
||||
*
|
||||
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
* base = devm_ioremap_resource(&pdev->dev, res);
|
||||
* if (IS_ERR(base))
|
||||
* return PTR_ERR(base);
|
||||
*/
|
||||
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
|
||||
{
|
||||
resource_size_t size;
|
||||
const char *name;
|
||||
void __iomem *dest_ptr;
|
||||
|
||||
BUG_ON(!dev);
|
||||
|
||||
if (!res || resource_type(res) != IORESOURCE_MEM) {
|
||||
dev_err(dev, "invalid resource\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
name = res->name ?: dev_name(dev);
|
||||
|
||||
if (!devm_request_mem_region(dev, res->start, size, name)) {
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
if (res->flags & IORESOURCE_CACHEABLE)
|
||||
dest_ptr = devm_ioremap(dev, res->start, size);
|
||||
else
|
||||
dest_ptr = devm_ioremap_nocache(dev, res->start, size);
|
||||
|
||||
if (!dest_ptr) {
|
||||
dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
devm_release_mem_region(dev, res->start, size);
|
||||
dest_ptr = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return dest_ptr;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_ioremap_resource);
|
||||
|
||||
/**
|
||||
* devm_request_and_ioremap() - Check, request region, and ioremap resource
|
||||
* @dev: Generic device to handle the resource for
|
||||
|
@ -100,37 +154,14 @@ EXPORT_SYMBOL(devm_iounmap);
|
|||
* if (!base)
|
||||
* return -EADDRNOTAVAIL;
|
||||
*/
|
||||
void __iomem *devm_request_and_ioremap(struct device *dev,
|
||||
struct resource *res)
|
||||
void __iomem *devm_request_and_ioremap(struct device *device,
|
||||
struct resource *res)
|
||||
{
|
||||
resource_size_t size;
|
||||
const char *name;
|
||||
void __iomem *dest_ptr;
|
||||
|
||||
BUG_ON(!dev);
|
||||
|
||||
if (!res || resource_type(res) != IORESOURCE_MEM) {
|
||||
dev_err(dev, "invalid resource\n");
|
||||
dest_ptr = devm_ioremap_resource(device, res);
|
||||
if (IS_ERR(dest_ptr))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
name = res->name ?: dev_name(dev);
|
||||
|
||||
if (!devm_request_mem_region(dev, res->start, size, name)) {
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (res->flags & IORESOURCE_CACHEABLE)
|
||||
dest_ptr = devm_ioremap(dev, res->start, size);
|
||||
else
|
||||
dest_ptr = devm_ioremap_nocache(dev, res->start, size);
|
||||
|
||||
if (!dest_ptr) {
|
||||
dev_err(dev, "ioremap failed for resource %pR\n", res);
|
||||
devm_release_mem_region(dev, res->start, size);
|
||||
}
|
||||
|
||||
return dest_ptr;
|
||||
}
|
||||
|
|
90
scripts/coccinelle/api/devm_ioremap_resource.cocci
Normal file
90
scripts/coccinelle/api/devm_ioremap_resource.cocci
Normal file
|
@ -0,0 +1,90 @@
|
|||
virtual patch
|
||||
virtual report
|
||||
|
||||
@depends on patch@
|
||||
expression base, dev, res;
|
||||
@@
|
||||
|
||||
-base = devm_request_and_ioremap(dev, res);
|
||||
+base = devm_ioremap_resource(dev, res);
|
||||
...
|
||||
if (
|
||||
-base == NULL
|
||||
+IS_ERR(base)
|
||||
|| ...) {
|
||||
<...
|
||||
- return ...;
|
||||
+ return PTR_ERR(base);
|
||||
...>
|
||||
}
|
||||
|
||||
@depends on patch@
|
||||
expression e, E, ret;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
e = devm_ioremap_resource(...);
|
||||
...
|
||||
if (IS_ERR(e) || ...) {
|
||||
... when any
|
||||
- ret = E;
|
||||
+ ret = PTR_ERR(e);
|
||||
...
|
||||
(
|
||||
return ret;
|
||||
|
|
||||
goto l;
|
||||
)
|
||||
}
|
||||
|
||||
@depends on patch@
|
||||
expression e;
|
||||
@@
|
||||
|
||||
e = devm_ioremap_resource(...);
|
||||
...
|
||||
if (IS_ERR(e) || ...) {
|
||||
...
|
||||
- \(dev_dbg\|dev_err\|pr_debug\|pr_err\|DRM_ERROR\)(...);
|
||||
...
|
||||
}
|
||||
|
||||
@depends on patch@
|
||||
expression e;
|
||||
identifier l;
|
||||
@@
|
||||
|
||||
e = devm_ioremap_resource(...);
|
||||
...
|
||||
if (IS_ERR(e) || ...)
|
||||
-{
|
||||
(
|
||||
return ...;
|
||||
|
|
||||
goto l;
|
||||
)
|
||||
-}
|
||||
|
||||
@r depends on report@
|
||||
expression e;
|
||||
identifier l;
|
||||
position p1;
|
||||
@@
|
||||
|
||||
*e = devm_request_and_ioremap@p1(...);
|
||||
...
|
||||
if (e == NULL || ...) {
|
||||
...
|
||||
(
|
||||
return ...;
|
||||
|
|
||||
goto l;
|
||||
)
|
||||
}
|
||||
|
||||
@script:python depends on r@
|
||||
p1 << r.p1;
|
||||
@@
|
||||
|
||||
msg = "ERROR: deprecated devm_request_and_ioremap() API used on line %s" % (p1[0].line)
|
||||
coccilib.report.print_report(p1[0], msg)
|
Loading…
Reference in a new issue