162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * pgtable.h: SpitFire page table operations. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) 662306a36Sopenharmony_ci * Copyright 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef _SPARC64_PGTABLE_H 1062306a36Sopenharmony_ci#define _SPARC64_PGTABLE_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* This file contains the functions and defines necessary to modify and use 1362306a36Sopenharmony_ci * the SpitFire page tables. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm-generic/pgtable-nop4d.h> 1762306a36Sopenharmony_ci#include <linux/compiler.h> 1862306a36Sopenharmony_ci#include <linux/const.h> 1962306a36Sopenharmony_ci#include <asm/types.h> 2062306a36Sopenharmony_ci#include <asm/spitfire.h> 2162306a36Sopenharmony_ci#include <asm/asi.h> 2262306a36Sopenharmony_ci#include <asm/adi.h> 2362306a36Sopenharmony_ci#include <asm/page.h> 2462306a36Sopenharmony_ci#include <asm/processor.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB). 2762306a36Sopenharmony_ci * The page copy blockops can use 0x6000000 to 0x8000000. 2862306a36Sopenharmony_ci * The 8K TSB is mapped in the 0x8000000 to 0x8400000 range. 2962306a36Sopenharmony_ci * The 4M TSB is mapped in the 0x8400000 to 0x8800000 range. 3062306a36Sopenharmony_ci * The PROM resides in an area spanning 0xf0000000 to 0x100000000. 3162306a36Sopenharmony_ci * The vmalloc area spans 0x100000000 to 0x200000000. 3262306a36Sopenharmony_ci * Since modules need to be in the lowest 32-bits of the address space, 3362306a36Sopenharmony_ci * we place them right before the OBP area from 0x10000000 to 0xf0000000. 3462306a36Sopenharmony_ci * There is a single static kernel PMD which maps from 0x0 to address 3562306a36Sopenharmony_ci * 0x400000000. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#define TLBTEMP_BASE _AC(0x0000000006000000,UL) 3862306a36Sopenharmony_ci#define TSBMAP_8K_BASE _AC(0x0000000008000000,UL) 3962306a36Sopenharmony_ci#define TSBMAP_4M_BASE _AC(0x0000000008400000,UL) 4062306a36Sopenharmony_ci#define MODULES_VADDR _AC(0x0000000010000000,UL) 4162306a36Sopenharmony_ci#define MODULES_LEN _AC(0x00000000e0000000,UL) 4262306a36Sopenharmony_ci#define MODULES_END _AC(0x00000000f0000000,UL) 4362306a36Sopenharmony_ci#define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL) 4462306a36Sopenharmony_ci#define HI_OBP_ADDRESS _AC(0x0000000100000000,UL) 4562306a36Sopenharmony_ci#define VMALLOC_START _AC(0x0000000100000000,UL) 4662306a36Sopenharmony_ci#define VMEMMAP_BASE VMALLOC_END 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* PMD_SHIFT determines the size of the area a second-level page 4962306a36Sopenharmony_ci * table can map 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) 5262306a36Sopenharmony_ci#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT) 5362306a36Sopenharmony_ci#define PMD_MASK (~(PMD_SIZE-1)) 5462306a36Sopenharmony_ci#define PMD_BITS (PAGE_SHIFT - 3) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* PUD_SHIFT determines the size of the area a third-level page 5762306a36Sopenharmony_ci * table can map 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci#define PUD_SHIFT (PMD_SHIFT + PMD_BITS) 6062306a36Sopenharmony_ci#define PUD_SIZE (_AC(1,UL) << PUD_SHIFT) 6162306a36Sopenharmony_ci#define PUD_MASK (~(PUD_SIZE-1)) 6262306a36Sopenharmony_ci#define PUD_BITS (PAGE_SHIFT - 3) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* PGDIR_SHIFT determines what a fourth-level page table entry can map */ 6562306a36Sopenharmony_ci#define PGDIR_SHIFT (PUD_SHIFT + PUD_BITS) 6662306a36Sopenharmony_ci#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT) 6762306a36Sopenharmony_ci#define PGDIR_MASK (~(PGDIR_SIZE-1)) 6862306a36Sopenharmony_ci#define PGDIR_BITS (PAGE_SHIFT - 3) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#if (MAX_PHYS_ADDRESS_BITS > PGDIR_SHIFT + PGDIR_BITS) 7162306a36Sopenharmony_ci#error MAX_PHYS_ADDRESS_BITS exceeds what kernel page tables can support 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#if (PGDIR_SHIFT + PGDIR_BITS) != 53 7562306a36Sopenharmony_ci#error Page table parameters do not cover virtual address space properly. 7662306a36Sopenharmony_ci#endif 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#if (PMD_SHIFT != HPAGE_SHIFT) 7962306a36Sopenharmony_ci#error PMD_SHIFT must equal HPAGE_SHIFT for transparent huge pages. 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciextern unsigned long VMALLOC_END; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define vmemmap ((struct page *)VMEMMAP_BASE) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#include <linux/sched.h> 8962306a36Sopenharmony_ci#include <asm/tlbflush.h> 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cibool kern_addr_valid(unsigned long addr); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Entries per page directory level. */ 9462306a36Sopenharmony_ci#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3)) 9562306a36Sopenharmony_ci#define PTRS_PER_PMD (1UL << PMD_BITS) 9662306a36Sopenharmony_ci#define PTRS_PER_PUD (1UL << PUD_BITS) 9762306a36Sopenharmony_ci#define PTRS_PER_PGD (1UL << PGDIR_BITS) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define pmd_ERROR(e) \ 10062306a36Sopenharmony_ci pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n", \ 10162306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pmd_val(e), __builtin_return_address(0)) 10262306a36Sopenharmony_ci#define pud_ERROR(e) \ 10362306a36Sopenharmony_ci pr_err("%s:%d: bad pud %p(%016lx) seen at (%pS)\n", \ 10462306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pud_val(e), __builtin_return_address(0)) 10562306a36Sopenharmony_ci#define pgd_ERROR(e) \ 10662306a36Sopenharmony_ci pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n", \ 10762306a36Sopenharmony_ci __FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0)) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#endif /* !(__ASSEMBLY__) */ 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* PTE bits which are the same in SUN4U and SUN4V format. */ 11262306a36Sopenharmony_ci#define _PAGE_VALID _AC(0x8000000000000000,UL) /* Valid TTE */ 11362306a36Sopenharmony_ci#define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/ 11462306a36Sopenharmony_ci#define _PAGE_SPECIAL _AC(0x0200000000000000,UL) /* Special page */ 11562306a36Sopenharmony_ci#define _PAGE_PMD_HUGE _AC(0x0100000000000000,UL) /* Huge page */ 11662306a36Sopenharmony_ci#define _PAGE_PUD_HUGE _PAGE_PMD_HUGE 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* SUN4U pte bits... */ 11962306a36Sopenharmony_ci#define _PAGE_SZ4MB_4U _AC(0x6000000000000000,UL) /* 4MB Page */ 12062306a36Sopenharmony_ci#define _PAGE_SZ512K_4U _AC(0x4000000000000000,UL) /* 512K Page */ 12162306a36Sopenharmony_ci#define _PAGE_SZ64K_4U _AC(0x2000000000000000,UL) /* 64K Page */ 12262306a36Sopenharmony_ci#define _PAGE_SZ8K_4U _AC(0x0000000000000000,UL) /* 8K Page */ 12362306a36Sopenharmony_ci#define _PAGE_NFO_4U _AC(0x1000000000000000,UL) /* No Fault Only */ 12462306a36Sopenharmony_ci#define _PAGE_IE_4U _AC(0x0800000000000000,UL) /* Invert Endianness */ 12562306a36Sopenharmony_ci#define _PAGE_SOFT2_4U _AC(0x07FC000000000000,UL) /* Software bits, set 2 */ 12662306a36Sopenharmony_ci#define _PAGE_SPECIAL_4U _AC(0x0200000000000000,UL) /* Special page */ 12762306a36Sopenharmony_ci#define _PAGE_PMD_HUGE_4U _AC(0x0100000000000000,UL) /* Huge page */ 12862306a36Sopenharmony_ci#define _PAGE_RES1_4U _AC(0x0002000000000000,UL) /* Reserved */ 12962306a36Sopenharmony_ci#define _PAGE_SZ32MB_4U _AC(0x0001000000000000,UL) /* (Panther) 32MB page */ 13062306a36Sopenharmony_ci#define _PAGE_SZ256MB_4U _AC(0x2001000000000000,UL) /* (Panther) 256MB page */ 13162306a36Sopenharmony_ci#define _PAGE_SZALL_4U _AC(0x6001000000000000,UL) /* All pgsz bits */ 13262306a36Sopenharmony_ci#define _PAGE_SN_4U _AC(0x0000800000000000,UL) /* (Cheetah) Snoop */ 13362306a36Sopenharmony_ci#define _PAGE_RES2_4U _AC(0x0000780000000000,UL) /* Reserved */ 13462306a36Sopenharmony_ci#define _PAGE_PADDR_4U _AC(0x000007FFFFFFE000,UL) /* (Cheetah) pa[42:13] */ 13562306a36Sopenharmony_ci#define _PAGE_SOFT_4U _AC(0x0000000000001F80,UL) /* Software bits: */ 13662306a36Sopenharmony_ci#define _PAGE_EXEC_4U _AC(0x0000000000001000,UL) /* Executable SW bit */ 13762306a36Sopenharmony_ci#define _PAGE_MODIFIED_4U _AC(0x0000000000000800,UL) /* Modified (dirty) */ 13862306a36Sopenharmony_ci#define _PAGE_ACCESSED_4U _AC(0x0000000000000400,UL) /* Accessed (ref'd) */ 13962306a36Sopenharmony_ci#define _PAGE_READ_4U _AC(0x0000000000000200,UL) /* Readable SW Bit */ 14062306a36Sopenharmony_ci#define _PAGE_WRITE_4U _AC(0x0000000000000100,UL) /* Writable SW Bit */ 14162306a36Sopenharmony_ci#define _PAGE_PRESENT_4U _AC(0x0000000000000080,UL) /* Present */ 14262306a36Sopenharmony_ci#define _PAGE_L_4U _AC(0x0000000000000040,UL) /* Locked TTE */ 14362306a36Sopenharmony_ci#define _PAGE_CP_4U _AC(0x0000000000000020,UL) /* Cacheable in P-Cache */ 14462306a36Sopenharmony_ci#define _PAGE_CV_4U _AC(0x0000000000000010,UL) /* Cacheable in V-Cache */ 14562306a36Sopenharmony_ci#define _PAGE_E_4U _AC(0x0000000000000008,UL) /* side-Effect */ 14662306a36Sopenharmony_ci#define _PAGE_P_4U _AC(0x0000000000000004,UL) /* Privileged Page */ 14762306a36Sopenharmony_ci#define _PAGE_W_4U _AC(0x0000000000000002,UL) /* Writable */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* SUN4V pte bits... */ 15062306a36Sopenharmony_ci#define _PAGE_NFO_4V _AC(0x4000000000000000,UL) /* No Fault Only */ 15162306a36Sopenharmony_ci#define _PAGE_SOFT2_4V _AC(0x3F00000000000000,UL) /* Software bits, set 2 */ 15262306a36Sopenharmony_ci#define _PAGE_MODIFIED_4V _AC(0x2000000000000000,UL) /* Modified (dirty) */ 15362306a36Sopenharmony_ci#define _PAGE_ACCESSED_4V _AC(0x1000000000000000,UL) /* Accessed (ref'd) */ 15462306a36Sopenharmony_ci#define _PAGE_READ_4V _AC(0x0800000000000000,UL) /* Readable SW Bit */ 15562306a36Sopenharmony_ci#define _PAGE_WRITE_4V _AC(0x0400000000000000,UL) /* Writable SW Bit */ 15662306a36Sopenharmony_ci#define _PAGE_SPECIAL_4V _AC(0x0200000000000000,UL) /* Special page */ 15762306a36Sopenharmony_ci#define _PAGE_PMD_HUGE_4V _AC(0x0100000000000000,UL) /* Huge page */ 15862306a36Sopenharmony_ci#define _PAGE_PADDR_4V _AC(0x00FFFFFFFFFFE000,UL) /* paddr[55:13] */ 15962306a36Sopenharmony_ci#define _PAGE_IE_4V _AC(0x0000000000001000,UL) /* Invert Endianness */ 16062306a36Sopenharmony_ci#define _PAGE_E_4V _AC(0x0000000000000800,UL) /* side-Effect */ 16162306a36Sopenharmony_ci#define _PAGE_CP_4V _AC(0x0000000000000400,UL) /* Cacheable in P-Cache */ 16262306a36Sopenharmony_ci#define _PAGE_CV_4V _AC(0x0000000000000200,UL) /* Cacheable in V-Cache */ 16362306a36Sopenharmony_ci/* Bit 9 is used to enable MCD corruption detection instead on M7 */ 16462306a36Sopenharmony_ci#define _PAGE_MCD_4V _AC(0x0000000000000200,UL) /* Memory Corruption */ 16562306a36Sopenharmony_ci#define _PAGE_P_4V _AC(0x0000000000000100,UL) /* Privileged Page */ 16662306a36Sopenharmony_ci#define _PAGE_EXEC_4V _AC(0x0000000000000080,UL) /* Executable Page */ 16762306a36Sopenharmony_ci#define _PAGE_W_4V _AC(0x0000000000000040,UL) /* Writable */ 16862306a36Sopenharmony_ci#define _PAGE_SOFT_4V _AC(0x0000000000000030,UL) /* Software bits */ 16962306a36Sopenharmony_ci#define _PAGE_PRESENT_4V _AC(0x0000000000000010,UL) /* Present */ 17062306a36Sopenharmony_ci#define _PAGE_RESV_4V _AC(0x0000000000000008,UL) /* Reserved */ 17162306a36Sopenharmony_ci#define _PAGE_SZ16GB_4V _AC(0x0000000000000007,UL) /* 16GB Page */ 17262306a36Sopenharmony_ci#define _PAGE_SZ2GB_4V _AC(0x0000000000000006,UL) /* 2GB Page */ 17362306a36Sopenharmony_ci#define _PAGE_SZ256MB_4V _AC(0x0000000000000005,UL) /* 256MB Page */ 17462306a36Sopenharmony_ci#define _PAGE_SZ32MB_4V _AC(0x0000000000000004,UL) /* 32MB Page */ 17562306a36Sopenharmony_ci#define _PAGE_SZ4MB_4V _AC(0x0000000000000003,UL) /* 4MB Page */ 17662306a36Sopenharmony_ci#define _PAGE_SZ512K_4V _AC(0x0000000000000002,UL) /* 512K Page */ 17762306a36Sopenharmony_ci#define _PAGE_SZ64K_4V _AC(0x0000000000000001,UL) /* 64K Page */ 17862306a36Sopenharmony_ci#define _PAGE_SZ8K_4V _AC(0x0000000000000000,UL) /* 8K Page */ 17962306a36Sopenharmony_ci#define _PAGE_SZALL_4V _AC(0x0000000000000007,UL) /* All pgsz bits */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define _PAGE_SZBITS_4U _PAGE_SZ8K_4U 18262306a36Sopenharmony_ci#define _PAGE_SZBITS_4V _PAGE_SZ8K_4V 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#if REAL_HPAGE_SHIFT != 22 18562306a36Sopenharmony_ci#error REAL_HPAGE_SHIFT and _PAGE_SZHUGE_foo must match up 18662306a36Sopenharmony_ci#endif 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#define _PAGE_SZHUGE_4U _PAGE_SZ4MB_4U 18962306a36Sopenharmony_ci#define _PAGE_SZHUGE_4V _PAGE_SZ4MB_4V 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* We borrow bit 20 to store the exclusive marker in swap PTEs. */ 19262306a36Sopenharmony_ci#define _PAGE_SWP_EXCLUSIVE _AC(0x0000000000100000, UL) 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cipte_t mk_pte_io(unsigned long, pgprot_t, int, unsigned long); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciunsigned long pte_sz_bits(unsigned long size); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciextern pgprot_t PAGE_KERNEL; 20162306a36Sopenharmony_ciextern pgprot_t PAGE_KERNEL_LOCKED; 20262306a36Sopenharmony_ciextern pgprot_t PAGE_COPY; 20362306a36Sopenharmony_ciextern pgprot_t PAGE_SHARED; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* XXX This ugliness is for the atyfb driver's sparc mmap() support. XXX */ 20662306a36Sopenharmony_ciextern unsigned long _PAGE_IE; 20762306a36Sopenharmony_ciextern unsigned long _PAGE_E; 20862306a36Sopenharmony_ciextern unsigned long _PAGE_CACHE; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciextern unsigned long pg_iobits; 21162306a36Sopenharmony_ciextern unsigned long _PAGE_ALL_SZ_BITS; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciextern struct page *mem_map_zero; 21462306a36Sopenharmony_ci#define ZERO_PAGE(vaddr) (mem_map_zero) 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* PFNs are real physical page numbers. However, mem_map only begins to record 21762306a36Sopenharmony_ci * per-page information starting at pfn_base. This is to handle systems where 21862306a36Sopenharmony_ci * the first physical page in the machine is at some huge physical address, 21962306a36Sopenharmony_ci * such as 4GB. This is common on a partitioned E10000, for example. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci unsigned long paddr = pfn << PAGE_SHIFT; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci BUILD_BUG_ON(_PAGE_SZBITS_4U != 0UL || _PAGE_SZBITS_4V != 0UL); 22662306a36Sopenharmony_ci return __pte(paddr | pgprot_val(prot)); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 23162306a36Sopenharmony_cistatic inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci pte_t pte = pfn_pte(page_nr, pgprot); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return __pmd(pte_val(pte)); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) 23862306a36Sopenharmony_ci#endif 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* This one can be done with two shifts. */ 24162306a36Sopenharmony_cistatic inline unsigned long pte_pfn(pte_t pte) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci unsigned long ret; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci __asm__ __volatile__( 24662306a36Sopenharmony_ci "\n661: sllx %1, %2, %0\n" 24762306a36Sopenharmony_ci " srlx %0, %3, %0\n" 24862306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 24962306a36Sopenharmony_ci " .word 661b\n" 25062306a36Sopenharmony_ci " sllx %1, %4, %0\n" 25162306a36Sopenharmony_ci " srlx %0, %5, %0\n" 25262306a36Sopenharmony_ci " .previous\n" 25362306a36Sopenharmony_ci : "=r" (ret) 25462306a36Sopenharmony_ci : "r" (pte_val(pte)), 25562306a36Sopenharmony_ci "i" (21), "i" (21 + PAGE_SHIFT), 25662306a36Sopenharmony_ci "i" (8), "i" (8 + PAGE_SHIFT)); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return ret; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci#define pte_page(x) pfn_to_page(pte_pfn(x)) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic inline pte_t pte_modify(pte_t pte, pgprot_t prot) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci unsigned long mask, tmp; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* SUN4U: 0x630107ffffffec38 (negated == 0x9cfef800000013c7) 26762306a36Sopenharmony_ci * SUN4V: 0x33ffffffffffee07 (negated == 0xcc000000000011f8) 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Even if we use negation tricks the result is still a 6 27062306a36Sopenharmony_ci * instruction sequence, so don't try to play fancy and just 27162306a36Sopenharmony_ci * do the most straightforward implementation. 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * Note: We encode this into 3 sun4v 2-insn patch sequences. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci BUILD_BUG_ON(_PAGE_SZBITS_4U != 0UL || _PAGE_SZBITS_4V != 0UL); 27762306a36Sopenharmony_ci __asm__ __volatile__( 27862306a36Sopenharmony_ci "\n661: sethi %%uhi(%2), %1\n" 27962306a36Sopenharmony_ci " sethi %%hi(%2), %0\n" 28062306a36Sopenharmony_ci "\n662: or %1, %%ulo(%2), %1\n" 28162306a36Sopenharmony_ci " or %0, %%lo(%2), %0\n" 28262306a36Sopenharmony_ci "\n663: sllx %1, 32, %1\n" 28362306a36Sopenharmony_ci " or %0, %1, %0\n" 28462306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 28562306a36Sopenharmony_ci " .word 661b\n" 28662306a36Sopenharmony_ci " sethi %%uhi(%3), %1\n" 28762306a36Sopenharmony_ci " sethi %%hi(%3), %0\n" 28862306a36Sopenharmony_ci " .word 662b\n" 28962306a36Sopenharmony_ci " or %1, %%ulo(%3), %1\n" 29062306a36Sopenharmony_ci " or %0, %%lo(%3), %0\n" 29162306a36Sopenharmony_ci " .word 663b\n" 29262306a36Sopenharmony_ci " sllx %1, 32, %1\n" 29362306a36Sopenharmony_ci " or %0, %1, %0\n" 29462306a36Sopenharmony_ci " .previous\n" 29562306a36Sopenharmony_ci " .section .sun_m7_2insn_patch, \"ax\"\n" 29662306a36Sopenharmony_ci " .word 661b\n" 29762306a36Sopenharmony_ci " sethi %%uhi(%4), %1\n" 29862306a36Sopenharmony_ci " sethi %%hi(%4), %0\n" 29962306a36Sopenharmony_ci " .word 662b\n" 30062306a36Sopenharmony_ci " or %1, %%ulo(%4), %1\n" 30162306a36Sopenharmony_ci " or %0, %%lo(%4), %0\n" 30262306a36Sopenharmony_ci " .word 663b\n" 30362306a36Sopenharmony_ci " sllx %1, 32, %1\n" 30462306a36Sopenharmony_ci " or %0, %1, %0\n" 30562306a36Sopenharmony_ci " .previous\n" 30662306a36Sopenharmony_ci : "=r" (mask), "=r" (tmp) 30762306a36Sopenharmony_ci : "i" (_PAGE_PADDR_4U | _PAGE_MODIFIED_4U | _PAGE_ACCESSED_4U | 30862306a36Sopenharmony_ci _PAGE_CP_4U | _PAGE_CV_4U | _PAGE_E_4U | 30962306a36Sopenharmony_ci _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4U), 31062306a36Sopenharmony_ci "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V | 31162306a36Sopenharmony_ci _PAGE_CP_4V | _PAGE_CV_4V | _PAGE_E_4V | 31262306a36Sopenharmony_ci _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V), 31362306a36Sopenharmony_ci "i" (_PAGE_PADDR_4V | _PAGE_MODIFIED_4V | _PAGE_ACCESSED_4V | 31462306a36Sopenharmony_ci _PAGE_CP_4V | _PAGE_E_4V | 31562306a36Sopenharmony_ci _PAGE_SPECIAL | _PAGE_PMD_HUGE | _PAGE_SZALL_4V)); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return __pte((pte_val(pte) & mask) | (pgprot_val(prot) & ~mask)); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 32162306a36Sopenharmony_cistatic inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci pte = pte_modify(pte, newprot); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return __pmd(pte_val(pte)); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic inline pgprot_t pgprot_noncached(pgprot_t prot) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci unsigned long val = pgprot_val(prot); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci __asm__ __volatile__( 33662306a36Sopenharmony_ci "\n661: andn %0, %2, %0\n" 33762306a36Sopenharmony_ci " or %0, %3, %0\n" 33862306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 33962306a36Sopenharmony_ci " .word 661b\n" 34062306a36Sopenharmony_ci " andn %0, %4, %0\n" 34162306a36Sopenharmony_ci " or %0, %5, %0\n" 34262306a36Sopenharmony_ci " .previous\n" 34362306a36Sopenharmony_ci " .section .sun_m7_2insn_patch, \"ax\"\n" 34462306a36Sopenharmony_ci " .word 661b\n" 34562306a36Sopenharmony_ci " andn %0, %6, %0\n" 34662306a36Sopenharmony_ci " or %0, %5, %0\n" 34762306a36Sopenharmony_ci " .previous\n" 34862306a36Sopenharmony_ci : "=r" (val) 34962306a36Sopenharmony_ci : "0" (val), "i" (_PAGE_CP_4U | _PAGE_CV_4U), "i" (_PAGE_E_4U), 35062306a36Sopenharmony_ci "i" (_PAGE_CP_4V | _PAGE_CV_4V), "i" (_PAGE_E_4V), 35162306a36Sopenharmony_ci "i" (_PAGE_CP_4V)); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return __pgprot(val); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci/* Various pieces of code check for platform support by ifdef testing 35662306a36Sopenharmony_ci * on "pgprot_noncached". That's broken and should be fixed, but for 35762306a36Sopenharmony_ci * now... 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci#define pgprot_noncached pgprot_noncached 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic inline unsigned long pte_dirty(pte_t pte) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned long mask; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci __asm__ __volatile__( 36662306a36Sopenharmony_ci "\n661: mov %1, %0\n" 36762306a36Sopenharmony_ci " nop\n" 36862306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 36962306a36Sopenharmony_ci " .word 661b\n" 37062306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 37162306a36Sopenharmony_ci " sllx %0, 32, %0\n" 37262306a36Sopenharmony_ci " .previous\n" 37362306a36Sopenharmony_ci : "=r" (mask) 37462306a36Sopenharmony_ci : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return (pte_val(pte) & mask); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic inline unsigned long pte_write(pte_t pte) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci unsigned long mask; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci __asm__ __volatile__( 38462306a36Sopenharmony_ci "\n661: mov %1, %0\n" 38562306a36Sopenharmony_ci " nop\n" 38662306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 38762306a36Sopenharmony_ci " .word 661b\n" 38862306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 38962306a36Sopenharmony_ci " sllx %0, 32, %0\n" 39062306a36Sopenharmony_ci " .previous\n" 39162306a36Sopenharmony_ci : "=r" (mask) 39262306a36Sopenharmony_ci : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return (pte_val(pte) & mask); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE) 39862306a36Sopenharmony_cipte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags); 39962306a36Sopenharmony_ci#define arch_make_huge_pte arch_make_huge_pte 40062306a36Sopenharmony_cistatic inline unsigned long __pte_default_huge_mask(void) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci unsigned long mask; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci __asm__ __volatile__( 40562306a36Sopenharmony_ci "\n661: sethi %%uhi(%1), %0\n" 40662306a36Sopenharmony_ci " sllx %0, 32, %0\n" 40762306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 40862306a36Sopenharmony_ci " .word 661b\n" 40962306a36Sopenharmony_ci " mov %2, %0\n" 41062306a36Sopenharmony_ci " nop\n" 41162306a36Sopenharmony_ci " .previous\n" 41262306a36Sopenharmony_ci : "=r" (mask) 41362306a36Sopenharmony_ci : "i" (_PAGE_SZHUGE_4U), "i" (_PAGE_SZHUGE_4V)); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return mask; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic inline pte_t pte_mkhuge(pte_t pte) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci return __pte(pte_val(pte) | __pte_default_huge_mask()); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic inline bool is_default_hugetlb_pte(pte_t pte) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci unsigned long mask = __pte_default_huge_mask(); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return (pte_val(pte) & mask) == mask; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic inline bool is_hugetlb_pmd(pmd_t pmd) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci return !!(pmd_val(pmd) & _PAGE_PMD_HUGE); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic inline bool is_hugetlb_pud(pud_t pud) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci return !!(pud_val(pud) & _PAGE_PUD_HUGE); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 44162306a36Sopenharmony_cistatic inline pmd_t pmd_mkhuge(pmd_t pmd) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci pte = pte_mkhuge(pte); 44662306a36Sopenharmony_ci pte_val(pte) |= _PAGE_PMD_HUGE; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return __pmd(pte_val(pte)); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci#endif 45162306a36Sopenharmony_ci#else 45262306a36Sopenharmony_cistatic inline bool is_hugetlb_pte(pte_t pte) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci return false; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci#endif 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic inline pte_t __pte_mkhwwrite(pte_t pte) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci unsigned long val = pte_val(pte); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Note: we only want to set the HW writable bit if the SW writable bit 46462306a36Sopenharmony_ci * and the SW dirty bit are set. 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci __asm__ __volatile__( 46762306a36Sopenharmony_ci "\n661: or %0, %2, %0\n" 46862306a36Sopenharmony_ci " .section .sun4v_1insn_patch, \"ax\"\n" 46962306a36Sopenharmony_ci " .word 661b\n" 47062306a36Sopenharmony_ci " or %0, %3, %0\n" 47162306a36Sopenharmony_ci " .previous\n" 47262306a36Sopenharmony_ci : "=r" (val) 47362306a36Sopenharmony_ci : "0" (val), "i" (_PAGE_W_4U), "i" (_PAGE_W_4V)); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return __pte(val); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic inline pte_t pte_mkdirty(pte_t pte) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci unsigned long val = pte_val(pte), mask; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci __asm__ __volatile__( 48362306a36Sopenharmony_ci "\n661: mov %1, %0\n" 48462306a36Sopenharmony_ci " nop\n" 48562306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 48662306a36Sopenharmony_ci " .word 661b\n" 48762306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 48862306a36Sopenharmony_ci " sllx %0, 32, %0\n" 48962306a36Sopenharmony_ci " .previous\n" 49062306a36Sopenharmony_ci : "=r" (mask) 49162306a36Sopenharmony_ci : "i" (_PAGE_MODIFIED_4U), "i" (_PAGE_MODIFIED_4V)); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci pte = __pte(val | mask); 49462306a36Sopenharmony_ci return pte_write(pte) ? __pte_mkhwwrite(pte) : pte; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic inline pte_t pte_mkclean(pte_t pte) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci unsigned long val = pte_val(pte), tmp; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci __asm__ __volatile__( 50262306a36Sopenharmony_ci "\n661: andn %0, %3, %0\n" 50362306a36Sopenharmony_ci " nop\n" 50462306a36Sopenharmony_ci "\n662: nop\n" 50562306a36Sopenharmony_ci " nop\n" 50662306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 50762306a36Sopenharmony_ci " .word 661b\n" 50862306a36Sopenharmony_ci " sethi %%uhi(%4), %1\n" 50962306a36Sopenharmony_ci " sllx %1, 32, %1\n" 51062306a36Sopenharmony_ci " .word 662b\n" 51162306a36Sopenharmony_ci " or %1, %%lo(%4), %1\n" 51262306a36Sopenharmony_ci " andn %0, %1, %0\n" 51362306a36Sopenharmony_ci " .previous\n" 51462306a36Sopenharmony_ci : "=r" (val), "=r" (tmp) 51562306a36Sopenharmony_ci : "0" (val), "i" (_PAGE_MODIFIED_4U | _PAGE_W_4U), 51662306a36Sopenharmony_ci "i" (_PAGE_MODIFIED_4V | _PAGE_W_4V)); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return __pte(val); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic inline pte_t pte_mkwrite_novma(pte_t pte) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci unsigned long val = pte_val(pte), mask; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci __asm__ __volatile__( 52662306a36Sopenharmony_ci "\n661: mov %1, %0\n" 52762306a36Sopenharmony_ci " nop\n" 52862306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 52962306a36Sopenharmony_ci " .word 661b\n" 53062306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 53162306a36Sopenharmony_ci " sllx %0, 32, %0\n" 53262306a36Sopenharmony_ci " .previous\n" 53362306a36Sopenharmony_ci : "=r" (mask) 53462306a36Sopenharmony_ci : "i" (_PAGE_WRITE_4U), "i" (_PAGE_WRITE_4V)); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci pte = __pte(val | mask); 53762306a36Sopenharmony_ci return pte_dirty(pte) ? __pte_mkhwwrite(pte) : pte; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic inline pte_t pte_wrprotect(pte_t pte) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci unsigned long val = pte_val(pte), tmp; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci __asm__ __volatile__( 54562306a36Sopenharmony_ci "\n661: andn %0, %3, %0\n" 54662306a36Sopenharmony_ci " nop\n" 54762306a36Sopenharmony_ci "\n662: nop\n" 54862306a36Sopenharmony_ci " nop\n" 54962306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 55062306a36Sopenharmony_ci " .word 661b\n" 55162306a36Sopenharmony_ci " sethi %%uhi(%4), %1\n" 55262306a36Sopenharmony_ci " sllx %1, 32, %1\n" 55362306a36Sopenharmony_ci " .word 662b\n" 55462306a36Sopenharmony_ci " or %1, %%lo(%4), %1\n" 55562306a36Sopenharmony_ci " andn %0, %1, %0\n" 55662306a36Sopenharmony_ci " .previous\n" 55762306a36Sopenharmony_ci : "=r" (val), "=r" (tmp) 55862306a36Sopenharmony_ci : "0" (val), "i" (_PAGE_WRITE_4U | _PAGE_W_4U), 55962306a36Sopenharmony_ci "i" (_PAGE_WRITE_4V | _PAGE_W_4V)); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return __pte(val); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic inline pte_t pte_mkold(pte_t pte) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci unsigned long mask; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci __asm__ __volatile__( 56962306a36Sopenharmony_ci "\n661: mov %1, %0\n" 57062306a36Sopenharmony_ci " nop\n" 57162306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 57262306a36Sopenharmony_ci " .word 661b\n" 57362306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 57462306a36Sopenharmony_ci " sllx %0, 32, %0\n" 57562306a36Sopenharmony_ci " .previous\n" 57662306a36Sopenharmony_ci : "=r" (mask) 57762306a36Sopenharmony_ci : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci mask |= _PAGE_R; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return __pte(pte_val(pte) & ~mask); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic inline pte_t pte_mkyoung(pte_t pte) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci unsigned long mask; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci __asm__ __volatile__( 58962306a36Sopenharmony_ci "\n661: mov %1, %0\n" 59062306a36Sopenharmony_ci " nop\n" 59162306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 59262306a36Sopenharmony_ci " .word 661b\n" 59362306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 59462306a36Sopenharmony_ci " sllx %0, 32, %0\n" 59562306a36Sopenharmony_ci " .previous\n" 59662306a36Sopenharmony_ci : "=r" (mask) 59762306a36Sopenharmony_ci : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci mask |= _PAGE_R; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return __pte(pte_val(pte) | mask); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic inline pte_t pte_mkspecial(pte_t pte) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci pte_val(pte) |= _PAGE_SPECIAL; 60762306a36Sopenharmony_ci return pte; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic inline pte_t pte_mkmcd(pte_t pte) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci pte_val(pte) |= _PAGE_MCD_4V; 61362306a36Sopenharmony_ci return pte; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_cistatic inline pte_t pte_mknotmcd(pte_t pte) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci pte_val(pte) &= ~_PAGE_MCD_4V; 61962306a36Sopenharmony_ci return pte; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic inline unsigned long pte_young(pte_t pte) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci unsigned long mask; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci __asm__ __volatile__( 62762306a36Sopenharmony_ci "\n661: mov %1, %0\n" 62862306a36Sopenharmony_ci " nop\n" 62962306a36Sopenharmony_ci " .section .sun4v_2insn_patch, \"ax\"\n" 63062306a36Sopenharmony_ci " .word 661b\n" 63162306a36Sopenharmony_ci " sethi %%uhi(%2), %0\n" 63262306a36Sopenharmony_ci " sllx %0, 32, %0\n" 63362306a36Sopenharmony_ci " .previous\n" 63462306a36Sopenharmony_ci : "=r" (mask) 63562306a36Sopenharmony_ci : "i" (_PAGE_ACCESSED_4U), "i" (_PAGE_ACCESSED_4V)); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return (pte_val(pte) & mask); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic inline unsigned long pte_exec(pte_t pte) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci unsigned long mask; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci __asm__ __volatile__( 64562306a36Sopenharmony_ci "\n661: sethi %%hi(%1), %0\n" 64662306a36Sopenharmony_ci " .section .sun4v_1insn_patch, \"ax\"\n" 64762306a36Sopenharmony_ci " .word 661b\n" 64862306a36Sopenharmony_ci " mov %2, %0\n" 64962306a36Sopenharmony_ci " .previous\n" 65062306a36Sopenharmony_ci : "=r" (mask) 65162306a36Sopenharmony_ci : "i" (_PAGE_EXEC_4U), "i" (_PAGE_EXEC_4V)); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return (pte_val(pte) & mask); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic inline unsigned long pte_present(pte_t pte) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci unsigned long val = pte_val(pte); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci __asm__ __volatile__( 66162306a36Sopenharmony_ci "\n661: and %0, %2, %0\n" 66262306a36Sopenharmony_ci " .section .sun4v_1insn_patch, \"ax\"\n" 66362306a36Sopenharmony_ci " .word 661b\n" 66462306a36Sopenharmony_ci " and %0, %3, %0\n" 66562306a36Sopenharmony_ci " .previous\n" 66662306a36Sopenharmony_ci : "=r" (val) 66762306a36Sopenharmony_ci : "0" (val), "i" (_PAGE_PRESENT_4U), "i" (_PAGE_PRESENT_4V)); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return val; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci#define pte_accessible pte_accessible 67362306a36Sopenharmony_cistatic inline unsigned long pte_accessible(struct mm_struct *mm, pte_t a) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci return pte_val(a) & _PAGE_VALID; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic inline unsigned long pte_special(pte_t pte) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci return pte_val(pte) & _PAGE_SPECIAL; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci#define pmd_leaf pmd_large 68462306a36Sopenharmony_cistatic inline unsigned long pmd_large(pmd_t pmd) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci return pte_val(pte) & _PAGE_PMD_HUGE; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic inline unsigned long pmd_pfn(pmd_t pmd) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return pte_pfn(pte); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci#define pmd_write pmd_write 69962306a36Sopenharmony_cistatic inline unsigned long pmd_write(pmd_t pmd) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return pte_write(pte); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci#define pud_write(pud) pte_write(__pte(pud_val(pud))) 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 70962306a36Sopenharmony_cistatic inline unsigned long pmd_dirty(pmd_t pmd) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci return pte_dirty(pte); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci#define pmd_young pmd_young 71762306a36Sopenharmony_cistatic inline unsigned long pmd_young(pmd_t pmd) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return pte_young(pte); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic inline unsigned long pmd_trans_huge(pmd_t pmd) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return pte_val(pte) & _PAGE_PMD_HUGE; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic inline pmd_t pmd_mkold(pmd_t pmd) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci pte = pte_mkold(pte); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return __pmd(pte_val(pte)); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic inline pmd_t pmd_wrprotect(pmd_t pmd) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci pte = pte_wrprotect(pte); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci return __pmd(pte_val(pte)); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic inline pmd_t pmd_mkdirty(pmd_t pmd) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci pte = pte_mkdirty(pte); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return __pmd(pte_val(pte)); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_cistatic inline pmd_t pmd_mkclean(pmd_t pmd) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci pte = pte_mkclean(pte); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return __pmd(pte_val(pte)); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic inline pmd_t pmd_mkyoung(pmd_t pmd) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci pte = pte_mkyoung(pte); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return __pmd(pte_val(pte)); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic inline pmd_t pmd_mkwrite_novma(pmd_t pmd) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci pte = pte_mkwrite_novma(pte); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return __pmd(pte_val(pte)); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic inline pgprot_t pmd_pgprot(pmd_t entry) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci unsigned long val = pmd_val(entry); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return __pgprot(val); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci#endif 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic inline int pmd_present(pmd_t pmd) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci return pmd_val(pmd) != 0UL; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci#define pmd_none(pmd) (!pmd_val(pmd)) 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci/* pmd_bad() is only called on non-trans-huge PMDs. Our encoding is 80162306a36Sopenharmony_ci * very simple, it's just the physical address. PTE tables are of 80262306a36Sopenharmony_ci * size PAGE_SIZE so make sure the sub-PAGE_SIZE bits are clear and 80362306a36Sopenharmony_ci * the top bits outside of the range of any physical address size we 80462306a36Sopenharmony_ci * support are clear as well. We also validate the physical itself. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK) 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci#define pud_none(pud) (!pud_val(pud)) 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci#define pud_bad(pud) (pud_val(pud) & ~PAGE_MASK) 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci#define p4d_none(p4d) (!p4d_val(p4d)) 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci#define p4d_bad(p4d) (p4d_val(p4d) & ~PAGE_MASK) 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 81762306a36Sopenharmony_civoid set_pmd_at(struct mm_struct *mm, unsigned long addr, 81862306a36Sopenharmony_ci pmd_t *pmdp, pmd_t pmd); 81962306a36Sopenharmony_ci#else 82062306a36Sopenharmony_cistatic inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, 82162306a36Sopenharmony_ci pmd_t *pmdp, pmd_t pmd) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci *pmdp = pmd; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci#endif 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic inline void pmd_set(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci unsigned long val = __pa((unsigned long) (ptep)); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci pmd_val(*pmdp) = val; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci#define pud_set(pudp, pmdp) \ 83562306a36Sopenharmony_ci (pud_val(*(pudp)) = (__pa((unsigned long) (pmdp)))) 83662306a36Sopenharmony_cistatic inline unsigned long pmd_page_vaddr(pmd_t pmd) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci pte_t pte = __pte(pmd_val(pmd)); 83962306a36Sopenharmony_ci unsigned long pfn; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci pfn = pte_pfn(pte); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return ((unsigned long) __va(pfn << PAGE_SHIFT)); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic inline pmd_t *pud_pgtable(pud_t pud) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci pte_t pte = __pte(pud_val(pud)); 84962306a36Sopenharmony_ci unsigned long pfn; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci pfn = pte_pfn(pte); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return ((pmd_t *) __va(pfn << PAGE_SHIFT)); 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci#define pmd_page(pmd) virt_to_page((void *)pmd_page_vaddr(pmd)) 85762306a36Sopenharmony_ci#define pud_page(pud) virt_to_page((void *)pud_pgtable(pud)) 85862306a36Sopenharmony_ci#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) 85962306a36Sopenharmony_ci#define pud_present(pud) (pud_val(pud) != 0U) 86062306a36Sopenharmony_ci#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) 86162306a36Sopenharmony_ci#define p4d_pgtable(p4d) \ 86262306a36Sopenharmony_ci ((pud_t *) __va(p4d_val(p4d))) 86362306a36Sopenharmony_ci#define p4d_present(p4d) (p4d_val(p4d) != 0U) 86462306a36Sopenharmony_ci#define p4d_clear(p4dp) (p4d_val(*(p4dp)) = 0UL) 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci/* only used by the stubbed out hugetlb gup code, should never be called */ 86762306a36Sopenharmony_ci#define p4d_page(p4d) NULL 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci#define pud_leaf pud_large 87062306a36Sopenharmony_cistatic inline unsigned long pud_large(pud_t pud) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci pte_t pte = __pte(pud_val(pud)); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return pte_val(pte) & _PAGE_PMD_HUGE; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic inline unsigned long pud_pfn(pud_t pud) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci pte_t pte = __pte(pud_val(pud)); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return pte_pfn(pte); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci/* Same in both SUN4V and SUN4U. */ 88562306a36Sopenharmony_ci#define pte_none(pte) (!pte_val(pte)) 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci#define p4d_set(p4dp, pudp) \ 88862306a36Sopenharmony_ci (p4d_val(*(p4dp)) = (__pa((unsigned long) (pudp)))) 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* We cannot include <linux/mm_types.h> at this point yet: */ 89162306a36Sopenharmony_ciextern struct mm_struct init_mm; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* Actual page table PTE updates. */ 89462306a36Sopenharmony_civoid tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, 89562306a36Sopenharmony_ci pte_t *ptep, pte_t orig, int fullmm, 89662306a36Sopenharmony_ci unsigned int hugepage_shift); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic void maybe_tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, 89962306a36Sopenharmony_ci pte_t *ptep, pte_t orig, int fullmm, 90062306a36Sopenharmony_ci unsigned int hugepage_shift) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci /* It is more efficient to let flush_tlb_kernel_range() 90362306a36Sopenharmony_ci * handle init_mm tlb flushes. 90462306a36Sopenharmony_ci * 90562306a36Sopenharmony_ci * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U 90662306a36Sopenharmony_ci * and SUN4V pte layout, so this inline test is fine. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci if (likely(mm != &init_mm) && pte_accessible(mm, orig)) 90962306a36Sopenharmony_ci tlb_batch_add(mm, vaddr, ptep, orig, fullmm, hugepage_shift); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR 91362306a36Sopenharmony_cistatic inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, 91462306a36Sopenharmony_ci unsigned long addr, 91562306a36Sopenharmony_ci pmd_t *pmdp) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci pmd_t pmd = *pmdp; 91862306a36Sopenharmony_ci set_pmd_at(mm, addr, pmdp, __pmd(0UL)); 91962306a36Sopenharmony_ci return pmd; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, 92362306a36Sopenharmony_ci pte_t *ptep, pte_t pte, int fullmm) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci pte_t orig = *ptep; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci *ptep = pte; 92862306a36Sopenharmony_ci maybe_tlb_batch_add(mm, addr, ptep, orig, fullmm, PAGE_SHIFT); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic inline void set_ptes(struct mm_struct *mm, unsigned long addr, 93262306a36Sopenharmony_ci pte_t *ptep, pte_t pte, unsigned int nr) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci arch_enter_lazy_mmu_mode(); 93562306a36Sopenharmony_ci for (;;) { 93662306a36Sopenharmony_ci __set_pte_at(mm, addr, ptep, pte, 0); 93762306a36Sopenharmony_ci if (--nr == 0) 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci ptep++; 94062306a36Sopenharmony_ci pte_val(pte) += PAGE_SIZE; 94162306a36Sopenharmony_ci addr += PAGE_SIZE; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci arch_leave_lazy_mmu_mode(); 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci#define set_ptes set_ptes 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci#define pte_clear(mm,addr,ptep) \ 94862306a36Sopenharmony_ci set_pte_at((mm), (addr), (ptep), __pte(0UL)) 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci#define __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL 95162306a36Sopenharmony_ci#define pte_clear_not_present_full(mm,addr,ptep,fullmm) \ 95262306a36Sopenharmony_ci __set_pte_at((mm), (addr), (ptep), __pte(0UL), (fullmm)) 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci#ifdef DCACHE_ALIASING_POSSIBLE 95562306a36Sopenharmony_ci#define __HAVE_ARCH_MOVE_PTE 95662306a36Sopenharmony_ci#define move_pte(pte, prot, old_addr, new_addr) \ 95762306a36Sopenharmony_ci({ \ 95862306a36Sopenharmony_ci pte_t newpte = (pte); \ 95962306a36Sopenharmony_ci if (tlb_type != hypervisor && pte_present(pte)) { \ 96062306a36Sopenharmony_ci unsigned long this_pfn = pte_pfn(pte); \ 96162306a36Sopenharmony_ci \ 96262306a36Sopenharmony_ci if (pfn_valid(this_pfn) && \ 96362306a36Sopenharmony_ci (((old_addr) ^ (new_addr)) & (1 << 13))) \ 96462306a36Sopenharmony_ci flush_dcache_folio_all(current->mm, \ 96562306a36Sopenharmony_ci page_folio(pfn_to_page(this_pfn))); \ 96662306a36Sopenharmony_ci } \ 96762306a36Sopenharmony_ci newpte; \ 96862306a36Sopenharmony_ci}) 96962306a36Sopenharmony_ci#endif 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ciextern pgd_t swapper_pg_dir[PTRS_PER_PGD]; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_civoid paging_init(void); 97462306a36Sopenharmony_ciunsigned long find_ecache_flush_span(unsigned long size); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistruct seq_file; 97762306a36Sopenharmony_civoid mmu_info(struct seq_file *); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistruct vm_area_struct; 98062306a36Sopenharmony_civoid update_mmu_cache_range(struct vm_fault *, struct vm_area_struct *, 98162306a36Sopenharmony_ci unsigned long addr, pte_t *ptep, unsigned int nr); 98262306a36Sopenharmony_ci#define update_mmu_cache(vma, addr, ptep) \ 98362306a36Sopenharmony_ci update_mmu_cache_range(NULL, vma, addr, ptep, 1) 98462306a36Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 98562306a36Sopenharmony_civoid update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, 98662306a36Sopenharmony_ci pmd_t *pmd); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci#define __HAVE_ARCH_PMDP_INVALIDATE 98962306a36Sopenharmony_ciextern pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 99062306a36Sopenharmony_ci pmd_t *pmdp); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci#define __HAVE_ARCH_PGTABLE_DEPOSIT 99362306a36Sopenharmony_civoid pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, 99462306a36Sopenharmony_ci pgtable_t pgtable); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci#define __HAVE_ARCH_PGTABLE_WITHDRAW 99762306a36Sopenharmony_cipgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); 99862306a36Sopenharmony_ci#endif 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci/* 100162306a36Sopenharmony_ci * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that 100262306a36Sopenharmony_ci * are !pte_none() && !pte_present(). 100362306a36Sopenharmony_ci * 100462306a36Sopenharmony_ci * Format of swap PTEs: 100562306a36Sopenharmony_ci * 100662306a36Sopenharmony_ci * 6 6 6 6 5 5 5 5 5 5 5 5 5 5 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 100762306a36Sopenharmony_ci * 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 100862306a36Sopenharmony_ci * <--------------------------- offset --------------------------- 100962306a36Sopenharmony_ci * 101062306a36Sopenharmony_ci * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 101162306a36Sopenharmony_ci * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 101262306a36Sopenharmony_ci * --------------------> E <-- type ---> <------- zeroes --------> 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_ci#define __swp_type(entry) (((entry).val >> PAGE_SHIFT) & 0x7fUL) 101562306a36Sopenharmony_ci#define __swp_offset(entry) ((entry).val >> (PAGE_SHIFT + 8UL)) 101662306a36Sopenharmony_ci#define __swp_entry(type, offset) \ 101762306a36Sopenharmony_ci ( (swp_entry_t) \ 101862306a36Sopenharmony_ci { \ 101962306a36Sopenharmony_ci ((((long)(type) & 0x7fUL) << PAGE_SHIFT) | \ 102062306a36Sopenharmony_ci ((long)(offset) << (PAGE_SHIFT + 8UL))) \ 102162306a36Sopenharmony_ci } ) 102262306a36Sopenharmony_ci#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) 102362306a36Sopenharmony_ci#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic inline int pte_swp_exclusive(pte_t pte) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci return pte_val(pte) & _PAGE_SWP_EXCLUSIVE; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic inline pte_t pte_swp_mkexclusive(pte_t pte) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci return __pte(pte_val(pte) | _PAGE_SWP_EXCLUSIVE); 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic inline pte_t pte_swp_clear_exclusive(pte_t pte) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci return __pte(pte_val(pte) & ~_PAGE_SWP_EXCLUSIVE); 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ciint page_in_phys_avail(unsigned long paddr); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci/* 104362306a36Sopenharmony_ci * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in 104462306a36Sopenharmony_ci * its high 4 bits. These macros/functions put it there or get it from there. 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci#define MK_IOSPACE_PFN(space, pfn) (pfn | (space << (BITS_PER_LONG - 4))) 104762306a36Sopenharmony_ci#define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) 104862306a36Sopenharmony_ci#define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL) 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciint remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, 105162306a36Sopenharmony_ci unsigned long, pgprot_t); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_civoid adi_restore_tags(struct mm_struct *mm, struct vm_area_struct *vma, 105462306a36Sopenharmony_ci unsigned long addr, pte_t pte); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ciint adi_save_tags(struct mm_struct *mm, struct vm_area_struct *vma, 105762306a36Sopenharmony_ci unsigned long addr, pte_t oldpte); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci#define __HAVE_ARCH_DO_SWAP_PAGE 106062306a36Sopenharmony_cistatic inline void arch_do_swap_page(struct mm_struct *mm, 106162306a36Sopenharmony_ci struct vm_area_struct *vma, 106262306a36Sopenharmony_ci unsigned long addr, 106362306a36Sopenharmony_ci pte_t pte, pte_t oldpte) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci /* If this is a new page being mapped in, there can be no 106662306a36Sopenharmony_ci * ADI tags stored away for this page. Skip looking for 106762306a36Sopenharmony_ci * stored tags 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ci if (pte_none(oldpte)) 107062306a36Sopenharmony_ci return; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (adi_state.enabled && (pte_val(pte) & _PAGE_MCD_4V)) 107362306a36Sopenharmony_ci adi_restore_tags(mm, vma, addr, pte); 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci#define __HAVE_ARCH_UNMAP_ONE 107762306a36Sopenharmony_cistatic inline int arch_unmap_one(struct mm_struct *mm, 107862306a36Sopenharmony_ci struct vm_area_struct *vma, 107962306a36Sopenharmony_ci unsigned long addr, pte_t oldpte) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci if (adi_state.enabled && (pte_val(oldpte) & _PAGE_MCD_4V)) 108262306a36Sopenharmony_ci return adi_save_tags(mm, vma, addr, oldpte); 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic inline int io_remap_pfn_range(struct vm_area_struct *vma, 108762306a36Sopenharmony_ci unsigned long from, unsigned long pfn, 108862306a36Sopenharmony_ci unsigned long size, pgprot_t prot) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; 109162306a36Sopenharmony_ci int space = GET_IOSPACE(pfn); 109262306a36Sopenharmony_ci unsigned long phys_base; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci phys_base = offset | (((unsigned long) space) << 32UL); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot); 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci#define io_remap_pfn_range io_remap_pfn_range 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic inline unsigned long __untagged_addr(unsigned long start) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci if (adi_capable()) { 110362306a36Sopenharmony_ci long addr = start; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* If userspace has passed a versioned address, kernel 110662306a36Sopenharmony_ci * will not find it in the VMAs since it does not store 110762306a36Sopenharmony_ci * the version tags in the list of VMAs. Storing version 110862306a36Sopenharmony_ci * tags in list of VMAs is impractical since they can be 110962306a36Sopenharmony_ci * changed any time from userspace without dropping into 111062306a36Sopenharmony_ci * kernel. Any address search in VMAs will be done with 111162306a36Sopenharmony_ci * non-versioned addresses. Ensure the ADI version bits 111262306a36Sopenharmony_ci * are dropped here by sign extending the last bit before 111362306a36Sopenharmony_ci * ADI bits. IOMMU does not implement version tags. 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci return (addr << (long)adi_nbits()) >> (long)adi_nbits(); 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return start; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci#define untagged_addr(addr) \ 112162306a36Sopenharmony_ci ((__typeof__(addr))(__untagged_addr((unsigned long)(addr)))) 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cistatic inline bool pte_access_permitted(pte_t pte, bool write) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci u64 prot; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (tlb_type == hypervisor) { 112862306a36Sopenharmony_ci prot = _PAGE_PRESENT_4V | _PAGE_P_4V; 112962306a36Sopenharmony_ci if (write) 113062306a36Sopenharmony_ci prot |= _PAGE_WRITE_4V; 113162306a36Sopenharmony_ci } else { 113262306a36Sopenharmony_ci prot = _PAGE_PRESENT_4U | _PAGE_P_4U; 113362306a36Sopenharmony_ci if (write) 113462306a36Sopenharmony_ci prot |= _PAGE_WRITE_4U; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return (pte_val(pte) & (prot | _PAGE_SPECIAL)) == prot; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci#define pte_access_permitted pte_access_permitted 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci/* We provide our own get_unmapped_area to cope with VA holes and 114262306a36Sopenharmony_ci * SHM area cache aliasing for userland. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA 114562306a36Sopenharmony_ci#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci/* We provide a special get_unmapped_area for framebuffer mmaps to try and use 114862306a36Sopenharmony_ci * the largest alignment possible such that larget PTEs can be used. 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_ciunsigned long get_fb_unmapped_area(struct file *filp, unsigned long, 115162306a36Sopenharmony_ci unsigned long, unsigned long, 115262306a36Sopenharmony_ci unsigned long); 115362306a36Sopenharmony_ci#define HAVE_ARCH_FB_UNMAPPED_AREA 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_civoid sun4v_register_fault_status(void); 115662306a36Sopenharmony_civoid sun4v_ktsb_register(void); 115762306a36Sopenharmony_civoid __init cheetah_ecache_flush_init(void); 115862306a36Sopenharmony_civoid sun4v_patch_tlb_handlers(void); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ciextern unsigned long cmdline_memory_size; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ciasmlinkage void do_sparc64_fault(struct pt_regs *regs); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci#define pmd_pgtable(PMD) ((pte_t *)pmd_page_vaddr(PMD)) 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci#define pud_leaf_size pud_leaf_size 116962306a36Sopenharmony_ciextern unsigned long pud_leaf_size(pud_t pud); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci#define pmd_leaf_size pmd_leaf_size 117262306a36Sopenharmony_ciextern unsigned long pmd_leaf_size(pmd_t pmd); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci#define pte_leaf_size pte_leaf_size 117562306a36Sopenharmony_ciextern unsigned long pte_leaf_size(pte_t pte); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci#endif /* CONFIG_HUGETLB_PAGE */ 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci#endif /* !(__ASSEMBLY__) */ 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci#endif /* !(_SPARC64_PGTABLE_H) */ 1182