📄 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/config.h>#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/abs_addr.h>#include <asm/sections.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];hpte_t *htab_address;unsigned long htab_hash_mask;int mmu_linear_psize = MMU_PAGE_4K;int mmu_virtual_psize = MMU_PAGE_4K;#ifdef CONFIG_HUGETLB_PAGEint mmu_huge_psize = MMU_PAGE_16M;unsigned int HPAGE_SHIFT;#endif/* 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){ 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 vpn, hash, hpteg; unsigned long vsid = get_kernel_vsid(vaddr); unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff); vpn = va >> shift; 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); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); /* The crap below can be cleaned once ppd_md.probe() can * set up the hash callbacks, thus we can just used the * normal insert callback here. */#ifdef CONFIG_PPC_ISERIES if (_machine == PLATFORM_ISERIES_LPAR) ret = iSeries_hpte_insert(hpteg, va, virt_to_abs(paddr), tmp_mode, HPTE_V_BOLTED, psize); else#endif#ifdef CONFIG_PPC_PSERIES if (_machine & PLATFORM_LPAR) ret = pSeries_lpar_hpte_insert(hpteg, va, virt_to_abs(paddr), tmp_mode, HPTE_V_BOLTED, psize); else#endif#ifdef CONFIG_PPC_MULTIPLATFORM ret = native_hpte_insert(hpteg, va, virt_to_abs(paddr), tmp_mode, HPTE_V_BOLTED, psize);#endif if (ret < 0) break; } return ret < 0 ? ret : 0;}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 ((_machine != PLATFORM_ISERIES_LPAR) && cpu_has_feature(CPU_FTR_16M_PAGE)) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found: /* * 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; /* * Pick a size for the ordinary pages. Default is 4K, we support * 64K if cache inhibited large pages are supported by the * processor */#ifdef CONFIG_PPC_64K_PAGES if (mmu_psize_defs[MMU_PAGE_64K].shift && cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) mmu_virtual_psize = MMU_PAGE_64K;#endif printk(KERN_INFO "Page orders: linear mapping = %d, others = %d\n", mmu_psize_defs[mmu_linear_psize].shift, mmu_psize_defs[mmu_virtual_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 * retreive 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -