Commit 182475b7 authored by Dan Williams's avatar Dan Williams

memremap: fix highmem support

Currently memremap checks if the range is "System RAM" and returns the
kernel linear address.  This is broken for highmem platforms where a
range may be "System RAM", but is not part of the kernel linear mapping.
Fallback to ioremap_cache() in these cases, to let the arch code attempt
to handle it.

Note that ARM ioremap will WARN when attempting to remap ram, and in
that case the caller needs to be fixed.  For this reason, existing
ioremap_cache() usages for ARM are already trained to avoid attempts to
remap ram.

The impact of this bug is low for now since the pmem driver is the only
user of memremap(), but this is important to fix before more conversions
to memremap arrive in 4.4.

Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reported-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 25cb62b7
...@@ -24,6 +24,16 @@ __weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size) ...@@ -24,6 +24,16 @@ __weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size)
} }
#endif #endif
static void *try_ram_remap(resource_size_t offset, size_t size)
{
struct page *page = pfn_to_page(offset >> PAGE_SHIFT);
/* In the simple case just return the existing linear address */
if (!PageHighMem(page))
return __va(offset);
return NULL; /* fallback to ioremap_cache */
}
/** /**
* memremap() - remap an iomem_resource as cacheable memory * memremap() - remap an iomem_resource as cacheable memory
* @offset: iomem resource start address * @offset: iomem resource start address
...@@ -66,8 +76,8 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags) ...@@ -66,8 +76,8 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags)
* the requested range is potentially in "System RAM" * the requested range is potentially in "System RAM"
*/ */
if (is_ram == REGION_INTERSECTS) if (is_ram == REGION_INTERSECTS)
addr = __va(offset); addr = try_ram_remap(offset, size);
else if (!addr)
addr = ioremap_cache(offset, size); addr = ioremap_cache(offset, size);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment