diff options
Diffstat (limited to 'kernel/resource.c')
-rw-r--r-- | kernel/resource.c | 141 |
1 files changed, 63 insertions, 78 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index 30e1bc68503b..b3a3a1fc499e 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -318,33 +318,34 @@ int release_resource(struct resource *old) | |||
318 | 318 | ||
319 | EXPORT_SYMBOL(release_resource); | 319 | EXPORT_SYMBOL(release_resource); |
320 | 320 | ||
321 | /* | 321 | /** |
322 | * Finds the lowest iomem resource existing within [res->start.res->end). | 322 | * Finds the lowest iomem resource that covers part of [start..end]. The |
323 | * The caller must specify res->start, res->end, res->flags, and optionally | 323 | * caller must specify start, end, flags, and desc (which may be |
324 | * desc. If found, returns 0, res is overwritten, if not found, returns -1. | 324 | * IORES_DESC_NONE). |
325 | * This function walks the whole tree and not just first level children until | 325 | * |
326 | * and unless first_level_children_only is true. | 326 | * If a resource is found, returns 0 and *res is overwritten with the part |
327 | * of the resource that's within [start..end]; if none is found, returns | ||
328 | * -1. | ||
329 | * | ||
330 | * This function walks the whole tree and not just first level children | ||
331 | * unless @first_lvl is true. | ||
327 | */ | 332 | */ |
328 | static int find_next_iomem_res(struct resource *res, unsigned long desc, | 333 | static int find_next_iomem_res(resource_size_t start, resource_size_t end, |
329 | bool first_level_children_only) | 334 | unsigned long flags, unsigned long desc, |
335 | bool first_lvl, struct resource *res) | ||
330 | { | 336 | { |
331 | resource_size_t start, end; | ||
332 | struct resource *p; | 337 | struct resource *p; |
333 | bool sibling_only = false; | ||
334 | 338 | ||
335 | BUG_ON(!res); | 339 | if (!res) |
336 | 340 | return -EINVAL; | |
337 | start = res->start; | ||
338 | end = res->end; | ||
339 | BUG_ON(start >= end); | ||
340 | 341 | ||
341 | if (first_level_children_only) | 342 | if (start >= end) |
342 | sibling_only = true; | 343 | return -EINVAL; |
343 | 344 | ||
344 | read_lock(&resource_lock); | 345 | read_lock(&resource_lock); |
345 | 346 | ||
346 | for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) { | 347 | for (p = iomem_resource.child; p; p = next_resource(p, first_lvl)) { |
347 | if ((p->flags & res->flags) != res->flags) | 348 | if ((p->flags & flags) != flags) |
348 | continue; | 349 | continue; |
349 | if ((desc != IORES_DESC_NONE) && (desc != p->desc)) | 350 | if ((desc != IORES_DESC_NONE) && (desc != p->desc)) |
350 | continue; | 351 | continue; |
@@ -352,45 +353,43 @@ static int find_next_iomem_res(struct resource *res, unsigned long desc, | |||
352 | p = NULL; | 353 | p = NULL; |
353 | break; | 354 | break; |
354 | } | 355 | } |
355 | if ((p->end >= start) && (p->start < end)) | 356 | if ((p->end >= start) && (p->start <= end)) |
356 | break; | 357 | break; |
357 | } | 358 | } |
358 | 359 | ||
359 | read_unlock(&resource_lock); | 360 | read_unlock(&resource_lock); |
360 | if (!p) | 361 | if (!p) |
361 | return -1; | 362 | return -1; |
363 | |||
362 | /* copy data */ | 364 | /* copy data */ |
363 | if (res->start < p->start) | 365 | res->start = max(start, p->start); |
364 | res->start = p->start; | 366 | res->end = min(end, p->end); |
365 | if (res->end > p->end) | ||
366 | res->end = p->end; | ||
367 | res->flags = p->flags; | 367 | res->flags = p->flags; |
368 | res->desc = p->desc; | 368 | res->desc = p->desc; |
369 | return 0; | 369 | return 0; |
370 | } | 370 | } |
371 | 371 | ||
372 | static int __walk_iomem_res_desc(struct resource *res, unsigned long desc, | 372 | static int __walk_iomem_res_desc(resource_size_t start, resource_size_t end, |
373 | bool first_level_children_only, | 373 | unsigned long flags, unsigned long desc, |
374 | void *arg, | 374 | bool first_lvl, void *arg, |
375 | int (*func)(struct resource *, void *)) | 375 | int (*func)(struct resource *, void *)) |
376 | { | 376 | { |
377 | u64 orig_end = res->end; | 377 | struct resource res; |
378 | int ret = -1; | 378 | int ret = -1; |
379 | 379 | ||
380 | while ((res->start < res->end) && | 380 | while (start < end && |
381 | !find_next_iomem_res(res, desc, first_level_children_only)) { | 381 | !find_next_iomem_res(start, end, flags, desc, first_lvl, &res)) { |
382 | ret = (*func)(res, arg); | 382 | ret = (*func)(&res, arg); |
383 | if (ret) | 383 | if (ret) |
384 | break; | 384 | break; |
385 | 385 | ||
386 | res->start = res->end + 1; | 386 | start = res.end + 1; |
387 | res->end = orig_end; | ||
388 | } | 387 | } |
389 | 388 | ||
390 | return ret; | 389 | return ret; |
391 | } | 390 | } |
392 | 391 | ||
393 | /* | 392 | /** |
394 | * Walks through iomem resources and calls func() with matching resource | 393 | * Walks through iomem resources and calls func() with matching resource |
395 | * ranges. This walks through whole tree and not just first level children. | 394 | * ranges. This walks through whole tree and not just first level children. |
396 | * All the memory ranges which overlap start,end and also match flags and | 395 | * All the memory ranges which overlap start,end and also match flags and |
@@ -407,13 +406,7 @@ static int __walk_iomem_res_desc(struct resource *res, unsigned long desc, | |||
407 | int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, | 406 | int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, |
408 | u64 end, void *arg, int (*func)(struct resource *, void *)) | 407 | u64 end, void *arg, int (*func)(struct resource *, void *)) |
409 | { | 408 | { |
410 | struct resource res; | 409 | return __walk_iomem_res_desc(start, end, flags, desc, false, arg, func); |
411 | |||
412 | res.start = start; | ||
413 | res.end = end; | ||
414 | res.flags = flags; | ||
415 | |||
416 | return __walk_iomem_res_desc(&res, desc, false, arg, func); | ||
417 | } | 410 | } |
418 | EXPORT_SYMBOL_GPL(walk_iomem_res_desc); | 411 | EXPORT_SYMBOL_GPL(walk_iomem_res_desc); |
419 | 412 | ||
@@ -425,15 +418,11 @@ EXPORT_SYMBOL_GPL(walk_iomem_res_desc); | |||
425 | * ranges. | 418 | * ranges. |
426 | */ | 419 | */ |
427 | int walk_system_ram_res(u64 start, u64 end, void *arg, | 420 | int walk_system_ram_res(u64 start, u64 end, void *arg, |
428 | int (*func)(struct resource *, void *)) | 421 | int (*func)(struct resource *, void *)) |
429 | { | 422 | { |
430 | struct resource res; | 423 | unsigned long flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
431 | 424 | ||
432 | res.start = start; | 425 | return __walk_iomem_res_desc(start, end, flags, IORES_DESC_NONE, true, |
433 | res.end = end; | ||
434 | res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | ||
435 | |||
436 | return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true, | ||
437 | arg, func); | 426 | arg, func); |
438 | } | 427 | } |
439 | 428 | ||
@@ -444,13 +433,9 @@ int walk_system_ram_res(u64 start, u64 end, void *arg, | |||
444 | int walk_mem_res(u64 start, u64 end, void *arg, | 433 | int walk_mem_res(u64 start, u64 end, void *arg, |
445 | int (*func)(struct resource *, void *)) | 434 | int (*func)(struct resource *, void *)) |
446 | { | 435 | { |
447 | struct resource res; | 436 | unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
448 | |||
449 | res.start = start; | ||
450 | res.end = end; | ||
451 | res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
452 | 437 | ||
453 | return __walk_iomem_res_desc(&res, IORES_DESC_NONE, true, | 438 | return __walk_iomem_res_desc(start, end, flags, IORES_DESC_NONE, true, |
454 | arg, func); | 439 | arg, func); |
455 | } | 440 | } |
456 | 441 | ||
@@ -462,27 +447,27 @@ int walk_mem_res(u64 start, u64 end, void *arg, | |||
462 | * It is to be used only for System RAM. | 447 | * It is to be used only for System RAM. |
463 | */ | 448 | */ |
464 | int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, | 449 | int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, |
465 | void *arg, int (*func)(unsigned long, unsigned long, void *)) | 450 | void *arg, int (*func)(unsigned long, unsigned long, void *)) |
466 | { | 451 | { |
452 | resource_size_t start, end; | ||
453 | unsigned long flags; | ||
467 | struct resource res; | 454 | struct resource res; |
468 | unsigned long pfn, end_pfn; | 455 | unsigned long pfn, end_pfn; |
469 | u64 orig_end; | ||
470 | int ret = -1; | 456 | int ret = -1; |
471 | 457 | ||
472 | res.start = (u64) start_pfn << PAGE_SHIFT; | 458 | start = (u64) start_pfn << PAGE_SHIFT; |
473 | res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; | 459 | end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; |
474 | res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; | 460 | flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; |
475 | orig_end = res.end; | 461 | while (start < end && |
476 | while ((res.start < res.end) && | 462 | !find_next_iomem_res(start, end, flags, IORES_DESC_NONE, |
477 | (find_next_iomem_res(&res, IORES_DESC_NONE, true) >= 0)) { | 463 | true, &res)) { |
478 | pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT; | 464 | pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT; |
479 | end_pfn = (res.end + 1) >> PAGE_SHIFT; | 465 | end_pfn = (res.end + 1) >> PAGE_SHIFT; |
480 | if (end_pfn > pfn) | 466 | if (end_pfn > pfn) |
481 | ret = (*func)(pfn, end_pfn - pfn, arg); | 467 | ret = (*func)(pfn, end_pfn - pfn, arg); |
482 | if (ret) | 468 | if (ret) |
483 | break; | 469 | break; |
484 | res.start = res.end + 1; | 470 | start = res.end + 1; |
485 | res.end = orig_end; | ||
486 | } | 471 | } |
487 | return ret; | 472 | return ret; |
488 | } | 473 | } |
@@ -658,8 +643,8 @@ static int find_resource(struct resource *root, struct resource *new, | |||
658 | * @constraint: the size and alignment constraints to be met. | 643 | * @constraint: the size and alignment constraints to be met. |
659 | */ | 644 | */ |
660 | static int reallocate_resource(struct resource *root, struct resource *old, | 645 | static int reallocate_resource(struct resource *root, struct resource *old, |
661 | resource_size_t newsize, | 646 | resource_size_t newsize, |
662 | struct resource_constraint *constraint) | 647 | struct resource_constraint *constraint) |
663 | { | 648 | { |
664 | int err=0; | 649 | int err=0; |
665 | struct resource new = *old; | 650 | struct resource new = *old; |
@@ -972,7 +957,7 @@ skip: | |||
972 | * Existing children of the resource are assumed to be immutable. | 957 | * Existing children of the resource are assumed to be immutable. |
973 | */ | 958 | */ |
974 | int adjust_resource(struct resource *res, resource_size_t start, | 959 | int adjust_resource(struct resource *res, resource_size_t start, |
975 | resource_size_t size) | 960 | resource_size_t size) |
976 | { | 961 | { |
977 | int result; | 962 | int result; |
978 | 963 | ||
@@ -983,9 +968,9 @@ int adjust_resource(struct resource *res, resource_size_t start, | |||
983 | } | 968 | } |
984 | EXPORT_SYMBOL(adjust_resource); | 969 | EXPORT_SYMBOL(adjust_resource); |
985 | 970 | ||
986 | static void __init __reserve_region_with_split(struct resource *root, | 971 | static void __init |
987 | resource_size_t start, resource_size_t end, | 972 | __reserve_region_with_split(struct resource *root, resource_size_t start, |
988 | const char *name) | 973 | resource_size_t end, const char *name) |
989 | { | 974 | { |
990 | struct resource *parent = root; | 975 | struct resource *parent = root; |
991 | struct resource *conflict; | 976 | struct resource *conflict; |
@@ -1044,9 +1029,9 @@ static void __init __reserve_region_with_split(struct resource *root, | |||
1044 | 1029 | ||
1045 | } | 1030 | } |
1046 | 1031 | ||
1047 | void __init reserve_region_with_split(struct resource *root, | 1032 | void __init |
1048 | resource_size_t start, resource_size_t end, | 1033 | reserve_region_with_split(struct resource *root, resource_size_t start, |
1049 | const char *name) | 1034 | resource_size_t end, const char *name) |
1050 | { | 1035 | { |
1051 | int abort = 0; | 1036 | int abort = 0; |
1052 | 1037 | ||
@@ -1172,7 +1157,7 @@ EXPORT_SYMBOL(__request_region); | |||
1172 | * The described resource region must match a currently busy region. | 1157 | * The described resource region must match a currently busy region. |
1173 | */ | 1158 | */ |
1174 | void __release_region(struct resource *parent, resource_size_t start, | 1159 | void __release_region(struct resource *parent, resource_size_t start, |
1175 | resource_size_t n) | 1160 | resource_size_t n) |
1176 | { | 1161 | { |
1177 | struct resource **p; | 1162 | struct resource **p; |
1178 | resource_size_t end; | 1163 | resource_size_t end; |
@@ -1234,7 +1219,7 @@ EXPORT_SYMBOL(__release_region); | |||
1234 | * simplicity. Enhance this logic when necessary. | 1219 | * simplicity. Enhance this logic when necessary. |
1235 | */ | 1220 | */ |
1236 | int release_mem_region_adjustable(struct resource *parent, | 1221 | int release_mem_region_adjustable(struct resource *parent, |
1237 | resource_size_t start, resource_size_t size) | 1222 | resource_size_t start, resource_size_t size) |
1238 | { | 1223 | { |
1239 | struct resource **p; | 1224 | struct resource **p; |
1240 | struct resource *res; | 1225 | struct resource *res; |
@@ -1410,9 +1395,9 @@ static int devm_region_match(struct device *dev, void *res, void *match_data) | |||
1410 | this->start == match->start && this->n == match->n; | 1395 | this->start == match->start && this->n == match->n; |
1411 | } | 1396 | } |
1412 | 1397 | ||
1413 | struct resource * __devm_request_region(struct device *dev, | 1398 | struct resource * |
1414 | struct resource *parent, resource_size_t start, | 1399 | __devm_request_region(struct device *dev, struct resource *parent, |
1415 | resource_size_t n, const char *name) | 1400 | resource_size_t start, resource_size_t n, const char *name) |
1416 | { | 1401 | { |
1417 | struct region_devres *dr = NULL; | 1402 | struct region_devres *dr = NULL; |
1418 | struct resource *res; | 1403 | struct resource *res; |