iseries_hashtable.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 224 行
C
224 行
/* * * * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> IBM Corporation * updated by Dave Boutcher (boutcher@us.ibm.com) * * Module name: iSeries_hashtable.c * * Description: * Handles Hash Table faults for iSeries LPAR. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <asm/processor.h>#include <asm/pgtable.h>#include <linux/mm.h>#include <asm/mmu_context.h>#include <asm/page.h>#include <asm/types.h>#include <linux/spinlock.h>#include <asm/iSeries/HvCallHpt.h>#include <asm/iSeries/LparData.h>#include <asm/mmu_context.h>int iSeries_hpt_loaded;static spinlock_t mmu_hash_lock = SPIN_LOCK_UNLOCKED;extern unsigned long htab_reloads; // Defined in ppc/kernel/ppc_htab.cextern unsigned long htab_evicts;unsigned long htab_pp_update = 0;unsigned long flush_hash_page_count = 0;unsigned long Hash_mask; unsigned long flush_hash_range_count = 0;unsigned long flush_hash_range_hv_finds = 0;unsigned long flush_hash_range_hv_evicts = 0;extern int iSeries_max_kernel_hpt_slot;static unsigned next_slot = 4; // good enough starting valueextern void flush_hash_range( u64, u64, unsigned );static inline u32 computeHptePP( unsigned long pte ){ return ( ( pte & _PAGE_USER ) >> 1 ) | ( ( ( pte & _PAGE_USER ) >> 2 ) & ( (~pte & _PAGE_RW ) >> 10 ) );}static inline u32 computeHpteHash( unsigned long vsid, unsigned long pid ){ return ( vsid ^ pid ) & Hash_mask;}/* * Should be called with hash page lock */static void __create_hpte(unsigned long vsid, unsigned long va, unsigned long newpte){ PTE hpte; u64 vpn; u64 rtnIndex; u64 *hpte0Ptr, *hpte1Ptr; u32 newpp, gIndex; vsid = vsid & 0x7ffffff; vpn = ((u64)vsid << 16) | ((va >> 12) & 0xffff); hpte0Ptr = (u64 *)&hpte; hpte1Ptr = hpte0Ptr + 1; *hpte0Ptr = *hpte1Ptr = 0; rtnIndex = HvCallHpt_findValid( &hpte, vpn ); newpp = computeHptePP( newpte ); if ( hpte.v ) { /* A matching valid entry was found * Just update the pp bits */ ++htab_pp_update; HvCallHpt_setPp( rtnIndex, newpp ); } else { /* No matching entry was found Build new hpte */ hpte.vsid = vsid; hpte.api = (va >> 23) & 0x1f; hpte.v = 1; hpte.rpn = physRpn_to_absRpn(newpte>>12); hpte.r = 1; hpte.c = 1; hpte.m = 1; hpte.pp = newpp; if ( ( rtnIndex != ~0 ) && ( rtnIndex != 0x00000000ffffffff ) ) { /* Free entry was found */ if ( ( rtnIndex >> 63 ) || ( rtnIndex & 0x80000000 ) ) hpte.h = 1; HvCallHpt_addValidate( rtnIndex, hpte.h, &hpte ); } else { /* No free entry was found */ gIndex = computeHpteHash( vsid, vpn & 0xffff ); rtnIndex = gIndex*8 + next_slot; if ( ++next_slot > 7 ) next_slot = iSeries_max_kernel_hpt_slot+1; HvCallHpt_invalidateSetSwBitsGet( rtnIndex, 0, 1 ); HvCallHpt_addValidate( rtnIndex, 0, &hpte ); ++htab_evicts; } }} int iSeries_create_hpte( unsigned long access, unsigned long va ){ struct thread_struct *ts; pgd_t * pg; pmd_t * pm; pte_t * pt; u32 vsid; unsigned flags; vsid = mfsrin( va ) & 0x07ffffff; if ( va >= KERNELBASE ) pg = swapper_pg_dir; else { // Get the thread structure ts = (struct thread_struct *)mfspr(SPRG3); // Get the page directory pg = ts->pgdir; } pg = pg + pgd_index( va ); // offset into first level pm = pmd_offset( pg, va ); // offset into second level if ( pmd_none( *pm ) ) // if no third level return 1; // indicate failure pt = pte_offset( pm, va ); // offset into third level access |= _PAGE_PRESENT; // _PAGE_PRESENT also needed spin_lock( &mmu_hash_lock ); // check if pte is in the required state if ( ( access & ~(pte_val(*pt)) ) ) { spin_unlock( &mmu_hash_lock ); return 1; } /* pte allows the access we are making */ flags = _PAGE_ACCESSED | _PAGE_HASHPTE | _PAGE_COHERENT; if ( access & _PAGE_RW ) /* If write access */ flags |= _PAGE_RW; /* atomically update pte */ pte_update( pt, 0, flags ); __create_hpte(vsid, va, pte_val(*pt)); spin_unlock( &mmu_hash_lock ); return 0;}void add_hash_page(unsigned context, unsigned long va, pte_t *ptep){ spin_lock( &mmu_hash_lock ); pte_update(ptep,0,_PAGE_HASHPTE); __create_hpte(CTX_TO_VSID(context, va), va, pte_val(*ptep)); spin_unlock( &mmu_hash_lock );}int flush_hash_page(unsigned context, unsigned long va, pte_t *ptep){ int rc; PTE hpte; u64 vpn; unsigned long vsid; u64 rtnIndex; u64 *hpte0Ptr, *hpte1Ptr; vsid = CTX_TO_VSID(context, va); vpn = ((u64)vsid << 16) | ((va >> 12) & 0xffff); hpte0Ptr = (u64 *)&hpte; hpte1Ptr = hpte0Ptr + 1; *hpte0Ptr = *hpte1Ptr = 0; spin_lock( &mmu_hash_lock ); rtnIndex = HvCallHpt_findValid( &hpte, vpn ); if ( hpte.v ) { pte_update(ptep, _PAGE_HASHPTE, 0); HvCallHpt_invalidateSetSwBitsGet(rtnIndex, 0, 1 ); rc = 0; } else rc = 1; spin_unlock( &mmu_hash_lock ); return rc;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?