162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/m68k/mm/motorola.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Routines specific to the Motorola MMU, originally from: 662306a36Sopenharmony_ci * linux/arch/m68k/init.c 762306a36Sopenharmony_ci * which are Copyright (C) 1995 Hamish Macdonald 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Moved 8/20/1999 Sam Creasey 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/signal.h> 1462306a36Sopenharmony_ci#include <linux/sched.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/swap.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/string.h> 1962306a36Sopenharmony_ci#include <linux/types.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/memblock.h> 2262306a36Sopenharmony_ci#include <linux/gfp.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <asm/setup.h> 2562306a36Sopenharmony_ci#include <linux/uaccess.h> 2662306a36Sopenharmony_ci#include <asm/page.h> 2762306a36Sopenharmony_ci#include <asm/pgalloc.h> 2862306a36Sopenharmony_ci#include <asm/machdep.h> 2962306a36Sopenharmony_ci#include <asm/io.h> 3062306a36Sopenharmony_ci#ifdef CONFIG_ATARI 3162306a36Sopenharmony_ci#include <asm/atari_stram.h> 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci#include <asm/sections.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#undef DEBUG 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifndef mm_cachebits 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Bits to add to page descriptors for "normal" caching mode. 4062306a36Sopenharmony_ci * For 68020/030 this is 0. 4162306a36Sopenharmony_ci * For 68040, this is _PAGE_CACHE040 (cachable, copyback) 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ciunsigned long mm_cachebits; 4462306a36Sopenharmony_ciEXPORT_SYMBOL(mm_cachebits); 4562306a36Sopenharmony_ci#endif 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* Prior to calling these routines, the page should have been flushed 4862306a36Sopenharmony_ci * from both the cache and ATC, or the CPU might not notice that the 4962306a36Sopenharmony_ci * cache setting for the page has been changed. -jskov 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic inline void nocache_page(void *vaddr) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (CPU_IS_040_OR_060) { 5662306a36Sopenharmony_ci pte_t *ptep = virt_to_kpte(addr); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci *ptep = pte_mknocache(*ptep); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic inline void cache_page(void *vaddr) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (CPU_IS_040_OR_060) { 6762306a36Sopenharmony_ci pte_t *ptep = virt_to_kpte(addr); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci *ptep = pte_mkcache(*ptep); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * Motorola 680x0 user's manual recommends using uncached memory for address 7562306a36Sopenharmony_ci * translation tables. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Seeing how the MMU can be external on (some of) these chips, that seems like 7862306a36Sopenharmony_ci * a very important recommendation to follow. Provide some helpers to combat 7962306a36Sopenharmony_ci * 'variation' amongst the users of this. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid mmu_page_ctor(void *page) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci __flush_pages_to_ram(page, 1); 8562306a36Sopenharmony_ci flush_tlb_kernel_page(page); 8662306a36Sopenharmony_ci nocache_page(page); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_civoid mmu_page_dtor(void *page) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci cache_page(page); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from 9562306a36Sopenharmony_ci struct page instead of separately kmalloced struct. Stolen from 9662306a36Sopenharmony_ci arch/sparc/mm/srmmu.c ... */ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_citypedef struct list_head ptable_desc; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic struct list_head ptable_list[2] = { 10162306a36Sopenharmony_ci LIST_HEAD_INIT(ptable_list[0]), 10262306a36Sopenharmony_ci LIST_HEAD_INIT(ptable_list[1]), 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page((void *)(page))->lru)) 10662306a36Sopenharmony_ci#define PD_PAGE(ptable) (list_entry(ptable, struct page, lru)) 10762306a36Sopenharmony_ci#define PD_MARKBITS(dp) (*(unsigned int *)&PD_PAGE(dp)->index) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const int ptable_shift[2] = { 11062306a36Sopenharmony_ci 7+2, /* PGD, PMD */ 11162306a36Sopenharmony_ci 6+2, /* PTE */ 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define ptable_size(type) (1U << ptable_shift[type]) 11562306a36Sopenharmony_ci#define ptable_mask(type) ((1U << (PAGE_SIZE / ptable_size(type))) - 1) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid __init init_pointer_table(void *table, int type) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci ptable_desc *dp; 12062306a36Sopenharmony_ci unsigned long ptable = (unsigned long)table; 12162306a36Sopenharmony_ci unsigned long page = ptable & PAGE_MASK; 12262306a36Sopenharmony_ci unsigned int mask = 1U << ((ptable - page)/ptable_size(type)); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci dp = PD_PTABLE(page); 12562306a36Sopenharmony_ci if (!(PD_MARKBITS(dp) & mask)) { 12662306a36Sopenharmony_ci PD_MARKBITS(dp) = ptable_mask(type); 12762306a36Sopenharmony_ci list_add(dp, &ptable_list[type]); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci PD_MARKBITS(dp) &= ~mask; 13162306a36Sopenharmony_ci pr_debug("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp)); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* unreserve the page so it's possible to free that page */ 13462306a36Sopenharmony_ci __ClearPageReserved(PD_PAGE(dp)); 13562306a36Sopenharmony_ci init_page_count(PD_PAGE(dp)); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_civoid *get_pointer_table(int type) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci ptable_desc *dp = ptable_list[type].next; 14362306a36Sopenharmony_ci unsigned int mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp); 14462306a36Sopenharmony_ci unsigned int tmp, off; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * For a pointer table for a user process address space, a 14862306a36Sopenharmony_ci * table is taken from a page allocated for the purpose. Each 14962306a36Sopenharmony_ci * page can hold 8 pointer tables. The page is remapped in 15062306a36Sopenharmony_ci * virtual address space to be noncacheable. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if (mask == 0) { 15362306a36Sopenharmony_ci void *page; 15462306a36Sopenharmony_ci ptable_desc *new; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (!(page = (void *)get_zeroed_page(GFP_KERNEL))) 15762306a36Sopenharmony_ci return NULL; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (type == TABLE_PTE) { 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * m68k doesn't have SPLIT_PTE_PTLOCKS for not having 16262306a36Sopenharmony_ci * SMP. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci pagetable_pte_ctor(virt_to_ptdesc(page)); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mmu_page_ctor(page); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci new = PD_PTABLE(page); 17062306a36Sopenharmony_ci PD_MARKBITS(new) = ptable_mask(type) - 1; 17162306a36Sopenharmony_ci list_add_tail(new, dp); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return (pmd_t *)page; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += ptable_size(type)) 17762306a36Sopenharmony_ci ; 17862306a36Sopenharmony_ci PD_MARKBITS(dp) = mask & ~tmp; 17962306a36Sopenharmony_ci if (!PD_MARKBITS(dp)) { 18062306a36Sopenharmony_ci /* move to end of list */ 18162306a36Sopenharmony_ci list_move_tail(dp, &ptable_list[type]); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci return page_address(PD_PAGE(dp)) + off; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ciint free_pointer_table(void *table, int type) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci ptable_desc *dp; 18962306a36Sopenharmony_ci unsigned long ptable = (unsigned long)table; 19062306a36Sopenharmony_ci unsigned long page = ptable & PAGE_MASK; 19162306a36Sopenharmony_ci unsigned int mask = 1U << ((ptable - page)/ptable_size(type)); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dp = PD_PTABLE(page); 19462306a36Sopenharmony_ci if (PD_MARKBITS (dp) & mask) 19562306a36Sopenharmony_ci panic ("table already free!"); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci PD_MARKBITS (dp) |= mask; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (PD_MARKBITS(dp) == ptable_mask(type)) { 20062306a36Sopenharmony_ci /* all tables in page are free, free page */ 20162306a36Sopenharmony_ci list_del(dp); 20262306a36Sopenharmony_ci mmu_page_dtor((void *)page); 20362306a36Sopenharmony_ci if (type == TABLE_PTE) 20462306a36Sopenharmony_ci pagetable_pte_dtor(virt_to_ptdesc((void *)page)); 20562306a36Sopenharmony_ci free_page (page); 20662306a36Sopenharmony_ci return 1; 20762306a36Sopenharmony_ci } else if (ptable_list[type].next != dp) { 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * move this descriptor to the front of the list, since 21062306a36Sopenharmony_ci * it has one or more free tables. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci list_move(dp, &ptable_list[type]); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* size of memory already mapped in head.S */ 21862306a36Sopenharmony_ciextern __initdata unsigned long m68k_init_mapped_size; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciextern unsigned long availmem; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic pte_t *last_pte_table __initdata = NULL; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic pte_t * __init kernel_page_table(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci pte_t *pte_table = last_pte_table; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (PAGE_ALIGNED(last_pte_table)) { 22962306a36Sopenharmony_ci pte_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 23062306a36Sopenharmony_ci if (!pte_table) { 23162306a36Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=%lx\n", 23262306a36Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci clear_page(pte_table); 23662306a36Sopenharmony_ci mmu_page_ctor(pte_table); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci last_pte_table = pte_table; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci last_pte_table += PTRS_PER_PTE; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return pte_table; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic pmd_t *last_pmd_table __initdata = NULL; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic pmd_t * __init kernel_ptr_table(void) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci if (!last_pmd_table) { 25162306a36Sopenharmony_ci unsigned long pmd, last; 25262306a36Sopenharmony_ci int i; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Find the last ptr table that was used in head.S and 25562306a36Sopenharmony_ci * reuse the remaining space in that page for further 25662306a36Sopenharmony_ci * ptr tables. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci last = (unsigned long)kernel_pg_dir; 25962306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PGD; i++) { 26062306a36Sopenharmony_ci pud_t *pud = (pud_t *)(&kernel_pg_dir[i]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!pud_present(*pud)) 26362306a36Sopenharmony_ci continue; 26462306a36Sopenharmony_ci pmd = pgd_page_vaddr(kernel_pg_dir[i]); 26562306a36Sopenharmony_ci if (pmd > last) 26662306a36Sopenharmony_ci last = pmd; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci last_pmd_table = (pmd_t *)last; 27062306a36Sopenharmony_ci#ifdef DEBUG 27162306a36Sopenharmony_ci printk("kernel_ptr_init: %p\n", last_pmd_table); 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci last_pmd_table += PTRS_PER_PMD; 27662306a36Sopenharmony_ci if (PAGE_ALIGNED(last_pmd_table)) { 27762306a36Sopenharmony_ci last_pmd_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 27862306a36Sopenharmony_ci if (!last_pmd_table) 27962306a36Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=%lx\n", 28062306a36Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci clear_page(last_pmd_table); 28362306a36Sopenharmony_ci mmu_page_ctor(last_pmd_table); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return last_pmd_table; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void __init map_node(int node) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci unsigned long physaddr, virtaddr, size; 29262306a36Sopenharmony_ci pgd_t *pgd_dir; 29362306a36Sopenharmony_ci p4d_t *p4d_dir; 29462306a36Sopenharmony_ci pud_t *pud_dir; 29562306a36Sopenharmony_ci pmd_t *pmd_dir; 29662306a36Sopenharmony_ci pte_t *pte_dir; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci size = m68k_memory[node].size; 29962306a36Sopenharmony_ci physaddr = m68k_memory[node].addr; 30062306a36Sopenharmony_ci virtaddr = (unsigned long)phys_to_virt(physaddr); 30162306a36Sopenharmony_ci physaddr |= m68k_supervisor_cachemode | 30262306a36Sopenharmony_ci _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY; 30362306a36Sopenharmony_ci if (CPU_IS_040_OR_060) 30462306a36Sopenharmony_ci physaddr |= _PAGE_GLOBAL040; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci while (size > 0) { 30762306a36Sopenharmony_ci#ifdef DEBUG 30862306a36Sopenharmony_ci if (!(virtaddr & (PMD_SIZE-1))) 30962306a36Sopenharmony_ci printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK, 31062306a36Sopenharmony_ci virtaddr); 31162306a36Sopenharmony_ci#endif 31262306a36Sopenharmony_ci pgd_dir = pgd_offset_k(virtaddr); 31362306a36Sopenharmony_ci if (virtaddr && CPU_IS_020_OR_030) { 31462306a36Sopenharmony_ci if (!(virtaddr & (PGDIR_SIZE-1)) && 31562306a36Sopenharmony_ci size >= PGDIR_SIZE) { 31662306a36Sopenharmony_ci#ifdef DEBUG 31762306a36Sopenharmony_ci printk ("[very early term]"); 31862306a36Sopenharmony_ci#endif 31962306a36Sopenharmony_ci pgd_val(*pgd_dir) = physaddr; 32062306a36Sopenharmony_ci size -= PGDIR_SIZE; 32162306a36Sopenharmony_ci virtaddr += PGDIR_SIZE; 32262306a36Sopenharmony_ci physaddr += PGDIR_SIZE; 32362306a36Sopenharmony_ci continue; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci p4d_dir = p4d_offset(pgd_dir, virtaddr); 32762306a36Sopenharmony_ci pud_dir = pud_offset(p4d_dir, virtaddr); 32862306a36Sopenharmony_ci if (!pud_present(*pud_dir)) { 32962306a36Sopenharmony_ci pmd_dir = kernel_ptr_table(); 33062306a36Sopenharmony_ci#ifdef DEBUG 33162306a36Sopenharmony_ci printk ("[new pointer %p]", pmd_dir); 33262306a36Sopenharmony_ci#endif 33362306a36Sopenharmony_ci pud_set(pud_dir, pmd_dir); 33462306a36Sopenharmony_ci } else 33562306a36Sopenharmony_ci pmd_dir = pmd_offset(pud_dir, virtaddr); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (CPU_IS_020_OR_030) { 33862306a36Sopenharmony_ci if (virtaddr) { 33962306a36Sopenharmony_ci#ifdef DEBUG 34062306a36Sopenharmony_ci printk ("[early term]"); 34162306a36Sopenharmony_ci#endif 34262306a36Sopenharmony_ci pmd_val(*pmd_dir) = physaddr; 34362306a36Sopenharmony_ci physaddr += PMD_SIZE; 34462306a36Sopenharmony_ci } else { 34562306a36Sopenharmony_ci int i; 34662306a36Sopenharmony_ci#ifdef DEBUG 34762306a36Sopenharmony_ci printk ("[zero map]"); 34862306a36Sopenharmony_ci#endif 34962306a36Sopenharmony_ci pte_dir = kernel_page_table(); 35062306a36Sopenharmony_ci pmd_set(pmd_dir, pte_dir); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci pte_val(*pte_dir++) = 0; 35362306a36Sopenharmony_ci physaddr += PAGE_SIZE; 35462306a36Sopenharmony_ci for (i = 1; i < PTRS_PER_PTE; physaddr += PAGE_SIZE, i++) 35562306a36Sopenharmony_ci pte_val(*pte_dir++) = physaddr; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci size -= PMD_SIZE; 35862306a36Sopenharmony_ci virtaddr += PMD_SIZE; 35962306a36Sopenharmony_ci } else { 36062306a36Sopenharmony_ci if (!pmd_present(*pmd_dir)) { 36162306a36Sopenharmony_ci#ifdef DEBUG 36262306a36Sopenharmony_ci printk ("[new table]"); 36362306a36Sopenharmony_ci#endif 36462306a36Sopenharmony_ci pte_dir = kernel_page_table(); 36562306a36Sopenharmony_ci pmd_set(pmd_dir, pte_dir); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci pte_dir = pte_offset_kernel(pmd_dir, virtaddr); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (virtaddr) { 37062306a36Sopenharmony_ci if (!pte_present(*pte_dir)) 37162306a36Sopenharmony_ci pte_val(*pte_dir) = physaddr; 37262306a36Sopenharmony_ci } else 37362306a36Sopenharmony_ci pte_val(*pte_dir) = 0; 37462306a36Sopenharmony_ci size -= PAGE_SIZE; 37562306a36Sopenharmony_ci virtaddr += PAGE_SIZE; 37662306a36Sopenharmony_ci physaddr += PAGE_SIZE; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci#ifdef DEBUG 38162306a36Sopenharmony_ci printk("\n"); 38262306a36Sopenharmony_ci#endif 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * Alternate definitions that are compile time constants, for 38762306a36Sopenharmony_ci * initializing protection_map. The cachebits are fixed later. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci#define PAGE_NONE_C __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) 39062306a36Sopenharmony_ci#define PAGE_SHARED_C __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) 39162306a36Sopenharmony_ci#define PAGE_COPY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED) 39262306a36Sopenharmony_ci#define PAGE_READONLY_C __pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED) 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic pgprot_t protection_map[16] __ro_after_init = { 39562306a36Sopenharmony_ci [VM_NONE] = PAGE_NONE_C, 39662306a36Sopenharmony_ci [VM_READ] = PAGE_READONLY_C, 39762306a36Sopenharmony_ci [VM_WRITE] = PAGE_COPY_C, 39862306a36Sopenharmony_ci [VM_WRITE | VM_READ] = PAGE_COPY_C, 39962306a36Sopenharmony_ci [VM_EXEC] = PAGE_READONLY_C, 40062306a36Sopenharmony_ci [VM_EXEC | VM_READ] = PAGE_READONLY_C, 40162306a36Sopenharmony_ci [VM_EXEC | VM_WRITE] = PAGE_COPY_C, 40262306a36Sopenharmony_ci [VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY_C, 40362306a36Sopenharmony_ci [VM_SHARED] = PAGE_NONE_C, 40462306a36Sopenharmony_ci [VM_SHARED | VM_READ] = PAGE_READONLY_C, 40562306a36Sopenharmony_ci [VM_SHARED | VM_WRITE] = PAGE_SHARED_C, 40662306a36Sopenharmony_ci [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED_C, 40762306a36Sopenharmony_ci [VM_SHARED | VM_EXEC] = PAGE_READONLY_C, 40862306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READONLY_C, 40962306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED_C, 41062306a36Sopenharmony_ci [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED_C 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ciDECLARE_VM_GET_PAGE_PROT 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/* 41562306a36Sopenharmony_ci * paging_init() continues the virtual memory environment setup which 41662306a36Sopenharmony_ci * was begun by the code in arch/head.S. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_civoid __init paging_init(void) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0, }; 42162306a36Sopenharmony_ci unsigned long min_addr, max_addr; 42262306a36Sopenharmony_ci unsigned long addr; 42362306a36Sopenharmony_ci int i; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci#ifdef DEBUG 42662306a36Sopenharmony_ci printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem); 42762306a36Sopenharmony_ci#endif 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Fix the cache mode in the page descriptors for the 680[46]0. */ 43062306a36Sopenharmony_ci if (CPU_IS_040_OR_060) { 43162306a36Sopenharmony_ci int i; 43262306a36Sopenharmony_ci#ifndef mm_cachebits 43362306a36Sopenharmony_ci mm_cachebits = _PAGE_CACHE040; 43462306a36Sopenharmony_ci#endif 43562306a36Sopenharmony_ci for (i = 0; i < 16; i++) 43662306a36Sopenharmony_ci pgprot_val(protection_map[i]) |= _PAGE_CACHE040; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci min_addr = m68k_memory[0].addr; 44062306a36Sopenharmony_ci max_addr = min_addr + m68k_memory[0].size - 1; 44162306a36Sopenharmony_ci memblock_add_node(m68k_memory[0].addr, m68k_memory[0].size, 0, 44262306a36Sopenharmony_ci MEMBLOCK_NONE); 44362306a36Sopenharmony_ci for (i = 1; i < m68k_num_memory;) { 44462306a36Sopenharmony_ci if (m68k_memory[i].addr < min_addr) { 44562306a36Sopenharmony_ci printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n", 44662306a36Sopenharmony_ci m68k_memory[i].addr, m68k_memory[i].size); 44762306a36Sopenharmony_ci printk("Fix your bootloader or use a memfile to make use of this area!\n"); 44862306a36Sopenharmony_ci m68k_num_memory--; 44962306a36Sopenharmony_ci memmove(m68k_memory + i, m68k_memory + i + 1, 45062306a36Sopenharmony_ci (m68k_num_memory - i) * sizeof(struct m68k_mem_info)); 45162306a36Sopenharmony_ci continue; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci memblock_add_node(m68k_memory[i].addr, m68k_memory[i].size, i, 45462306a36Sopenharmony_ci MEMBLOCK_NONE); 45562306a36Sopenharmony_ci addr = m68k_memory[i].addr + m68k_memory[i].size - 1; 45662306a36Sopenharmony_ci if (addr > max_addr) 45762306a36Sopenharmony_ci max_addr = addr; 45862306a36Sopenharmony_ci i++; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci m68k_memoffset = min_addr - PAGE_OFFSET; 46162306a36Sopenharmony_ci m68k_virt_to_node_shift = fls(max_addr - min_addr) - 6; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci module_fixup(NULL, __start_fixup, __stop_fixup); 46462306a36Sopenharmony_ci flush_icache(); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci high_memory = phys_to_virt(max_addr) + 1; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci min_low_pfn = availmem >> PAGE_SHIFT; 46962306a36Sopenharmony_ci max_pfn = max_low_pfn = (max_addr >> PAGE_SHIFT) + 1; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Reserve kernel text/data/bss and the memory allocated in head.S */ 47262306a36Sopenharmony_ci memblock_reserve(m68k_memory[0].addr, availmem - m68k_memory[0].addr); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * Map the physical memory available into the kernel virtual 47662306a36Sopenharmony_ci * address space. Make sure memblock will not try to allocate 47762306a36Sopenharmony_ci * pages beyond the memory we already mapped in head.S 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci memblock_set_bottom_up(true); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci for (i = 0; i < m68k_num_memory; i++) { 48262306a36Sopenharmony_ci m68k_setup_node(i); 48362306a36Sopenharmony_ci map_node(i); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci flush_tlb_all(); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci early_memtest(min_addr, max_addr); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * initialize the bad page table and bad page to point 49262306a36Sopenharmony_ci * to a couple of allocated pages 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci empty_zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 49562306a36Sopenharmony_ci if (!empty_zero_page) 49662306a36Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=0x%lx\n", 49762306a36Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * Set up SFC/DFC registers 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci set_fc(USER_DATA); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci#ifdef DEBUG 50562306a36Sopenharmony_ci printk ("before free_area_init\n"); 50662306a36Sopenharmony_ci#endif 50762306a36Sopenharmony_ci for (i = 0; i < m68k_num_memory; i++) 50862306a36Sopenharmony_ci if (node_present_pages(i)) 50962306a36Sopenharmony_ci node_set_state(i, N_NORMAL_MEMORY); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci max_zone_pfn[ZONE_DMA] = memblock_end_of_DRAM(); 51262306a36Sopenharmony_ci free_area_init(max_zone_pfn); 51362306a36Sopenharmony_ci} 514