diff options
author | Dan Williams <dan.j.williams@intel.com> | 2015-08-10 23:07:05 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2015-08-10 23:07:05 -0400 |
commit | 124fe20d94630b6f173dae5eb815e6e6e350c72d (patch) | |
tree | fc550c3a1a497f770b81b87ca574a1273dd965a7 /kernel/resource.c | |
parent | f6ef5a2a50816b58e3126206de13d0b9fdf89df5 (diff) |
mm: enhance region_is_ram() to region_intersects()
region_is_ram() is used to prevent the establishment of aliased mappings
to physical "System RAM" with incompatible cache settings. However, it
uses "-1" to indicate both "unknown" memory ranges (ranges not described
by platform firmware) and "mixed" ranges (where the parameters describe
a range that partially overlaps "System RAM").
Fix this up by explicitly tracking the "unknown" vs "mixed" resource
cases and returning REGION_INTERSECTS, REGION_MIXED, or REGION_DISJOINT.
This re-write also adds support for detecting when the requested region
completely eclipses all of a resource. Note, the implementation treats
overlaps between "unknown" and the requested memory type as
REGION_INTERSECTS.
Finally, other memory types can be passed in by name, for now the only
usage "System RAM".
Suggested-by: Luis R. Rodriguez <mcgrof@suse.com>
Reviewed-by: Toshi Kani <toshi.kani@hp.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'kernel/resource.c')
-rw-r--r-- | kernel/resource.c | 61 |
1 files changed, 36 insertions, 25 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index fed052a1bc9f..f150dbbe6f62 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -492,40 +492,51 @@ int __weak page_is_ram(unsigned long pfn) | |||
492 | } | 492 | } |
493 | EXPORT_SYMBOL_GPL(page_is_ram); | 493 | EXPORT_SYMBOL_GPL(page_is_ram); |
494 | 494 | ||
495 | /* | 495 | /** |
496 | * Search for a resouce entry that fully contains the specified region. | 496 | * region_intersects() - determine intersection of region with known resources |
497 | * If found, return 1 if it is RAM, 0 if not. | 497 | * @start: region start address |
498 | * If not found, or region is not fully contained, return -1 | 498 | * @size: size of region |
499 | * @name: name of resource (in iomem_resource) | ||
499 | * | 500 | * |
500 | * Used by the ioremap functions to ensure the user is not remapping RAM and is | 501 | * Check if the specified region partially overlaps or fully eclipses a |
501 | * a vast speed up over walking through the resource table page by page. | 502 | * resource identified by @name. Return REGION_DISJOINT if the region |
503 | * does not overlap @name, return REGION_MIXED if the region overlaps | ||
504 | * @type and another resource, and return REGION_INTERSECTS if the | ||
505 | * region overlaps @type and no other defined resource. Note, that | ||
506 | * REGION_INTERSECTS is also returned in the case when the specified | ||
507 | * region overlaps RAM and undefined memory holes. | ||
508 | * | ||
509 | * region_intersect() is used by memory remapping functions to ensure | ||
510 | * the user is not remapping RAM and is a vast speed up over walking | ||
511 | * through the resource table page by page. | ||
502 | */ | 512 | */ |
503 | int region_is_ram(resource_size_t start, unsigned long size) | 513 | int region_intersects(resource_size_t start, size_t size, const char *name) |
504 | { | 514 | { |
505 | struct resource *p; | ||
506 | resource_size_t end = start + size - 1; | ||
507 | unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 515 | unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY; |
508 | const char *name = "System RAM"; | 516 | resource_size_t end = start + size - 1; |
509 | int ret = -1; | 517 | int type = 0; int other = 0; |
518 | struct resource *p; | ||
510 | 519 | ||
511 | read_lock(&resource_lock); | 520 | read_lock(&resource_lock); |
512 | for (p = iomem_resource.child; p ; p = p->sibling) { | 521 | for (p = iomem_resource.child; p ; p = p->sibling) { |
513 | if (p->end < start) | 522 | bool is_type = strcmp(p->name, name) == 0 && p->flags == flags; |
514 | continue; | 523 | |
515 | 524 | if (start >= p->start && start <= p->end) | |
516 | if (p->start <= start && end <= p->end) { | 525 | is_type ? type++ : other++; |
517 | /* resource fully contains region */ | 526 | if (end >= p->start && end <= p->end) |
518 | if ((p->flags != flags) || strcmp(p->name, name)) | 527 | is_type ? type++ : other++; |
519 | ret = 0; | 528 | if (p->start >= start && p->end <= end) |
520 | else | 529 | is_type ? type++ : other++; |
521 | ret = 1; | ||
522 | break; | ||
523 | } | ||
524 | if (end < p->start) | ||
525 | break; /* not found */ | ||
526 | } | 530 | } |
527 | read_unlock(&resource_lock); | 531 | read_unlock(&resource_lock); |
528 | return ret; | 532 | |
533 | if (other == 0) | ||
534 | return type ? REGION_INTERSECTS : REGION_DISJOINT; | ||
535 | |||
536 | if (type) | ||
537 | return REGION_MIXED; | ||
538 | |||
539 | return REGION_DISJOINT; | ||
529 | } | 540 | } |
530 | 541 | ||
531 | void __weak arch_remove_reservations(struct resource *avail) | 542 | void __weak arch_remove_reservations(struct resource *avail) |