@@ -10,6 +10,15 @@ void devm_ioremap_release(struct device *dev, void *res)
iounmap(*(void __iomem **)res);
}
+void devm_ioremap_release_region(struct device *dev, void *res)
+{
+ resource_size_t offset = ((struct resource *)res)->start;
+ resource_size_t size = resource_size((struct resource *)res);
+
+ iounmap(*(void __iomem **)res);
+ devm_release_mem_region(dev, offset, size);
+}
+
static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
{
return *(void **)res == match_data;
@@ -136,7 +145,7 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
{
resource_size_t size;
const char *name;
- void __iomem *dest_ptr;
+ void __iomem *addr, **ptr;
BUG_ON(!dev);
@@ -153,14 +162,25 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)
return IOMEM_ERR_PTR(-EBUSY);
}
- dest_ptr = devm_ioremap(dev, res->start, size);
- if (!dest_ptr) {
+ ptr = devres_alloc(devm_ioremap_release_region, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr) {
+ dev_err(dev, "malloc failed for resource %pR\n", res);
+ devm_release_mem_region(dev, res->start, size);
+ return IOMEM_ERR_PTR(-ENOMEM);
+ }
+
+ addr = ioremap(res->start, size);
+ if (addr) {
+ *ptr = addr;
+ devres_add(dev, ptr);
+ } else {
dev_err(dev, "ioremap failed for resource %pR\n", res);
devm_release_mem_region(dev, res->start, size);
- dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
+ devres_free(ptr);
+ addr = IOMEM_ERR_PTR(-ENOMEM);
}
- return dest_ptr;
+ return addr;
}
EXPORT_SYMBOL(devm_ioremap_resource);