[for 4.3-final PATCH v2] memremap: fix highmem support
Ard Biesheuvel
ard.biesheuvel at linaro.org
Fri Oct 30 23:30:30 PDT 2015
On 30 October 2015 at 21:19, Dan Williams <dan.j.williams at intel.com> wrote:
> 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 at intel.com>
> Reported-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
> Signed-off-by: Dan Williams <dan.j.williams at intel.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
This does still leave the issue that we assume that lowmem memory
ranges listed as 'System RAM' in /proc/iomem are always covered by the
linear mapping. Since the semantics of 'System RAM' are not documented
anywhere (as far as I know), this may not be universally true on all
architectures.
> ---
> kernel/memremap.c | 14 ++++++++++++--
> 1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/memremap.c b/kernel/memremap.c
> index 72b0c66628b6..9d6b55587eaa 100644
> --- a/kernel/memremap.c
> +++ b/kernel/memremap.c
> @@ -24,6 +24,16 @@ __weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size)
> }
> #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
> * @offset: iomem resource start address
> @@ -66,8 +76,8 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags)
> * the requested range is potentially in "System RAM"
> */
> if (is_ram == REGION_INTERSECTS)
> - addr = __va(offset);
> - else
> + addr = try_ram_remap(offset, size);
> + if (!addr)
> addr = ioremap_cache(offset, size);
> }
>
>
More information about the linux-arm-kernel
mailing list