18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/m68k/mm/motorola.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Routines specific to the Motorola MMU, originally from: 68c2ecf20Sopenharmony_ci * linux/arch/m68k/init.c 78c2ecf20Sopenharmony_ci * which are Copyright (C) 1995 Hamish Macdonald 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Moved 8/20/1999 Sam Creasey 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/signal.h> 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci#include <linux/swap.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/memblock.h> 228c2ecf20Sopenharmony_ci#include <linux/gfp.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/setup.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <asm/page.h> 278c2ecf20Sopenharmony_ci#include <asm/pgalloc.h> 288c2ecf20Sopenharmony_ci#include <asm/machdep.h> 298c2ecf20Sopenharmony_ci#include <asm/io.h> 308c2ecf20Sopenharmony_ci#include <asm/dma.h> 318c2ecf20Sopenharmony_ci#ifdef CONFIG_ATARI 328c2ecf20Sopenharmony_ci#include <asm/atari_stram.h> 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci#include <asm/sections.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#undef DEBUG 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifndef mm_cachebits 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Bits to add to page descriptors for "normal" caching mode. 418c2ecf20Sopenharmony_ci * For 68020/030 this is 0. 428c2ecf20Sopenharmony_ci * For 68040, this is _PAGE_CACHE040 (cachable, copyback) 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciunsigned long mm_cachebits; 458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mm_cachebits); 468c2ecf20Sopenharmony_ci#endif 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Prior to calling these routines, the page should have been flushed 498c2ecf20Sopenharmony_ci * from both the cache and ATC, or the CPU might not notice that the 508c2ecf20Sopenharmony_ci * cache setting for the page has been changed. -jskov 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistatic inline void nocache_page(void *vaddr) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (CPU_IS_040_OR_060) { 578c2ecf20Sopenharmony_ci pte_t *ptep = virt_to_kpte(addr); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci *ptep = pte_mknocache(*ptep); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline void cache_page(void *vaddr) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)vaddr; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (CPU_IS_040_OR_060) { 688c2ecf20Sopenharmony_ci pte_t *ptep = virt_to_kpte(addr); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci *ptep = pte_mkcache(*ptep); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * Motorola 680x0 user's manual recommends using uncached memory for address 768c2ecf20Sopenharmony_ci * translation tables. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Seeing how the MMU can be external on (some of) these chips, that seems like 798c2ecf20Sopenharmony_ci * a very important recommendation to follow. Provide some helpers to combat 808c2ecf20Sopenharmony_ci * 'variation' amongst the users of this. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid mmu_page_ctor(void *page) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci __flush_page_to_ram(page); 868c2ecf20Sopenharmony_ci flush_tlb_kernel_page(page); 878c2ecf20Sopenharmony_ci nocache_page(page); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_civoid mmu_page_dtor(void *page) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci cache_page(page); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from 968c2ecf20Sopenharmony_ci struct page instead of separately kmalloced struct. Stolen from 978c2ecf20Sopenharmony_ci arch/sparc/mm/srmmu.c ... */ 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_citypedef struct list_head ptable_desc; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct list_head ptable_list[2] = { 1028c2ecf20Sopenharmony_ci LIST_HEAD_INIT(ptable_list[0]), 1038c2ecf20Sopenharmony_ci LIST_HEAD_INIT(ptable_list[1]), 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page(page)->lru)) 1078c2ecf20Sopenharmony_ci#define PD_PAGE(ptable) (list_entry(ptable, struct page, lru)) 1088c2ecf20Sopenharmony_ci#define PD_MARKBITS(dp) (*(unsigned int *)&PD_PAGE(dp)->index) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const int ptable_shift[2] = { 1118c2ecf20Sopenharmony_ci 7+2, /* PGD, PMD */ 1128c2ecf20Sopenharmony_ci 6+2, /* PTE */ 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#define ptable_size(type) (1U << ptable_shift[type]) 1168c2ecf20Sopenharmony_ci#define ptable_mask(type) ((1U << (PAGE_SIZE / ptable_size(type))) - 1) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid __init init_pointer_table(void *table, int type) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci ptable_desc *dp; 1218c2ecf20Sopenharmony_ci unsigned long ptable = (unsigned long)table; 1228c2ecf20Sopenharmony_ci unsigned long page = ptable & PAGE_MASK; 1238c2ecf20Sopenharmony_ci unsigned int mask = 1U << ((ptable - page)/ptable_size(type)); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci dp = PD_PTABLE(page); 1268c2ecf20Sopenharmony_ci if (!(PD_MARKBITS(dp) & mask)) { 1278c2ecf20Sopenharmony_ci PD_MARKBITS(dp) = ptable_mask(type); 1288c2ecf20Sopenharmony_ci list_add(dp, &ptable_list[type]); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci PD_MARKBITS(dp) &= ~mask; 1328c2ecf20Sopenharmony_ci pr_debug("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp)); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* unreserve the page so it's possible to free that page */ 1358c2ecf20Sopenharmony_ci __ClearPageReserved(PD_PAGE(dp)); 1368c2ecf20Sopenharmony_ci init_page_count(PD_PAGE(dp)); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_civoid *get_pointer_table(int type) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci ptable_desc *dp = ptable_list[type].next; 1448c2ecf20Sopenharmony_ci unsigned int mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp); 1458c2ecf20Sopenharmony_ci unsigned int tmp, off; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci * For a pointer table for a user process address space, a 1498c2ecf20Sopenharmony_ci * table is taken from a page allocated for the purpose. Each 1508c2ecf20Sopenharmony_ci * page can hold 8 pointer tables. The page is remapped in 1518c2ecf20Sopenharmony_ci * virtual address space to be noncacheable. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci if (mask == 0) { 1548c2ecf20Sopenharmony_ci void *page; 1558c2ecf20Sopenharmony_ci ptable_desc *new; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (!(page = (void *)get_zeroed_page(GFP_KERNEL))) 1588c2ecf20Sopenharmony_ci return NULL; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (type == TABLE_PTE) { 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * m68k doesn't have SPLIT_PTE_PTLOCKS for not having 1638c2ecf20Sopenharmony_ci * SMP. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci pgtable_pte_page_ctor(virt_to_page(page)); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mmu_page_ctor(page); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci new = PD_PTABLE(page); 1718c2ecf20Sopenharmony_ci PD_MARKBITS(new) = ptable_mask(type) - 1; 1728c2ecf20Sopenharmony_ci list_add_tail(new, dp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return (pmd_t *)page; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += ptable_size(type)) 1788c2ecf20Sopenharmony_ci ; 1798c2ecf20Sopenharmony_ci PD_MARKBITS(dp) = mask & ~tmp; 1808c2ecf20Sopenharmony_ci if (!PD_MARKBITS(dp)) { 1818c2ecf20Sopenharmony_ci /* move to end of list */ 1828c2ecf20Sopenharmony_ci list_move_tail(dp, &ptable_list[type]); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci return page_address(PD_PAGE(dp)) + off; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ciint free_pointer_table(void *table, int type) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci ptable_desc *dp; 1908c2ecf20Sopenharmony_ci unsigned long ptable = (unsigned long)table; 1918c2ecf20Sopenharmony_ci unsigned long page = ptable & PAGE_MASK; 1928c2ecf20Sopenharmony_ci unsigned int mask = 1U << ((ptable - page)/ptable_size(type)); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci dp = PD_PTABLE(page); 1958c2ecf20Sopenharmony_ci if (PD_MARKBITS (dp) & mask) 1968c2ecf20Sopenharmony_ci panic ("table already free!"); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci PD_MARKBITS (dp) |= mask; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (PD_MARKBITS(dp) == ptable_mask(type)) { 2018c2ecf20Sopenharmony_ci /* all tables in page are free, free page */ 2028c2ecf20Sopenharmony_ci list_del(dp); 2038c2ecf20Sopenharmony_ci mmu_page_dtor((void *)page); 2048c2ecf20Sopenharmony_ci if (type == TABLE_PTE) 2058c2ecf20Sopenharmony_ci pgtable_pte_page_dtor(virt_to_page(page)); 2068c2ecf20Sopenharmony_ci free_page (page); 2078c2ecf20Sopenharmony_ci return 1; 2088c2ecf20Sopenharmony_ci } else if (ptable_list[type].next != dp) { 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * move this descriptor to the front of the list, since 2118c2ecf20Sopenharmony_ci * it has one or more free tables. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci list_move(dp, &ptable_list[type]); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* size of memory already mapped in head.S */ 2198c2ecf20Sopenharmony_ciextern __initdata unsigned long m68k_init_mapped_size; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciextern unsigned long availmem; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic pte_t *last_pte_table __initdata = NULL; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic pte_t * __init kernel_page_table(void) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci pte_t *pte_table = last_pte_table; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (PAGE_ALIGNED(last_pte_table)) { 2308c2ecf20Sopenharmony_ci pte_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 2318c2ecf20Sopenharmony_ci if (!pte_table) { 2328c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=%lx\n", 2338c2ecf20Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci clear_page(pte_table); 2378c2ecf20Sopenharmony_ci mmu_page_ctor(pte_table); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci last_pte_table = pte_table; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci last_pte_table += PTRS_PER_PTE; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return pte_table; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic pmd_t *last_pmd_table __initdata = NULL; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic pmd_t * __init kernel_ptr_table(void) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci if (!last_pmd_table) { 2528c2ecf20Sopenharmony_ci unsigned long pmd, last; 2538c2ecf20Sopenharmony_ci int i; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Find the last ptr table that was used in head.S and 2568c2ecf20Sopenharmony_ci * reuse the remaining space in that page for further 2578c2ecf20Sopenharmony_ci * ptr tables. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci last = (unsigned long)kernel_pg_dir; 2608c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_PGD; i++) { 2618c2ecf20Sopenharmony_ci pud_t *pud = (pud_t *)(&kernel_pg_dir[i]); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!pud_present(*pud)) 2648c2ecf20Sopenharmony_ci continue; 2658c2ecf20Sopenharmony_ci pmd = pgd_page_vaddr(kernel_pg_dir[i]); 2668c2ecf20Sopenharmony_ci if (pmd > last) 2678c2ecf20Sopenharmony_ci last = pmd; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci last_pmd_table = (pmd_t *)last; 2718c2ecf20Sopenharmony_ci#ifdef DEBUG 2728c2ecf20Sopenharmony_ci printk("kernel_ptr_init: %p\n", last_pmd_table); 2738c2ecf20Sopenharmony_ci#endif 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci last_pmd_table += PTRS_PER_PMD; 2778c2ecf20Sopenharmony_ci if (PAGE_ALIGNED(last_pmd_table)) { 2788c2ecf20Sopenharmony_ci last_pmd_table = memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); 2798c2ecf20Sopenharmony_ci if (!last_pmd_table) 2808c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=%lx\n", 2818c2ecf20Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci clear_page(last_pmd_table); 2848c2ecf20Sopenharmony_ci mmu_page_ctor(last_pmd_table); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return last_pmd_table; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void __init map_node(int node) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci unsigned long physaddr, virtaddr, size; 2938c2ecf20Sopenharmony_ci pgd_t *pgd_dir; 2948c2ecf20Sopenharmony_ci p4d_t *p4d_dir; 2958c2ecf20Sopenharmony_ci pud_t *pud_dir; 2968c2ecf20Sopenharmony_ci pmd_t *pmd_dir; 2978c2ecf20Sopenharmony_ci pte_t *pte_dir; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci size = m68k_memory[node].size; 3008c2ecf20Sopenharmony_ci physaddr = m68k_memory[node].addr; 3018c2ecf20Sopenharmony_ci virtaddr = (unsigned long)phys_to_virt(physaddr); 3028c2ecf20Sopenharmony_ci physaddr |= m68k_supervisor_cachemode | 3038c2ecf20Sopenharmony_ci _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY; 3048c2ecf20Sopenharmony_ci if (CPU_IS_040_OR_060) 3058c2ecf20Sopenharmony_ci physaddr |= _PAGE_GLOBAL040; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci while (size > 0) { 3088c2ecf20Sopenharmony_ci#ifdef DEBUG 3098c2ecf20Sopenharmony_ci if (!(virtaddr & (PMD_SIZE-1))) 3108c2ecf20Sopenharmony_ci printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK, 3118c2ecf20Sopenharmony_ci virtaddr); 3128c2ecf20Sopenharmony_ci#endif 3138c2ecf20Sopenharmony_ci pgd_dir = pgd_offset_k(virtaddr); 3148c2ecf20Sopenharmony_ci if (virtaddr && CPU_IS_020_OR_030) { 3158c2ecf20Sopenharmony_ci if (!(virtaddr & (PGDIR_SIZE-1)) && 3168c2ecf20Sopenharmony_ci size >= PGDIR_SIZE) { 3178c2ecf20Sopenharmony_ci#ifdef DEBUG 3188c2ecf20Sopenharmony_ci printk ("[very early term]"); 3198c2ecf20Sopenharmony_ci#endif 3208c2ecf20Sopenharmony_ci pgd_val(*pgd_dir) = physaddr; 3218c2ecf20Sopenharmony_ci size -= PGDIR_SIZE; 3228c2ecf20Sopenharmony_ci virtaddr += PGDIR_SIZE; 3238c2ecf20Sopenharmony_ci physaddr += PGDIR_SIZE; 3248c2ecf20Sopenharmony_ci continue; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci p4d_dir = p4d_offset(pgd_dir, virtaddr); 3288c2ecf20Sopenharmony_ci pud_dir = pud_offset(p4d_dir, virtaddr); 3298c2ecf20Sopenharmony_ci if (!pud_present(*pud_dir)) { 3308c2ecf20Sopenharmony_ci pmd_dir = kernel_ptr_table(); 3318c2ecf20Sopenharmony_ci#ifdef DEBUG 3328c2ecf20Sopenharmony_ci printk ("[new pointer %p]", pmd_dir); 3338c2ecf20Sopenharmony_ci#endif 3348c2ecf20Sopenharmony_ci pud_set(pud_dir, pmd_dir); 3358c2ecf20Sopenharmony_ci } else 3368c2ecf20Sopenharmony_ci pmd_dir = pmd_offset(pud_dir, virtaddr); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (CPU_IS_020_OR_030) { 3398c2ecf20Sopenharmony_ci if (virtaddr) { 3408c2ecf20Sopenharmony_ci#ifdef DEBUG 3418c2ecf20Sopenharmony_ci printk ("[early term]"); 3428c2ecf20Sopenharmony_ci#endif 3438c2ecf20Sopenharmony_ci pmd_val(*pmd_dir) = physaddr; 3448c2ecf20Sopenharmony_ci physaddr += PMD_SIZE; 3458c2ecf20Sopenharmony_ci } else { 3468c2ecf20Sopenharmony_ci int i; 3478c2ecf20Sopenharmony_ci#ifdef DEBUG 3488c2ecf20Sopenharmony_ci printk ("[zero map]"); 3498c2ecf20Sopenharmony_ci#endif 3508c2ecf20Sopenharmony_ci pte_dir = kernel_page_table(); 3518c2ecf20Sopenharmony_ci pmd_set(pmd_dir, pte_dir); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci pte_val(*pte_dir++) = 0; 3548c2ecf20Sopenharmony_ci physaddr += PAGE_SIZE; 3558c2ecf20Sopenharmony_ci for (i = 1; i < PTRS_PER_PTE; physaddr += PAGE_SIZE, i++) 3568c2ecf20Sopenharmony_ci pte_val(*pte_dir++) = physaddr; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci size -= PMD_SIZE; 3598c2ecf20Sopenharmony_ci virtaddr += PMD_SIZE; 3608c2ecf20Sopenharmony_ci } else { 3618c2ecf20Sopenharmony_ci if (!pmd_present(*pmd_dir)) { 3628c2ecf20Sopenharmony_ci#ifdef DEBUG 3638c2ecf20Sopenharmony_ci printk ("[new table]"); 3648c2ecf20Sopenharmony_ci#endif 3658c2ecf20Sopenharmony_ci pte_dir = kernel_page_table(); 3668c2ecf20Sopenharmony_ci pmd_set(pmd_dir, pte_dir); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci pte_dir = pte_offset_kernel(pmd_dir, virtaddr); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (virtaddr) { 3718c2ecf20Sopenharmony_ci if (!pte_present(*pte_dir)) 3728c2ecf20Sopenharmony_ci pte_val(*pte_dir) = physaddr; 3738c2ecf20Sopenharmony_ci } else 3748c2ecf20Sopenharmony_ci pte_val(*pte_dir) = 0; 3758c2ecf20Sopenharmony_ci size -= PAGE_SIZE; 3768c2ecf20Sopenharmony_ci virtaddr += PAGE_SIZE; 3778c2ecf20Sopenharmony_ci physaddr += PAGE_SIZE; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci#ifdef DEBUG 3828c2ecf20Sopenharmony_ci printk("\n"); 3838c2ecf20Sopenharmony_ci#endif 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* 3878c2ecf20Sopenharmony_ci * paging_init() continues the virtual memory environment setup which 3888c2ecf20Sopenharmony_ci * was begun by the code in arch/head.S. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_civoid __init paging_init(void) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0, }; 3938c2ecf20Sopenharmony_ci unsigned long min_addr, max_addr; 3948c2ecf20Sopenharmony_ci unsigned long addr; 3958c2ecf20Sopenharmony_ci int i; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci#ifdef DEBUG 3988c2ecf20Sopenharmony_ci printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem); 3998c2ecf20Sopenharmony_ci#endif 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Fix the cache mode in the page descriptors for the 680[46]0. */ 4028c2ecf20Sopenharmony_ci if (CPU_IS_040_OR_060) { 4038c2ecf20Sopenharmony_ci int i; 4048c2ecf20Sopenharmony_ci#ifndef mm_cachebits 4058c2ecf20Sopenharmony_ci mm_cachebits = _PAGE_CACHE040; 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 4088c2ecf20Sopenharmony_ci pgprot_val(protection_map[i]) |= _PAGE_CACHE040; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci min_addr = m68k_memory[0].addr; 4128c2ecf20Sopenharmony_ci max_addr = min_addr + m68k_memory[0].size; 4138c2ecf20Sopenharmony_ci memblock_add_node(m68k_memory[0].addr, m68k_memory[0].size, 0); 4148c2ecf20Sopenharmony_ci for (i = 1; i < m68k_num_memory;) { 4158c2ecf20Sopenharmony_ci if (m68k_memory[i].addr < min_addr) { 4168c2ecf20Sopenharmony_ci printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n", 4178c2ecf20Sopenharmony_ci m68k_memory[i].addr, m68k_memory[i].size); 4188c2ecf20Sopenharmony_ci printk("Fix your bootloader or use a memfile to make use of this area!\n"); 4198c2ecf20Sopenharmony_ci m68k_num_memory--; 4208c2ecf20Sopenharmony_ci memmove(m68k_memory + i, m68k_memory + i + 1, 4218c2ecf20Sopenharmony_ci (m68k_num_memory - i) * sizeof(struct m68k_mem_info)); 4228c2ecf20Sopenharmony_ci continue; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci memblock_add_node(m68k_memory[i].addr, m68k_memory[i].size, i); 4258c2ecf20Sopenharmony_ci addr = m68k_memory[i].addr + m68k_memory[i].size; 4268c2ecf20Sopenharmony_ci if (addr > max_addr) 4278c2ecf20Sopenharmony_ci max_addr = addr; 4288c2ecf20Sopenharmony_ci i++; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci m68k_memoffset = min_addr - PAGE_OFFSET; 4318c2ecf20Sopenharmony_ci m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci module_fixup(NULL, __start_fixup, __stop_fixup); 4348c2ecf20Sopenharmony_ci flush_icache(); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci high_memory = phys_to_virt(max_addr); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci min_low_pfn = availmem >> PAGE_SHIFT; 4398c2ecf20Sopenharmony_ci max_pfn = max_low_pfn = max_addr >> PAGE_SHIFT; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Reserve kernel text/data/bss and the memory allocated in head.S */ 4428c2ecf20Sopenharmony_ci memblock_reserve(m68k_memory[0].addr, availmem - m68k_memory[0].addr); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* 4458c2ecf20Sopenharmony_ci * Map the physical memory available into the kernel virtual 4468c2ecf20Sopenharmony_ci * address space. Make sure memblock will not try to allocate 4478c2ecf20Sopenharmony_ci * pages beyond the memory we already mapped in head.S 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci memblock_set_bottom_up(true); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci for (i = 0; i < m68k_num_memory; i++) { 4528c2ecf20Sopenharmony_ci m68k_setup_node(i); 4538c2ecf20Sopenharmony_ci map_node(i); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci flush_tlb_all(); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* 4598c2ecf20Sopenharmony_ci * initialize the bad page table and bad page to point 4608c2ecf20Sopenharmony_ci * to a couple of allocated pages 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci empty_zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 4638c2ecf20Sopenharmony_ci if (!empty_zero_page) 4648c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=0x%lx\n", 4658c2ecf20Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* 4688c2ecf20Sopenharmony_ci * Set up SFC/DFC registers 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci set_fs(KERNEL_DS); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci#ifdef DEBUG 4738c2ecf20Sopenharmony_ci printk ("before free_area_init\n"); 4748c2ecf20Sopenharmony_ci#endif 4758c2ecf20Sopenharmony_ci for (i = 0; i < m68k_num_memory; i++) 4768c2ecf20Sopenharmony_ci if (node_present_pages(i)) 4778c2ecf20Sopenharmony_ci node_set_state(i, N_NORMAL_MEMORY); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci max_zone_pfn[ZONE_DMA] = memblock_end_of_DRAM(); 4808c2ecf20Sopenharmony_ci free_area_init(max_zone_pfn); 4818c2ecf20Sopenharmony_ci} 482