162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P.
462306a36Sopenharmony_ci *	Bjorn Helgaas <bjorn.helgaas@hp.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/compiler.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/efi.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/mm.h>
1262306a36Sopenharmony_ci#include <linux/vmalloc.h>
1362306a36Sopenharmony_ci#include <asm/io.h>
1462306a36Sopenharmony_ci#include <asm/meminit.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic inline void __iomem *
1762306a36Sopenharmony_ci__ioremap_uc(unsigned long phys_addr)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_civoid __iomem *
2362306a36Sopenharmony_ciearly_ioremap (unsigned long phys_addr, unsigned long size)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	u64 attr;
2662306a36Sopenharmony_ci	attr = kern_mem_attribute(phys_addr, size);
2762306a36Sopenharmony_ci	if (attr & EFI_MEMORY_WB)
2862306a36Sopenharmony_ci		return (void __iomem *) phys_to_virt(phys_addr);
2962306a36Sopenharmony_ci	return __ioremap_uc(phys_addr);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_civoid __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
3362306a36Sopenharmony_ci			   unsigned long flags)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	u64 attr;
3662306a36Sopenharmony_ci	unsigned long gran_base, gran_size;
3762306a36Sopenharmony_ci	unsigned long page_base;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/*
4062306a36Sopenharmony_ci	 * For things in kern_memmap, we must use the same attribute
4162306a36Sopenharmony_ci	 * as the rest of the kernel.  For more details, see
4262306a36Sopenharmony_ci	 * Documentation/arch/ia64/aliasing.rst.
4362306a36Sopenharmony_ci	 */
4462306a36Sopenharmony_ci	attr = kern_mem_attribute(phys_addr, size);
4562306a36Sopenharmony_ci	if (attr & EFI_MEMORY_WB)
4662306a36Sopenharmony_ci		return (void __iomem *) phys_to_virt(phys_addr);
4762306a36Sopenharmony_ci	else if (attr & EFI_MEMORY_UC)
4862306a36Sopenharmony_ci		return __ioremap_uc(phys_addr);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/*
5162306a36Sopenharmony_ci	 * Some chipsets don't support UC access to memory.  If
5262306a36Sopenharmony_ci	 * WB is supported for the whole granule, we prefer that.
5362306a36Sopenharmony_ci	 */
5462306a36Sopenharmony_ci	gran_base = GRANULEROUNDDOWN(phys_addr);
5562306a36Sopenharmony_ci	gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base;
5662306a36Sopenharmony_ci	if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
5762306a36Sopenharmony_ci		return (void __iomem *) phys_to_virt(phys_addr);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * WB is not supported for the whole granule, so we can't use
6162306a36Sopenharmony_ci	 * the region 7 identity mapping.  If we can safely cover the
6262306a36Sopenharmony_ci	 * area with kernel page table mappings, we can use those
6362306a36Sopenharmony_ci	 * instead.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	page_base = phys_addr & PAGE_MASK;
6662306a36Sopenharmony_ci	size = PAGE_ALIGN(phys_addr + size) - page_base;
6762306a36Sopenharmony_ci	if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB)
6862306a36Sopenharmony_ci		return generic_ioremap_prot(phys_addr, size, __pgprot(flags));
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return __ioremap_uc(phys_addr);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ciEXPORT_SYMBOL(ioremap_prot);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_civoid __iomem *
7562306a36Sopenharmony_ciioremap_uc(unsigned long phys_addr, unsigned long size)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
7862306a36Sopenharmony_ci		return NULL;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return __ioremap_uc(phys_addr);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ciEXPORT_SYMBOL(ioremap_uc);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_civoid
8562306a36Sopenharmony_ciearly_iounmap (volatile void __iomem *addr, unsigned long size)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_civoid iounmap(volatile void __iomem *addr)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	if (REGION_NUMBER(addr) == RGN_GATE)
9262306a36Sopenharmony_ci		vunmap((void *) ((unsigned long) addr & PAGE_MASK));
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ciEXPORT_SYMBOL(iounmap);
95