162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1994 - 2000 Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 862306a36Sopenharmony_ci * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com 962306a36Sopenharmony_ci * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/bug.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/signal.h> 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci#include <linux/smp.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <linux/string.h> 2062306a36Sopenharmony_ci#include <linux/types.h> 2162306a36Sopenharmony_ci#include <linux/pagemap.h> 2262306a36Sopenharmony_ci#include <linux/ptrace.h> 2362306a36Sopenharmony_ci#include <linux/mman.h> 2462306a36Sopenharmony_ci#include <linux/mm.h> 2562306a36Sopenharmony_ci#include <linux/memblock.h> 2662306a36Sopenharmony_ci#include <linux/highmem.h> 2762306a36Sopenharmony_ci#include <linux/swap.h> 2862306a36Sopenharmony_ci#include <linux/proc_fs.h> 2962306a36Sopenharmony_ci#include <linux/pfn.h> 3062306a36Sopenharmony_ci#include <linux/hardirq.h> 3162306a36Sopenharmony_ci#include <linux/gfp.h> 3262306a36Sopenharmony_ci#include <linux/kcore.h> 3362306a36Sopenharmony_ci#include <linux/initrd.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <asm/bootinfo.h> 3662306a36Sopenharmony_ci#include <asm/cachectl.h> 3762306a36Sopenharmony_ci#include <asm/cpu.h> 3862306a36Sopenharmony_ci#include <asm/dma.h> 3962306a36Sopenharmony_ci#include <asm/maar.h> 4062306a36Sopenharmony_ci#include <asm/mmu_context.h> 4162306a36Sopenharmony_ci#include <asm/sections.h> 4262306a36Sopenharmony_ci#include <asm/pgalloc.h> 4362306a36Sopenharmony_ci#include <asm/tlb.h> 4462306a36Sopenharmony_ci#include <asm/fixmap.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * We have up to 8 empty zeroed pages so we can map one of the right colour 4862306a36Sopenharmony_ci * when needed. This is necessary only on R4000 / R4400 SC and MC versions 4962306a36Sopenharmony_ci * where we have to avoid VCED / VECI exceptions for good performance at 5062306a36Sopenharmony_ci * any price. Since page is never written to after the initialization we 5162306a36Sopenharmony_ci * don't have to care about aliases on other CPUs. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciunsigned long empty_zero_page, zero_page_mask; 5462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(empty_zero_page); 5562306a36Sopenharmony_ciEXPORT_SYMBOL(zero_page_mask); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Not static inline because used by IP27 special magic initialization code 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_civoid setup_zero_pages(void) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci unsigned int order, i; 6362306a36Sopenharmony_ci struct page *page; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (cpu_has_vce) 6662306a36Sopenharmony_ci order = 3; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci order = 0; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order); 7162306a36Sopenharmony_ci if (!empty_zero_page) 7262306a36Sopenharmony_ci panic("Oh boy, that early out of memory?"); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci page = virt_to_page((void *)empty_zero_page); 7562306a36Sopenharmony_ci split_page(page, order); 7662306a36Sopenharmony_ci for (i = 0; i < (1 << order); i++, page++) 7762306a36Sopenharmony_ci mark_page_reserved(page); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci enum fixed_addresses idx; 8562306a36Sopenharmony_ci unsigned int old_mmid; 8662306a36Sopenharmony_ci unsigned long vaddr, flags, entrylo; 8762306a36Sopenharmony_ci unsigned long old_ctx; 8862306a36Sopenharmony_ci pte_t pte; 8962306a36Sopenharmony_ci int tlbidx; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci BUG_ON(folio_test_dcache_dirty(page_folio(page))); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci preempt_disable(); 9462306a36Sopenharmony_ci pagefault_disable(); 9562306a36Sopenharmony_ci idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1); 9662306a36Sopenharmony_ci idx += in_interrupt() ? FIX_N_COLOURS : 0; 9762306a36Sopenharmony_ci vaddr = __fix_to_virt(FIX_CMAP_END - idx); 9862306a36Sopenharmony_ci pte = mk_pte(page, prot); 9962306a36Sopenharmony_ci#if defined(CONFIG_XPA) 10062306a36Sopenharmony_ci entrylo = pte_to_entrylo(pte.pte_high); 10162306a36Sopenharmony_ci#elif defined(CONFIG_PHYS_ADDR_T_64BIT) && defined(CONFIG_CPU_MIPS32) 10262306a36Sopenharmony_ci entrylo = pte.pte_high; 10362306a36Sopenharmony_ci#else 10462306a36Sopenharmony_ci entrylo = pte_to_entrylo(pte_val(pte)); 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci local_irq_save(flags); 10862306a36Sopenharmony_ci old_ctx = read_c0_entryhi(); 10962306a36Sopenharmony_ci write_c0_entryhi(vaddr & (PAGE_MASK << 1)); 11062306a36Sopenharmony_ci write_c0_entrylo0(entrylo); 11162306a36Sopenharmony_ci write_c0_entrylo1(entrylo); 11262306a36Sopenharmony_ci if (cpu_has_mmid) { 11362306a36Sopenharmony_ci old_mmid = read_c0_memorymapid(); 11462306a36Sopenharmony_ci write_c0_memorymapid(MMID_KERNEL_WIRED); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci#ifdef CONFIG_XPA 11762306a36Sopenharmony_ci if (cpu_has_xpa) { 11862306a36Sopenharmony_ci entrylo = (pte.pte_low & _PFNX_MASK); 11962306a36Sopenharmony_ci writex_c0_entrylo0(entrylo); 12062306a36Sopenharmony_ci writex_c0_entrylo1(entrylo); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci tlbidx = num_wired_entries(); 12462306a36Sopenharmony_ci write_c0_wired(tlbidx + 1); 12562306a36Sopenharmony_ci write_c0_index(tlbidx); 12662306a36Sopenharmony_ci mtc0_tlbw_hazard(); 12762306a36Sopenharmony_ci tlb_write_indexed(); 12862306a36Sopenharmony_ci tlbw_use_hazard(); 12962306a36Sopenharmony_ci write_c0_entryhi(old_ctx); 13062306a36Sopenharmony_ci if (cpu_has_mmid) 13162306a36Sopenharmony_ci write_c0_memorymapid(old_mmid); 13262306a36Sopenharmony_ci local_irq_restore(flags); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return (void*) vaddr; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_civoid *kmap_coherent(struct page *page, unsigned long addr) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return __kmap_pgprot(page, addr, PAGE_KERNEL); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid *kmap_noncoherent(struct page *page, unsigned long addr) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return __kmap_pgprot(page, addr, PAGE_KERNEL_NC); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_civoid kunmap_coherent(void) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci unsigned int wired; 15062306a36Sopenharmony_ci unsigned long flags, old_ctx; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci local_irq_save(flags); 15362306a36Sopenharmony_ci old_ctx = read_c0_entryhi(); 15462306a36Sopenharmony_ci wired = num_wired_entries() - 1; 15562306a36Sopenharmony_ci write_c0_wired(wired); 15662306a36Sopenharmony_ci write_c0_index(wired); 15762306a36Sopenharmony_ci write_c0_entryhi(UNIQUE_ENTRYHI(wired)); 15862306a36Sopenharmony_ci write_c0_entrylo0(0); 15962306a36Sopenharmony_ci write_c0_entrylo1(0); 16062306a36Sopenharmony_ci mtc0_tlbw_hazard(); 16162306a36Sopenharmony_ci tlb_write_indexed(); 16262306a36Sopenharmony_ci tlbw_use_hazard(); 16362306a36Sopenharmony_ci write_c0_entryhi(old_ctx); 16462306a36Sopenharmony_ci local_irq_restore(flags); 16562306a36Sopenharmony_ci pagefault_enable(); 16662306a36Sopenharmony_ci preempt_enable(); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid copy_user_highpage(struct page *to, struct page *from, 17062306a36Sopenharmony_ci unsigned long vaddr, struct vm_area_struct *vma) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct folio *src = page_folio(from); 17362306a36Sopenharmony_ci void *vfrom, *vto; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci vto = kmap_atomic(to); 17662306a36Sopenharmony_ci if (cpu_has_dc_aliases && 17762306a36Sopenharmony_ci folio_mapped(src) && !folio_test_dcache_dirty(src)) { 17862306a36Sopenharmony_ci vfrom = kmap_coherent(from, vaddr); 17962306a36Sopenharmony_ci copy_page(vto, vfrom); 18062306a36Sopenharmony_ci kunmap_coherent(); 18162306a36Sopenharmony_ci } else { 18262306a36Sopenharmony_ci vfrom = kmap_atomic(from); 18362306a36Sopenharmony_ci copy_page(vto, vfrom); 18462306a36Sopenharmony_ci kunmap_atomic(vfrom); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci if ((!cpu_has_ic_fills_f_dc) || 18762306a36Sopenharmony_ci pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) 18862306a36Sopenharmony_ci flush_data_cache_page((unsigned long)vto); 18962306a36Sopenharmony_ci kunmap_atomic(vto); 19062306a36Sopenharmony_ci /* Make sure this page is cleared on other CPU's too before using it */ 19162306a36Sopenharmony_ci smp_wmb(); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_civoid copy_to_user_page(struct vm_area_struct *vma, 19562306a36Sopenharmony_ci struct page *page, unsigned long vaddr, void *dst, const void *src, 19662306a36Sopenharmony_ci unsigned long len) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct folio *folio = page_folio(page); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (cpu_has_dc_aliases && 20162306a36Sopenharmony_ci folio_mapped(folio) && !folio_test_dcache_dirty(folio)) { 20262306a36Sopenharmony_ci void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 20362306a36Sopenharmony_ci memcpy(vto, src, len); 20462306a36Sopenharmony_ci kunmap_coherent(); 20562306a36Sopenharmony_ci } else { 20662306a36Sopenharmony_ci memcpy(dst, src, len); 20762306a36Sopenharmony_ci if (cpu_has_dc_aliases) 20862306a36Sopenharmony_ci folio_set_dcache_dirty(folio); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci if (vma->vm_flags & VM_EXEC) 21162306a36Sopenharmony_ci flush_cache_page(vma, vaddr, page_to_pfn(page)); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_civoid copy_from_user_page(struct vm_area_struct *vma, 21562306a36Sopenharmony_ci struct page *page, unsigned long vaddr, void *dst, const void *src, 21662306a36Sopenharmony_ci unsigned long len) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct folio *folio = page_folio(page); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (cpu_has_dc_aliases && 22162306a36Sopenharmony_ci folio_mapped(folio) && !folio_test_dcache_dirty(folio)) { 22262306a36Sopenharmony_ci void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); 22362306a36Sopenharmony_ci memcpy(dst, vfrom, len); 22462306a36Sopenharmony_ci kunmap_coherent(); 22562306a36Sopenharmony_ci } else { 22662306a36Sopenharmony_ci memcpy(dst, src, len); 22762306a36Sopenharmony_ci if (cpu_has_dc_aliases) 22862306a36Sopenharmony_ci folio_set_dcache_dirty(folio); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(copy_from_user_page); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_civoid __init fixrange_init(unsigned long start, unsigned long end, 23462306a36Sopenharmony_ci pgd_t *pgd_base) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci#ifdef CONFIG_HIGHMEM 23762306a36Sopenharmony_ci pgd_t *pgd; 23862306a36Sopenharmony_ci pud_t *pud; 23962306a36Sopenharmony_ci pmd_t *pmd; 24062306a36Sopenharmony_ci pte_t *pte; 24162306a36Sopenharmony_ci int i, j, k; 24262306a36Sopenharmony_ci unsigned long vaddr; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci vaddr = start; 24562306a36Sopenharmony_ci i = pgd_index(vaddr); 24662306a36Sopenharmony_ci j = pud_index(vaddr); 24762306a36Sopenharmony_ci k = pmd_index(vaddr); 24862306a36Sopenharmony_ci pgd = pgd_base + i; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { 25162306a36Sopenharmony_ci pud = (pud_t *)pgd; 25262306a36Sopenharmony_ci for ( ; (j < PTRS_PER_PUD) && (vaddr < end); pud++, j++) { 25362306a36Sopenharmony_ci pmd = (pmd_t *)pud; 25462306a36Sopenharmony_ci for (; (k < PTRS_PER_PMD) && (vaddr < end); pmd++, k++) { 25562306a36Sopenharmony_ci if (pmd_none(*pmd)) { 25662306a36Sopenharmony_ci pte = (pte_t *) memblock_alloc_low(PAGE_SIZE, 25762306a36Sopenharmony_ci PAGE_SIZE); 25862306a36Sopenharmony_ci if (!pte) 25962306a36Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=%lx\n", 26062306a36Sopenharmony_ci __func__, PAGE_SIZE, 26162306a36Sopenharmony_ci PAGE_SIZE); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci set_pmd(pmd, __pmd((unsigned long)pte)); 26462306a36Sopenharmony_ci BUG_ON(pte != pte_offset_kernel(pmd, 0)); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci vaddr += PMD_SIZE; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci k = 0; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci j = 0; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistruct maar_walk_info { 27662306a36Sopenharmony_ci struct maar_config cfg[16]; 27762306a36Sopenharmony_ci unsigned int num_cfg; 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages, 28162306a36Sopenharmony_ci void *data) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct maar_walk_info *wi = data; 28462306a36Sopenharmony_ci struct maar_config *cfg = &wi->cfg[wi->num_cfg]; 28562306a36Sopenharmony_ci unsigned int maar_align; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* MAAR registers hold physical addresses right shifted by 4 bits */ 28862306a36Sopenharmony_ci maar_align = BIT(MIPS_MAAR_ADDR_SHIFT + 4); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Fill in the MAAR config entry */ 29162306a36Sopenharmony_ci cfg->lower = ALIGN(PFN_PHYS(start_pfn), maar_align); 29262306a36Sopenharmony_ci cfg->upper = ALIGN_DOWN(PFN_PHYS(start_pfn + nr_pages), maar_align) - 1; 29362306a36Sopenharmony_ci cfg->attrs = MIPS_MAAR_S; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Ensure we don't overflow the cfg array */ 29662306a36Sopenharmony_ci if (!WARN_ON(wi->num_cfg >= ARRAY_SIZE(wi->cfg))) 29762306a36Sopenharmony_ci wi->num_cfg++; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciunsigned __weak platform_maar_init(unsigned num_pairs) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci unsigned int num_configured; 30662306a36Sopenharmony_ci struct maar_walk_info wi; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci wi.num_cfg = 0; 30962306a36Sopenharmony_ci walk_system_ram_range(0, max_pfn, &wi, maar_res_walk); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci num_configured = maar_config(wi.cfg, wi.num_cfg, num_pairs); 31262306a36Sopenharmony_ci if (num_configured < wi.num_cfg) 31362306a36Sopenharmony_ci pr_warn("Not enough MAAR pairs (%u) for all memory regions (%u)\n", 31462306a36Sopenharmony_ci num_pairs, wi.num_cfg); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return num_configured; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_civoid maar_init(void) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci unsigned num_maars, used, i; 32262306a36Sopenharmony_ci phys_addr_t lower, upper, attr; 32362306a36Sopenharmony_ci static struct { 32462306a36Sopenharmony_ci struct maar_config cfgs[3]; 32562306a36Sopenharmony_ci unsigned used; 32662306a36Sopenharmony_ci } recorded = { { { 0 } }, 0 }; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!cpu_has_maar) 32962306a36Sopenharmony_ci return; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Detect the number of MAARs */ 33262306a36Sopenharmony_ci write_c0_maari(~0); 33362306a36Sopenharmony_ci back_to_back_c0_hazard(); 33462306a36Sopenharmony_ci num_maars = read_c0_maari() + 1; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* MAARs should be in pairs */ 33762306a36Sopenharmony_ci WARN_ON(num_maars % 2); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Set MAARs using values we recorded already */ 34062306a36Sopenharmony_ci if (recorded.used) { 34162306a36Sopenharmony_ci used = maar_config(recorded.cfgs, recorded.used, num_maars / 2); 34262306a36Sopenharmony_ci BUG_ON(used != recorded.used); 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci /* Configure the required MAARs */ 34562306a36Sopenharmony_ci used = platform_maar_init(num_maars / 2); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Disable any further MAARs */ 34962306a36Sopenharmony_ci for (i = (used * 2); i < num_maars; i++) { 35062306a36Sopenharmony_ci write_c0_maari(i); 35162306a36Sopenharmony_ci back_to_back_c0_hazard(); 35262306a36Sopenharmony_ci write_c0_maar(0); 35362306a36Sopenharmony_ci back_to_back_c0_hazard(); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (recorded.used) 35762306a36Sopenharmony_ci return; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci pr_info("MAAR configuration:\n"); 36062306a36Sopenharmony_ci for (i = 0; i < num_maars; i += 2) { 36162306a36Sopenharmony_ci write_c0_maari(i); 36262306a36Sopenharmony_ci back_to_back_c0_hazard(); 36362306a36Sopenharmony_ci upper = read_c0_maar(); 36462306a36Sopenharmony_ci#ifdef CONFIG_XPA 36562306a36Sopenharmony_ci upper |= (phys_addr_t)readx_c0_maar() << MIPS_MAARX_ADDR_SHIFT; 36662306a36Sopenharmony_ci#endif 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci write_c0_maari(i + 1); 36962306a36Sopenharmony_ci back_to_back_c0_hazard(); 37062306a36Sopenharmony_ci lower = read_c0_maar(); 37162306a36Sopenharmony_ci#ifdef CONFIG_XPA 37262306a36Sopenharmony_ci lower |= (phys_addr_t)readx_c0_maar() << MIPS_MAARX_ADDR_SHIFT; 37362306a36Sopenharmony_ci#endif 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci attr = lower & upper; 37662306a36Sopenharmony_ci lower = (lower & MIPS_MAAR_ADDR) << 4; 37762306a36Sopenharmony_ci upper = ((upper & MIPS_MAAR_ADDR) << 4) | 0xffff; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci pr_info(" [%d]: ", i / 2); 38062306a36Sopenharmony_ci if ((attr & MIPS_MAAR_V) != MIPS_MAAR_V) { 38162306a36Sopenharmony_ci pr_cont("disabled\n"); 38262306a36Sopenharmony_ci continue; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci pr_cont("%pa-%pa", &lower, &upper); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (attr & MIPS_MAAR_S) 38862306a36Sopenharmony_ci pr_cont(" speculate"); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci pr_cont("\n"); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Record the setup for use on secondary CPUs */ 39362306a36Sopenharmony_ci if (used <= ARRAY_SIZE(recorded.cfgs)) { 39462306a36Sopenharmony_ci recorded.cfgs[recorded.used].lower = lower; 39562306a36Sopenharmony_ci recorded.cfgs[recorded.used].upper = upper; 39662306a36Sopenharmony_ci recorded.cfgs[recorded.used].attrs = attr; 39762306a36Sopenharmony_ci recorded.used++; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci#ifndef CONFIG_NUMA 40362306a36Sopenharmony_civoid __init paging_init(void) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci unsigned long max_zone_pfns[MAX_NR_ZONES]; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci pagetable_init(); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci#ifdef CONFIG_ZONE_DMA 41062306a36Sopenharmony_ci max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN; 41162306a36Sopenharmony_ci#endif 41262306a36Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32 41362306a36Sopenharmony_ci max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN; 41462306a36Sopenharmony_ci#endif 41562306a36Sopenharmony_ci max_zone_pfns[ZONE_NORMAL] = max_low_pfn; 41662306a36Sopenharmony_ci#ifdef CONFIG_HIGHMEM 41762306a36Sopenharmony_ci max_zone_pfns[ZONE_HIGHMEM] = highend_pfn; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) { 42062306a36Sopenharmony_ci printk(KERN_WARNING "This processor doesn't support highmem." 42162306a36Sopenharmony_ci " %ldk highmem ignored\n", 42262306a36Sopenharmony_ci (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10)); 42362306a36Sopenharmony_ci max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci max_mapnr = highend_pfn ? highend_pfn : max_low_pfn; 42762306a36Sopenharmony_ci#else 42862306a36Sopenharmony_ci max_mapnr = max_low_pfn; 42962306a36Sopenharmony_ci#endif 43062306a36Sopenharmony_ci high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci free_area_init(max_zone_pfns); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci#ifdef CONFIG_64BIT 43662306a36Sopenharmony_cistatic struct kcore_list kcore_kseg0; 43762306a36Sopenharmony_ci#endif 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic inline void __init mem_init_free_highmem(void) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci#ifdef CONFIG_HIGHMEM 44262306a36Sopenharmony_ci unsigned long tmp; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (cpu_has_dc_aliases) 44562306a36Sopenharmony_ci return; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { 44862306a36Sopenharmony_ci struct page *page = pfn_to_page(tmp); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (!memblock_is_memory(PFN_PHYS(tmp))) 45162306a36Sopenharmony_ci SetPageReserved(page); 45262306a36Sopenharmony_ci else 45362306a36Sopenharmony_ci free_highmem_page(page); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci#endif 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_civoid __init mem_init(void) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci /* 46162306a36Sopenharmony_ci * When PFN_PTE_SHIFT is greater than PAGE_SHIFT we won't have enough PTE 46262306a36Sopenharmony_ci * bits to hold a full 32b physical address on MIPS32 systems. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci BUILD_BUG_ON(IS_ENABLED(CONFIG_32BIT) && (PFN_PTE_SHIFT > PAGE_SHIFT)); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci maar_init(); 46762306a36Sopenharmony_ci memblock_free_all(); 46862306a36Sopenharmony_ci setup_zero_pages(); /* Setup zeroed pages. */ 46962306a36Sopenharmony_ci mem_init_free_highmem(); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci#ifdef CONFIG_64BIT 47262306a36Sopenharmony_ci if ((unsigned long) &_text > (unsigned long) CKSEG0) 47362306a36Sopenharmony_ci /* The -4 is a hack so that user tools don't have to handle 47462306a36Sopenharmony_ci the overflow. */ 47562306a36Sopenharmony_ci kclist_add(&kcore_kseg0, (void *) CKSEG0, 47662306a36Sopenharmony_ci 0x80000000 - 4, KCORE_TEXT); 47762306a36Sopenharmony_ci#endif 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci#endif /* !CONFIG_NUMA */ 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_civoid free_init_pages(const char *what, unsigned long begin, unsigned long end) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci unsigned long pfn; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci for (pfn = PFN_UP(begin); pfn < PFN_DOWN(end); pfn++) { 48662306a36Sopenharmony_ci struct page *page = pfn_to_page(pfn); 48762306a36Sopenharmony_ci void *addr = phys_to_virt(PFN_PHYS(pfn)); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci memset(addr, POISON_FREE_INITMEM, PAGE_SIZE); 49062306a36Sopenharmony_ci free_reserved_page(page); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_civoid (*free_init_pages_eva)(void *begin, void *end) = NULL; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_civoid __weak __init prom_free_prom_memory(void) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci /* nothing to do */ 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_civoid __ref free_initmem(void) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci prom_free_prom_memory(); 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Let the platform define a specific function to free the 50762306a36Sopenharmony_ci * init section since EVA may have used any possible mapping 50862306a36Sopenharmony_ci * between virtual and physical addresses. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci if (free_init_pages_eva) 51162306a36Sopenharmony_ci free_init_pages_eva((void *)&__init_begin, (void *)&__init_end); 51262306a36Sopenharmony_ci else 51362306a36Sopenharmony_ci free_initmem_default(POISON_FREE_INITMEM); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA 51762306a36Sopenharmony_ciunsigned long __per_cpu_offset[NR_CPUS] __read_mostly; 51862306a36Sopenharmony_ciEXPORT_SYMBOL(__per_cpu_offset); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int __init pcpu_cpu_distance(unsigned int from, unsigned int to) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci return node_distance(cpu_to_node(from), cpu_to_node(to)); 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int __init pcpu_cpu_to_node(int cpu) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci return cpu_to_node(cpu); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_civoid __init setup_per_cpu_areas(void) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci unsigned long delta; 53362306a36Sopenharmony_ci unsigned int cpu; 53462306a36Sopenharmony_ci int rc; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * Always reserve area for module percpu variables. That's 53862306a36Sopenharmony_ci * what the legacy allocator did. 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, 54162306a36Sopenharmony_ci PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, 54262306a36Sopenharmony_ci pcpu_cpu_distance, 54362306a36Sopenharmony_ci pcpu_cpu_to_node); 54462306a36Sopenharmony_ci if (rc < 0) 54562306a36Sopenharmony_ci panic("Failed to initialize percpu areas."); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; 54862306a36Sopenharmony_ci for_each_possible_cpu(cpu) 54962306a36Sopenharmony_ci __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci#endif 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci#ifndef CONFIG_MIPS_PGD_C0_CONTEXT 55462306a36Sopenharmony_ciunsigned long pgd_current[NR_CPUS]; 55562306a36Sopenharmony_ci#endif 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/* 55862306a36Sopenharmony_ci * Align swapper_pg_dir in to 64K, allows its address to be loaded 55962306a36Sopenharmony_ci * with a single LUI instruction in the TLB handlers. If we used 56062306a36Sopenharmony_ci * __aligned(64K), its size would get rounded up to the alignment 56162306a36Sopenharmony_ci * size, and waste space. So we place it in its own section and align 56262306a36Sopenharmony_ci * it in the linker script. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_cipgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir"); 56562306a36Sopenharmony_ci#ifndef __PAGETABLE_PUD_FOLDED 56662306a36Sopenharmony_cipud_t invalid_pud_table[PTRS_PER_PUD] __page_aligned_bss; 56762306a36Sopenharmony_ci#endif 56862306a36Sopenharmony_ci#ifndef __PAGETABLE_PMD_FOLDED 56962306a36Sopenharmony_cipmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss; 57062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(invalid_pmd_table); 57162306a36Sopenharmony_ci#endif 57262306a36Sopenharmony_cipte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss; 57362306a36Sopenharmony_ciEXPORT_SYMBOL(invalid_pte_table); 574