aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/resource.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2015-08-10 23:07:05 -0400
committerDan Williams <dan.j.williams@intel.com>2015-08-10 23:07:05 -0400
commit124fe20d94630b6f173dae5eb815e6e6e350c72d (patch)
treefc550c3a1a497f770b81b87ca574a1273dd965a7 /kernel/resource.c
parentf6ef5a2a50816b58e3126206de13d0b9fdf89df5 (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.c61
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}
493EXPORT_SYMBOL_GPL(page_is_ram); 493EXPORT_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 */
503int region_is_ram(resource_size_t start, unsigned long size) 513int 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
531void __weak arch_remove_reservations(struct resource *avail) 542void __weak arch_remove_reservations(struct resource *avail)