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