diff options
Diffstat (limited to 'kernel/resource.c')
-rw-r--r-- | kernel/resource.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index 60c5a3856ab7..46322019ab7d 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -1245,6 +1245,76 @@ int release_mem_region_adjustable(struct resource *parent, | |||
1245 | /* | 1245 | /* |
1246 | * Managed region resource | 1246 | * Managed region resource |
1247 | */ | 1247 | */ |
1248 | static void devm_resource_release(struct device *dev, void *ptr) | ||
1249 | { | ||
1250 | struct resource **r = ptr; | ||
1251 | |||
1252 | release_resource(*r); | ||
1253 | } | ||
1254 | |||
1255 | /** | ||
1256 | * devm_request_resource() - request and reserve an I/O or memory resource | ||
1257 | * @dev: device for which to request the resource | ||
1258 | * @root: root of the resource tree from which to request the resource | ||
1259 | * @new: descriptor of the resource to request | ||
1260 | * | ||
1261 | * This is a device-managed version of request_resource(). There is usually | ||
1262 | * no need to release resources requested by this function explicitly since | ||
1263 | * that will be taken care of when the device is unbound from its driver. | ||
1264 | * If for some reason the resource needs to be released explicitly, because | ||
1265 | * of ordering issues for example, drivers must call devm_release_resource() | ||
1266 | * rather than the regular release_resource(). | ||
1267 | * | ||
1268 | * When a conflict is detected between any existing resources and the newly | ||
1269 | * requested resource, an error message will be printed. | ||
1270 | * | ||
1271 | * Returns 0 on success or a negative error code on failure. | ||
1272 | */ | ||
1273 | int devm_request_resource(struct device *dev, struct resource *root, | ||
1274 | struct resource *new) | ||
1275 | { | ||
1276 | struct resource *conflict, **ptr; | ||
1277 | |||
1278 | ptr = devres_alloc(devm_resource_release, sizeof(*ptr), GFP_KERNEL); | ||
1279 | if (!ptr) | ||
1280 | return -ENOMEM; | ||
1281 | |||
1282 | *ptr = new; | ||
1283 | |||
1284 | conflict = request_resource_conflict(root, new); | ||
1285 | if (conflict) { | ||
1286 | dev_err(dev, "resource collision: %pR conflicts with %s %pR\n", | ||
1287 | new, conflict->name, conflict); | ||
1288 | devres_free(ptr); | ||
1289 | return -EBUSY; | ||
1290 | } | ||
1291 | |||
1292 | devres_add(dev, ptr); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | EXPORT_SYMBOL(devm_request_resource); | ||
1296 | |||
1297 | static int devm_resource_match(struct device *dev, void *res, void *data) | ||
1298 | { | ||
1299 | struct resource **ptr = res; | ||
1300 | |||
1301 | return *ptr == data; | ||
1302 | } | ||
1303 | |||
1304 | /** | ||
1305 | * devm_release_resource() - release a previously requested resource | ||
1306 | * @dev: device for which to release the resource | ||
1307 | * @new: descriptor of the resource to release | ||
1308 | * | ||
1309 | * Releases a resource previously requested using devm_request_resource(). | ||
1310 | */ | ||
1311 | void devm_release_resource(struct device *dev, struct resource *new) | ||
1312 | { | ||
1313 | WARN_ON(devres_release(dev, devm_resource_release, devm_resource_match, | ||
1314 | new)); | ||
1315 | } | ||
1316 | EXPORT_SYMBOL(devm_release_resource); | ||
1317 | |||
1248 | struct region_devres { | 1318 | struct region_devres { |
1249 | struct resource *parent; | 1319 | struct resource *parent; |
1250 | resource_size_t start; | 1320 | resource_size_t start; |