Skip to content

Commit 124fe20

Browse files
committed
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 <[email protected]> Reviewed-by: Toshi Kani <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent f6ef5a2 commit 124fe20

File tree

2 files changed

+44
-26
lines changed

2 files changed

+44
-26
lines changed

include/linux/mm.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,14 @@ static inline int put_page_unless_one(struct page *page)
369369
}
370370

371371
extern int page_is_ram(unsigned long pfn);
372-
extern int region_is_ram(resource_size_t phys_addr, unsigned long size);
372+
373+
enum {
374+
REGION_INTERSECTS,
375+
REGION_DISJOINT,
376+
REGION_MIXED,
377+
};
378+
379+
int region_intersects(resource_size_t offset, size_t size, const char *type);
373380

374381
/* Support for virtually mapped pages */
375382
struct page *vmalloc_to_page(const void *addr);

kernel/resource.c

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -492,40 +492,51 @@ int __weak page_is_ram(unsigned long pfn)
492492
}
493493
EXPORT_SYMBOL_GPL(page_is_ram);
494494

495-
/*
496-
* Search for a resouce entry that fully contains the specified region.
497-
* If found, return 1 if it is RAM, 0 if not.
498-
* If not found, or region is not fully contained, return -1
495+
/**
496+
* region_intersects() - determine intersection of region with known resources
497+
* @start: region start address
498+
* @size: size of region
499+
* @name: name of resource (in iomem_resource)
499500
*
500-
* Used by the ioremap functions to ensure the user is not remapping RAM and is
501-
* a vast speed up over walking through the resource table page by page.
501+
* Check if the specified region partially overlaps or fully eclipses a
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.
502512
*/
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)
504514
{
505-
struct resource *p;
506-
resource_size_t end = start + size - 1;
507515
unsigned long flags = IORESOURCE_MEM | IORESOURCE_BUSY;
508-
const char *name = "System RAM";
509-
int ret = -1;
516+
resource_size_t end = start + size - 1;
517+
int type = 0; int other = 0;
518+
struct resource *p;
510519

511520
read_lock(&resource_lock);
512521
for (p = iomem_resource.child; p ; p = p->sibling) {
513-
if (p->end < start)
514-
continue;
515-
516-
if (p->start <= start && end <= p->end) {
517-
/* resource fully contains region */
518-
if ((p->flags != flags) || strcmp(p->name, name))
519-
ret = 0;
520-
else
521-
ret = 1;
522-
break;
523-
}
524-
if (end < p->start)
525-
break; /* not found */
522+
bool is_type = strcmp(p->name, name) == 0 && p->flags == flags;
523+
524+
if (start >= p->start && start <= p->end)
525+
is_type ? type++ : other++;
526+
if (end >= p->start && end <= p->end)
527+
is_type ? type++ : other++;
528+
if (p->start >= start && p->end <= end)
529+
is_type ? type++ : other++;
526530
}
527531
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;
529540
}
530541

531542
void __weak arch_remove_reservations(struct resource *avail)

0 commit comments

Comments
 (0)