/* SPDX-License-Identifier: GPL-2.0-only */1/*2* Page table support for the Hexagon architecture3*4* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.5*/67#ifndef _ASM_PGALLOC_H8#define _ASM_PGALLOC_H910#include <asm/mem-layout.h>11#include <asm/atomic.h>1213#include <asm-generic/pgalloc.h>1415extern unsigned long long kmap_generation;1617/*18* Page table creation interface19*/20static inline pgd_t *pgd_alloc(struct mm_struct *mm)21{22pgd_t *pgd;2324pgd = __pgd_alloc(mm, 0);2526/*27* There may be better ways to do this, but to ensure28* that new address spaces always contain the kernel29* base mapping, and to ensure that the user area is30* initially marked invalid, initialize the new map31* map with a copy of the kernel's persistent map.32*/3334memcpy(pgd, swapper_pg_dir, PTRS_PER_PGD*sizeof(pgd_t));35mm->context.generation = kmap_generation;3637/* Physical version is what is passed to virtual machine on switch */38mm->context.ptbase = __pa(pgd);3940return pgd;41}4243static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,44pgtable_t pte)45{46/*47* Conveniently, zero in 3 LSB means indirect 4K page table.48* Not so convenient when you're trying to vary the page size.49*/50set_pmd(pmd, __pmd(((unsigned long)page_to_pfn(pte) << PAGE_SHIFT) |51HEXAGON_L1_PTE_SIZE));52}5354/*55* Other architectures seem to have ways of making all processes56* share the same pmd's for their kernel mappings, but the v0.357* Hexagon VM spec has a "monolithic" L1 table for user and kernel58* segments. We track "generations" of the kernel map to minimize59* overhead, and update the "slave" copies of the kernel mappings60* as part of switch_mm. However, we still need to update the61* kernel map of the active thread who's calling pmd_populate_kernel...62*/63static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,64pte_t *pte)65{66extern spinlock_t kmap_gen_lock;67pmd_t *ppmd;68int pmdindex;6970spin_lock(&kmap_gen_lock);71kmap_generation++;72mm->context.generation = kmap_generation;73current->active_mm->context.generation = kmap_generation;74spin_unlock(&kmap_gen_lock);7576set_pmd(pmd, __pmd(((unsigned long)__pa(pte)) | HEXAGON_L1_PTE_SIZE));7778/*79* Now the "slave" copy of the current thread.80* This is pointer arithmetic, not byte addresses!81*/82pmdindex = (pgd_t *)pmd - mm->pgd;83ppmd = (pmd_t *)current->active_mm->pgd + pmdindex;84set_pmd(ppmd, __pmd(((unsigned long)__pa(pte)) | HEXAGON_L1_PTE_SIZE));85if (pmdindex > max_kernel_seg)86max_kernel_seg = pmdindex;87}8889#define __pte_free_tlb(tlb, pte, addr) \90tlb_remove_ptdesc((tlb), page_ptdesc(pte))9192#endif939495