⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htab.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  * * PowerPC64 port by Mike Corrigan and Dave Engebretsen *   {mikejc|engebret}@us.ibm.com * *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> *  *    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. */#include <linux/config.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/init.h>#include <asm/system.h>#include <asm/iSeries/LparData.h>#include <linux/spinlock.h>#include <asm/ppcdebug.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 <asm/uaccess.h>#include <asm/naca.h>#include <asm/system.h>#include <asm/pmc.h>#include <asm/machdep.h>#include <asm/lmb.h>#include <asm/eeh.h>/* For iSeries */#include <asm/iSeries/HvCallHpt.h>/* Note:  pte   --> Linux PTE *        HPTE  --> PowerPC Hashed Page Table Entry */HTAB htab_data = {NULL, 0, 0, 0, 0};int proc_dol2crvec(ctl_table *table, int write, struct file *filp,		   void *buffer, size_t *lenp);void htab_initialize(void);void make_pte_LPAR(HPTE *htab,	      unsigned long va, unsigned long pa, int mode,	      unsigned long hash_mask, int large);extern unsigned long reloc_offset(void);extern unsigned long get_kernel_vsid( unsigned long ea );extern void cacheable_memzero( void *, unsigned int );extern unsigned long _SDR1;extern unsigned long klimit;extern unsigned long _ASR;extern inline void make_ste(unsigned long stab,			    unsigned long esid, unsigned long vsid);extern char _stext[], _etext[], __start_naca[], __end_stab[];static spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))#define RELOC(x)	(*PTRRELOC(&(x)))extern unsigned long htab_size( unsigned long );unsigned long hpte_getword0_iSeries( unsigned long slot );#define KB (1024)#define MB (1024*KB)static inline voidcreate_pte_mapping(unsigned long start, unsigned long end,		   unsigned long mode, unsigned long mask, int large){	unsigned long addr, offset = reloc_offset();	HTAB *_htab_data = PTRRELOC(&htab_data);	HPTE  *htab  = (HPTE *)__v2a(_htab_data->htab);	unsigned int step;	if (large)		step = 16*MB;	else		step = 4*KB;	for (addr = start; addr < end; addr += step) {		unsigned long vsid = get_kernel_vsid(addr);		unsigned long va = (vsid << 28) | (addr & 0xfffffff);		make_pte(htab, va, (unsigned long)__v2a(addr), mode, mask,				large);	}}voidhtab_initialize(void){	unsigned long table, htab_size_bytes;	unsigned long pteg_count;	unsigned long mode_ro, mode_rw, mask;	unsigned long offset = reloc_offset();	struct naca_struct *_naca = RELOC(naca);	HTAB *_htab_data = PTRRELOC(&htab_data);	/*	 * Calculate the required size of the htab.  We want the number of	 * PTEGs to equal one half the number of real pages.	 */ 	htab_size_bytes = 1UL << _naca->pftSize;	pteg_count = htab_size_bytes >> 7;	/* For debug, make the HTAB 1/8 as big as it normally would be. */	ifppcdebug(PPCDBG_HTABSIZE) {		pteg_count >>= 3;		htab_size_bytes = pteg_count << 7;	}	_htab_data->htab_num_ptegs = pteg_count;	_htab_data->htab_hash_mask = pteg_count - 1;	if(_naca->platform == PLATFORM_PSERIES) {		/* Find storage for the HPT.  Must be contiguous in		 * the absolute address space.		 */		table = lmb_alloc(htab_size_bytes, htab_size_bytes);		if ( !table )			panic("ERROR, cannot find space for HPTE\n");		_htab_data->htab = (HPTE *)__a2v(table);		/* htab absolute addr + encoded htabsize */		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;		/* Initialize the HPT with no entries */		cacheable_memzero((void *)table, htab_size_bytes);	} else {		_htab_data->htab = NULL;		RELOC(_SDR1) = 0; 	}	mode_ro = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RXRX;	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;	mask = pteg_count-1;	/* Create PTE's for the kernel text and data sections plus	 * the HPT and HPTX arrays.  Make the assumption that	 * (addr & KERNELBASE) == 0 (ie they are disjoint).	 * We also assume that the va is <= 64 bits.	 */#if 0	create_pte_mapping((unsigned long)_stext,       (unsigned long)__start_naca,                 mode_ro, mask);	create_pte_mapping((unsigned long)__start_naca, (unsigned long)__end_stab,                   mode_rw, mask);	create_pte_mapping((unsigned long)__end_stab,   (unsigned long)_etext,                       mode_ro, mask);	create_pte_mapping((unsigned long)_etext,       RELOC(klimit),                               mode_rw, mask);	create_pte_mapping((unsigned long)__a2v(table), (unsigned long)__a2v(table+htab_size_bytes), mode_rw, mask);#else#ifndef CONFIG_PPC_ISERIES	if (__is_processor(PV_POWER4) && _naca->physicalMemorySize > 256*MB) {		create_pte_mapping((unsigned long)KERNELBASE, 				   KERNELBASE + 256*MB, mode_rw, mask, 0);		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 				   KERNELBASE + (_naca->physicalMemorySize), 				   mode_rw, mask, 1);		return;	}#endif	create_pte_mapping((unsigned long)KERNELBASE, 			   KERNELBASE+(_naca->physicalMemorySize), 			   mode_rw, mask, 0);#endif}#undef KB#undef MB/* * Create a pte.  Used during initialization only. * We assume the PTE will fit in the primary PTEG. */void make_pte(HPTE *htab,	      unsigned long va, unsigned long pa, int mode,	      unsigned long hash_mask, int large){	HPTE  *hptep;	unsigned long hash, i;	volatile unsigned long x = 1;	unsigned long vpn;#ifdef CONFIG_PPC_PSERIES	if(naca->platform == PLATFORM_PSERIES_LPAR) {		make_pte_LPAR(htab, va, pa, mode, hash_mask, large); 		return;	}#endif	if (large)		vpn = va >> 24;	else		vpn = va >> 12;	hash = hpt_hash(vpn, large);	hptep  = htab +  ((hash & hash_mask)*HPTES_PER_GROUP);	for (i = 0; i < 8; ++i, ++hptep) {		if ( hptep->dw0.dw0.v == 0 ) {		/* !valid */			hptep->dw1.dword1 = pa | mode;			hptep->dw0.dword0 = 0;			hptep->dw0.dw0.avpn = va >> 23;			hptep->dw0.dw0.bolted = 1;	/* bolted */			hptep->dw0.dw0.v = 1;		/* make valid */			return;		}	}	/* We should _never_ get here and too early to call xmon. */	for(;x;x|=1);}/* Functions to invalidate a HPTE */static void hpte_invalidate_iSeries( unsigned long slot ){	HvCallHpt_invalidateSetSwBitsGet( slot, 0, 0 );}static void hpte_invalidate_pSeries( unsigned long slot ){	/* Local copy of the first doubleword of the HPTE */	union {		unsigned long d;		Hpte_dword0   h;	} hpte_dw0;	/* Locate the HPTE */	HPTE  * hptep  = htab_data.htab  + slot;	/* Get the first doubleword of the HPTE */	hpte_dw0.d = hptep->dw0.dword0;	/* Invalidate the hpte */	hptep->dw0.dword0 = 0;	/* Invalidate the tlb   */	{		unsigned long vsid, group, pi, pi_high;		vsid = hpte_dw0.h.avpn >> 5;		group = slot >> 3;		if(hpte_dw0.h.h) {			group = ~group;		} 		pi = (vsid ^ group) & 0x7ff;		pi_high = (hpte_dw0.h.avpn & 0x1f) << 11;		pi |= pi_high;		_tlbie(pi << 12);	}}/* Select an available HPT slot for a new HPTE *   return slot index (if in primary group) *   return -slot index (if in secondary group)  */static long hpte_selectslot_iSeries( unsigned long vpn ){	HPTE hpte;	long ret_slot, orig_slot;	unsigned long primary_hash;	unsigned long hpteg_slot;	unsigned long slot;	unsigned i, k;	union {		unsigned long	d;		Hpte_dword0	h;	} hpte_dw0;	ret_slot = orig_slot = HvCallHpt_findValid( &hpte, vpn );	if ( hpte.dw0.dw0.v ) {		/* If valid ...what do we do now? */		udbg_printf( "hpte_selectslot_iSeries: vpn 0x%016lx already valid at slot 0x%016lx\n", vpn, ret_slot );		udbg_printf( "hpte_selectslot_iSeries: returned hpte 0x%016lx 0x%016lx\n", hpte.dw0.dword0, hpte.dw1.dword1 );		return (0x8000000000000000); 		/*			panic("select_hpte_slot found entry already valid\n"); */	}	if ( ret_slot == -1 ) {		/* -1 indicates no available slots */		/* No available entry found in secondary group */		PMC_SW_SYSTEM(htab_capacity_castouts);		primary_hash = hpt_hash(vpn, 0);		hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;		k = htab_data.next_round_robin++ & 0x7;		for ( i=0; i<HPTES_PER_GROUP; ++i ) {			if ( k == HPTES_PER_GROUP )				k = 0;			slot = hpteg_slot + k;			hpte_dw0.d = hpte_getword0_iSeries( slot );			if ( !hpte_dw0.h.bolted ) {				hpte_invalidate_iSeries( slot );				ret_slot = slot;			}			++k;		}	} else {		if ( ret_slot < 0 ) {			PMC_SW_SYSTEM(htab_primary_overflows);			ret_slot &= 0x7fffffffffffffff;			ret_slot = -ret_slot;		}	}	if ( ret_slot == -1 ) {		/* No non-bolted entry found in primary group - time to panic */        	udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);        	panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);	}	PPCDBG(PPCDBG_MM, "hpte_selectslot_iSeries: vpn=0x%016lx, orig_slot=0x%016lx, ret_slot=0x%016lx \n",	       vpn, orig_slot, ret_slot );		return ret_slot;}static long hpte_selectslot_pSeries(unsigned long vpn){	HPTE * hptep;	unsigned long primary_hash;	unsigned long hpteg_slot;	unsigned i, k;	/* Search the primary group for an available slot */	primary_hash = hpt_hash(vpn, 0);	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;	hptep = htab_data.htab + hpteg_slot;		for (i=0; i<HPTES_PER_GROUP; ++i) {		if ( hptep->dw0.dw0.v == 0 ) {			/* If an available slot found, return it */			return hpteg_slot + i;		}		hptep++;	}	/* No available entry found in primary group */	PMC_SW_SYSTEM(htab_primary_overflows);	/* Search the secondary group */	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;	hptep = htab_data.htab + hpteg_slot;	for (i=0; i<HPTES_PER_GROUP; ++i) {		if ( hptep->dw0.dw0.v == 0 ) {			/* If an available slot found, return it */			return -(hpteg_slot + i);		}		hptep++;	}	/* No available entry found in secondary group */	PMC_SW_SYSTEM(htab_capacity_castouts);	/* Select an entry in the primary group to replace */	hpteg_slot = ( primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;	hptep = htab_data.htab + hpteg_slot;	k = htab_data.next_round_robin++ & 0x7;	for (i=0; i<HPTES_PER_GROUP; ++i) {		if (k == HPTES_PER_GROUP)			k = 0;		if (!hptep[k].dw0.dw0.bolted) {			hpteg_slot += k;			/* Invalidate the current entry */			ppc_md.hpte_invalidate(hpteg_slot); 			return hpteg_slot;		}		++k;	}	/* No non-bolted entry found in primary group - time to panic */        udbg_printf("hpte_selectslot_pSeries - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);	/*      xmon(0); */        panic("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);	/* keep the compiler happy */	return 0;}unsigned long hpte_getword0_iSeries( unsigned long slot ){	unsigned long dword0;	HPTE hpte;	HvCallHpt_get( &hpte, slot );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -