📄 hash_utils_64.c
字号:
/* * PowerPC64 port by Mike Corrigan and Dave Engebretsen * {mikejc|engebret}@us.ibm.com * * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> * * SMP scalability work: * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM * * Module name: htab.c * * Description: * PowerPC Hashed Page Table functions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#undef DEBUG#undef DEBUG_LOW#include <linux/spinlock.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/sysctl.h>#include <linux/ctype.h>#include <linux/cache.h>#include <linux/init.h>#include <linux/signal.h>#include <asm/processor.h>#include <asm/pgtable.h>#include <asm/mmu.h>#include <asm/mmu_context.h>#include <asm/page.h>#include <asm/types.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/machdep.h>#include <asm/lmb.h>#include <asm/abs_addr.h>#include <asm/tlbflush.h>#include <asm/io.h>#include <asm/eeh.h>#include <asm/tlb.h>#include <asm/cacheflush.h>#include <asm/cputable.h>#include <asm/sections.h>#include <asm/spu.h>#include <asm/udbg.h>#ifdef DEBUG#define DBG(fmt...) udbg_printf(fmt)#else#define DBG(fmt...)#endif#ifdef DEBUG_LOW#define DBG_LOW(fmt...) udbg_printf(fmt)#else#define DBG_LOW(fmt...)#endif#define KB (1024)#define MB (1024*KB)/* * Note: pte --> Linux PTE * HPTE --> PowerPC Hashed Page Table Entry * * Execution context: * htab_initialize is called with the MMU off (of course), but * the kernel has been copied down to zero so it can directly * reference global data. At this point it is very difficult * to print debug info. * */#ifdef CONFIG_U3_DARTextern unsigned long dart_tablebase;#endif /* CONFIG_U3_DART */static unsigned long _SDR1;struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];struct hash_pte *htab_address;unsigned long htab_size_bytes;unsigned long htab_hash_mask;int mmu_linear_psize = MMU_PAGE_4K;int mmu_virtual_psize = MMU_PAGE_4K;int mmu_vmalloc_psize = MMU_PAGE_4K;int mmu_io_psize = MMU_PAGE_4K;int mmu_kernel_ssize = MMU_SEGSIZE_256M;int mmu_highuser_ssize = MMU_SEGSIZE_256M;#ifdef CONFIG_HUGETLB_PAGEint mmu_huge_psize = MMU_PAGE_16M;unsigned int HPAGE_SHIFT;#endif#ifdef CONFIG_PPC_64K_PAGESint mmu_ci_restrictions;#endif#ifdef CONFIG_DEBUG_PAGEALLOCstatic u8 *linear_map_hash_slots;static unsigned long linear_map_hash_count;static DEFINE_SPINLOCK(linear_map_hash_lock);#endif /* CONFIG_DEBUG_PAGEALLOC *//* There are definitions of page sizes arrays to be used when none * is provided by the firmware. *//* Pre-POWER4 CPUs (4k pages only) */struct mmu_psize_def mmu_psize_defaults_old[] = { [MMU_PAGE_4K] = { .shift = 12, .sllp = 0, .penc = 0, .avpnm = 0, .tlbiel = 0, },};/* POWER4, GPUL, POWER5 * * Support for 16Mb large pages */struct mmu_psize_def mmu_psize_defaults_gp[] = { [MMU_PAGE_4K] = { .shift = 12, .sllp = 0, .penc = 0, .avpnm = 0, .tlbiel = 1, }, [MMU_PAGE_16M] = { .shift = 24, .sllp = SLB_VSID_L, .penc = 0, .avpnm = 0x1UL, .tlbiel = 0, },};int htab_bolt_mapping(unsigned long vstart, unsigned long vend, unsigned long pstart, unsigned long mode, int psize, int ssize){ unsigned long vaddr, paddr; unsigned int step, shift; unsigned long tmp_mode; int ret = 0; shift = mmu_psize_defs[psize].shift; step = 1 << shift; for (vaddr = vstart, paddr = pstart; vaddr < vend; vaddr += step, paddr += step) { unsigned long hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr, ssize); unsigned long va = hpt_va(vaddr, vsid, ssize); tmp_mode = mode; /* Make non-kernel text non-executable */ if (!in_kernel_text(vaddr)) tmp_mode = mode | HPTE_R_N; hash = hpt_hash(va, shift, ssize); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); DBG("htab_bolt_mapping: calling %p\n", ppc_md.hpte_insert); BUG_ON(!ppc_md.hpte_insert); ret = ppc_md.hpte_insert(hpteg, va, paddr, tmp_mode, HPTE_V_BOLTED, psize, ssize); if (ret < 0) break;#ifdef CONFIG_DEBUG_PAGEALLOC if ((paddr >> PAGE_SHIFT) < linear_map_hash_count) linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80;#endif /* CONFIG_DEBUG_PAGEALLOC */ } return ret < 0 ? ret : 0;}static int __init htab_dt_scan_seg_sizes(unsigned long node, const char *uname, int depth, void *data){ char *type = of_get_flat_dt_prop(node, "device_type", NULL); u32 *prop; unsigned long size = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; prop = (u32 *)of_get_flat_dt_prop(node, "ibm,processor-segment-sizes", &size); if (prop == NULL) return 0; for (; size >= 4; size -= 4, ++prop) { if (prop[0] == 40) { DBG("1T segment support detected\n"); cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT; return 1; } } cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B; return 0;}static void __init htab_init_seg_sizes(void){ of_scan_flat_dt(htab_dt_scan_seg_sizes, NULL);}static int __init htab_dt_scan_page_sizes(unsigned long node, const char *uname, int depth, void *data){ char *type = of_get_flat_dt_prop(node, "device_type", NULL); u32 *prop; unsigned long size = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; prop = (u32 *)of_get_flat_dt_prop(node, "ibm,segment-page-sizes", &size); if (prop != NULL) { DBG("Page sizes from device-tree:\n"); size /= 4; cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE); while(size > 0) { unsigned int shift = prop[0]; unsigned int slbenc = prop[1]; unsigned int lpnum = prop[2]; unsigned int lpenc = 0; struct mmu_psize_def *def; int idx = -1; size -= 3; prop += 3; while(size > 0 && lpnum) { if (prop[0] == shift) lpenc = prop[1]; prop += 2; size -= 2; lpnum--; } switch(shift) { case 0xc: idx = MMU_PAGE_4K; break; case 0x10: idx = MMU_PAGE_64K; break; case 0x14: idx = MMU_PAGE_1M; break; case 0x18: idx = MMU_PAGE_16M; cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE; break; case 0x22: idx = MMU_PAGE_16G; break; } if (idx < 0) continue; def = &mmu_psize_defs[idx]; def->shift = shift; if (shift <= 23) def->avpnm = 0; else def->avpnm = (1 << (shift - 23)) - 1; def->sllp = slbenc; def->penc = lpenc; /* We don't know for sure what's up with tlbiel, so * for now we only set it for 4K and 64K pages */ if (idx == MMU_PAGE_4K || idx == MMU_PAGE_64K) def->tlbiel = 1; else def->tlbiel = 0; DBG(" %d: shift=%02x, sllp=%04x, avpnm=%08x, " "tlbiel=%d, penc=%d\n", idx, shift, def->sllp, def->avpnm, def->tlbiel, def->penc); } return 1; } return 0;}static void __init htab_init_page_sizes(void){ int rc; /* Default to 4K pages only */ memcpy(mmu_psize_defs, mmu_psize_defaults_old, sizeof(mmu_psize_defaults_old)); /* * Try to find the available page sizes in the device-tree */ rc = of_scan_flat_dt(htab_dt_scan_page_sizes, NULL); if (rc != 0) /* Found */ goto found; /* * Not in the device-tree, let's fallback on known size * list for 16M capable GP & GR */ if (cpu_has_feature(CPU_FTR_16M_PAGE)) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found:#ifndef CONFIG_DEBUG_PAGEALLOC /* * Pick a size for the linear mapping. Currently, we only support * 16M, 1M and 4K which is the default */ if (mmu_psize_defs[MMU_PAGE_16M].shift) mmu_linear_psize = MMU_PAGE_16M; else if (mmu_psize_defs[MMU_PAGE_1M].shift) mmu_linear_psize = MMU_PAGE_1M;#endif /* CONFIG_DEBUG_PAGEALLOC */#ifdef CONFIG_PPC_64K_PAGES /* * Pick a size for the ordinary pages. Default is 4K, we support * 64K for user mappings and vmalloc if supported by the processor. * We only use 64k for ioremap if the processor * (and firmware) support cache-inhibited large pages. * If not, we use 4k and set mmu_ci_restrictions so that * hash_page knows to switch processes that use cache-inhibited * mappings to 4k pages. */ if (mmu_psize_defs[MMU_PAGE_64K].shift) { mmu_virtual_psize = MMU_PAGE_64K; mmu_vmalloc_psize = MMU_PAGE_64K; if (mmu_linear_psize == MMU_PAGE_4K) mmu_linear_psize = MMU_PAGE_64K; if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) mmu_io_psize = MMU_PAGE_64K; else mmu_ci_restrictions = 1; }#endif /* CONFIG_PPC_64K_PAGES */ printk(KERN_DEBUG "Page orders: linear mapping = %d, " "virtual = %d, io = %d\n", mmu_psize_defs[mmu_linear_psize].shift, mmu_psize_defs[mmu_virtual_psize].shift, mmu_psize_defs[mmu_io_psize].shift);#ifdef CONFIG_HUGETLB_PAGE /* Init large page size. Currently, we pick 16M or 1M depending * on what is available */ if (mmu_psize_defs[MMU_PAGE_16M].shift) mmu_huge_psize = MMU_PAGE_16M; /* With 4k/4level pagetables, we can't (for now) cope with a * huge page size < PMD_SIZE */ else if (mmu_psize_defs[MMU_PAGE_1M].shift) mmu_huge_psize = MMU_PAGE_1M; /* Calculate HPAGE_SHIFT and sanity check it */ if (mmu_psize_defs[mmu_huge_psize].shift > MIN_HUGEPTE_SHIFT && mmu_psize_defs[mmu_huge_psize].shift < SID_SHIFT) HPAGE_SHIFT = mmu_psize_defs[mmu_huge_psize].shift; else HPAGE_SHIFT = 0; /* No huge pages dude ! */#endif /* CONFIG_HUGETLB_PAGE */}static int __init htab_dt_scan_pftsize(unsigned long node, const char *uname, int depth, void *data){ char *type = of_get_flat_dt_prop(node, "device_type", NULL); u32 *prop; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; prop = (u32 *)of_get_flat_dt_prop(node, "ibm,pft-size", NULL); if (prop != NULL) { /* pft_size[0] is the NUMA CEC cookie */ ppc64_pft_size = prop[1]; return 1; } return 0;}static unsigned long __init htab_get_table_size(void){ unsigned long mem_size, rnd_mem_size, pteg_count; /* If hash size isn't already provided by the platform, we try to * retrieve it from the device-tree. If it's not there neither, we * calculate it now based on the total RAM size */ if (ppc64_pft_size == 0) of_scan_flat_dt(htab_dt_scan_pftsize, NULL); if (ppc64_pft_size) return 1UL << ppc64_pft_size; /* round mem_size up to next power of 2 */ mem_size = lmb_phys_mem_size(); rnd_mem_size = 1UL << __ilog2(mem_size); if (rnd_mem_size < mem_size) rnd_mem_size <<= 1; /* # pages / 2 */ pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11); return pteg_count << 7;}#ifdef CONFIG_MEMORY_HOTPLUGvoid create_section_mapping(unsigned long start, unsigned long end){ BUG_ON(htab_bolt_mapping(start, end, __pa(start), _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX, mmu_linear_psize, mmu_kernel_ssize));}#endif /* CONFIG_MEMORY_HOTPLUG */static inline void make_bl(unsigned int *insn_addr, void *func){ unsigned long funcp = *((unsigned long *)func); int offset = funcp - (unsigned long)insn_addr; *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc)); flush_icache_range((unsigned long)insn_addr, 4+ (unsigned long)insn_addr);}static void __init htab_finish_init(void){ extern unsigned int *htab_call_hpte_insert1; extern unsigned int *htab_call_hpte_insert2; extern unsigned int *htab_call_hpte_remove; extern unsigned int *htab_call_hpte_updatepp;#ifdef CONFIG_PPC_HAS_HASH_64K extern unsigned int *ht64_call_hpte_insert1; extern unsigned int *ht64_call_hpte_insert2; extern unsigned int *ht64_call_hpte_remove; extern unsigned int *ht64_call_hpte_updatepp; make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert); make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert); make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove); make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp);#endif /* CONFIG_PPC_HAS_HASH_64K */ make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert); make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert); make_bl(htab_call_hpte_remove, ppc_md.hpte_remove); make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);}void __init htab_initialize(void){ unsigned long table; unsigned long pteg_count; unsigned long mode_rw; unsigned long base = 0, size = 0; int i; extern unsigned long tce_alloc_start, tce_alloc_end; DBG(" -> htab_initialize()\n"); /* Initialize segment sizes */ htab_init_seg_sizes(); /* Initialize page sizes */ htab_init_page_sizes(); if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) { mmu_kernel_ssize = MMU_SEGSIZE_1T; mmu_highuser_ssize = MMU_SEGSIZE_1T; printk(KERN_INFO "Using 1TB segments\n"); } /* * Calculate the required size of the htab. We want the number of * PTEGs to equal one half the number of real pages. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -