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

📄 pseries_lpar.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * pSeries_lpar.c * Copyright (C) 2001 Todd Inglett, IBM Corporation * * pSeries LPAR support. *  * 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 <linux/config.h>#include <linux/kernel.h>#include <asm/processor.h>#include <asm/semaphore.h>#include <asm/mmu.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/machdep.h>#include <asm/abs_addr.h>#include <asm/mmu_context.h>#include <asm/ppcdebug.h>#include <asm/pci_dma.h>#include <linux/pci.h>#include <asm/naca.h>/* Status return values */#define H_Success	0#define H_Busy		1	/* Hardware busy -- retry later */#define H_Hardware	-1	/* Hardware error */#define H_Function	-2	/* Function not supported */#define H_Privilege	-3	/* Caller not privileged */#define H_Parameter	-4	/* Parameter invalid, out-of-range or conflicting */#define H_Bad_Mode	-5	/* Illegal msr value */#define H_PTEG_Full	-6	/* PTEG is full */#define H_Not_Found	-7	/* PTE was not found" */#define H_Reserved_DABR	-8	/* DABR address is reserved by the hypervisor on this processor" *//* Flags */#define H_LARGE_PAGE		(1UL<<(63-16))#define H_EXACT		    (1UL<<(63-24))	/* Use exact PTE or return H_PTEG_FULL */#define H_R_XLATE		(1UL<<(63-25))	/* include a valid logical page num in the pte if the valid bit is set */#define H_READ_4		(1UL<<(63-26))	/* Return 4 PTEs */#define H_AVPN			(1UL<<(63-32))	/* An avpn is provided as a sanity test */#define H_ICACHE_INVALIDATE	(1UL<<(63-40))	/* icbi, etc.  (ignored for IO pages) */#define H_ICACHE_SYNCHRONIZE	(1UL<<(63-41))	/* dcbst, icbi, etc (ignored for IO pages */#define H_ZERO_PAGE		(1UL<<(63-48))	/* zero the page before mapping (ignored for IO pages) */#define H_COPY_PAGE		(1UL<<(63-49))#define H_N			(1UL<<(63-61))#define H_PP1			(1UL<<(63-62))#define H_PP2			(1UL<<(63-63))/* pSeries hypervisor opcodes */#define H_REMOVE		0x04#define H_ENTER			0x08#define H_READ			0x0c#define H_CLEAR_MOD		0x10#define H_CLEAR_REF		0x14#define H_PROTECT		0x18#define H_GET_TCE		0x1c#define H_PUT_TCE		0x20#define H_SET_SPRG0		0x24#define H_SET_DABR		0x28#define H_PAGE_INIT		0x2c#define H_SET_ASR		0x30#define H_ASR_ON		0x34#define H_ASR_OFF		0x38#define H_LOGICAL_CI_LOAD	0x3c#define H_LOGICAL_CI_STORE	0x40#define H_LOGICAL_CACHE_LOAD	0x44#define H_LOGICAL_CACHE_STORE	0x48#define H_LOGICAL_ICBI		0x4c#define H_LOGICAL_DCBF		0x50#define H_GET_TERM_CHAR		0x54#define H_PUT_TERM_CHAR		0x58#define H_REAL_TO_LOGICAL	0x5c#define H_HYPERVISOR_DATA	0x60#define H_EOI			0x64#define H_CPPR			0x68#define H_IPI			0x6c#define H_IPOLL			0x70#define H_XIRR			0x74#define HSC			".long 0x44000022\n"#define H_ENTER_r3		"li	3, 0x08\n"/* plpar_hcall() -- Generic call interface using above opcodes * * The actual call interface is a hypervisor call instruction with * the opcode in R3 and input args in R4-R7. * Status is returned in R3 with variable output values in R4-R11. * Only H_PTE_READ with H_READ_4 uses R6-R11 so we ignore it for now * and return only two out args which MUST ALWAYS BE PROVIDED. */long plpar_hcall(unsigned long opcode,		 unsigned long arg1,		 unsigned long arg2,		 unsigned long arg3,		 unsigned long arg4,		 unsigned long *out1,		 unsigned long *out2,		 unsigned long *out3);/* Same as plpar_hcall but for those opcodes that return no values * other than status.  Slightly more efficient. */long plpar_hcall_norets(unsigned long opcode, ...);long plpar_pte_enter(unsigned long flags,		     unsigned long ptex,		     unsigned long new_pteh, unsigned long new_ptel,		     unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){	unsigned long dummy, ret;	ret = plpar_hcall(H_ENTER, flags, ptex, new_pteh, new_ptel,			   old_pteh_ret, old_ptel_ret, &dummy);	return(ret);}long plpar_pte_remove(unsigned long flags,		      unsigned long ptex,		      unsigned long avpn,		      unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){	unsigned long dummy;	return plpar_hcall(H_REMOVE, flags, ptex, avpn, 0,			   old_pteh_ret, old_ptel_ret, &dummy);}long plpar_pte_read(unsigned long flags,		    unsigned long ptex,		    unsigned long *old_pteh_ret, unsigned long *old_ptel_ret){	unsigned long dummy;	return plpar_hcall(H_READ, flags, ptex, 0, 0,			   old_pteh_ret, old_ptel_ret, &dummy);}long plpar_pte_protect(unsigned long flags,		       unsigned long ptex,		       unsigned long avpn){	return plpar_hcall_norets(H_PROTECT, flags, ptex);}long plpar_tce_get(unsigned long liobn,		   unsigned long ioba,		   unsigned long *tce_ret){	unsigned long dummy;	return plpar_hcall(H_GET_TCE, liobn, ioba, 0, 0,			   tce_ret, &dummy, &dummy);}long plpar_tce_put(unsigned long liobn,		   unsigned long ioba,		   unsigned long tceval){	return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);}long plpar_get_term_char(unsigned long termno,			 unsigned long *len_ret,			 char *buf_ret){	unsigned long *lbuf = (unsigned long *)buf_ret;  /* ToDo: alignment? */	return plpar_hcall(H_GET_TERM_CHAR, termno, 0, 0, 0,			   len_ret, lbuf+0, lbuf+1);}long plpar_put_term_char(unsigned long termno,			 unsigned long len,			 const char *buffer){	unsigned long dummy;	unsigned long *lbuf = (unsigned long *)buffer;  /* ToDo: alignment? */	return plpar_hcall(H_PUT_TERM_CHAR, termno, len,			   lbuf[0], lbuf[1], &dummy, &dummy, &dummy);}long plpar_eoi(unsigned long xirr){	return plpar_hcall_norets(H_EOI, xirr);}long plpar_cppr(unsigned long cppr){	return plpar_hcall_norets(H_CPPR, cppr);}long plpar_ipi(unsigned long servernum,	       unsigned long mfrr){	return plpar_hcall_norets(H_IPI, servernum, mfrr);}long plpar_xirr(unsigned long *xirr_ret){	unsigned long dummy;	return plpar_hcall(H_XIRR, 0, 0, 0, 0,			   xirr_ret, &dummy, &dummy);}long plpar_ipoll(unsigned long servernum, unsigned long* xirr_ret, unsigned long* mfrr_ret){	unsigned long dummy;	return plpar_hcall(H_IPOLL, servernum, 0, 0, 0,			   xirr_ret, mfrr_ret, &dummy);}/* * The following section contains code that ultimately should * be put in the relavent file (htab.c, xics.c, etc).  It has * been put here for the time being in order to ease maintainence * of the pSeries LPAR code until it can all be put into CVS. */static void hpte_invalidate_pSeriesLP(unsigned long slot){	HPTE old_pte;	unsigned long lpar_rc;	unsigned long flags = 0;				lpar_rc = plpar_pte_remove(flags,				   slot,				   0,				   &old_pte.dw0.dword0, 				   &old_pte.dw1.dword1);	if (lpar_rc != H_Success) BUG();}/* NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up.  So no transform is needed. * We can probably optimize here and assume the high bits of newpp are * already zero.  For now I am paranoid. */static void hpte_updatepp_pSeriesLP(long slot, unsigned long newpp, unsigned long va){	unsigned long lpar_rc;	unsigned long flags;	flags =   newpp & 3;	lpar_rc = plpar_pte_protect( flags,				     slot,				     0);	if (lpar_rc != H_Success) {		udbg_printf( " bad return code from pte protect rc = %lx \n", lpar_rc); 		for (;;);	}}static void hpte_updateboltedpp_pSeriesLP(unsigned long newpp, unsigned long ea){	unsigned long lpar_rc;	unsigned long vsid,va,vpn,flags;	long slot;	vsid = get_kernel_vsid( ea );	va = ( vsid << 28 ) | ( ea & 0x0fffffff );	vpn = va >> PAGE_SHIFT;	slot = ppc_md.hpte_find( vpn );	flags =   newpp & 3;	lpar_rc = plpar_pte_protect( flags,				     slot,				     0);	if (lpar_rc != H_Success) {		udbg_printf( " bad return code from pte bolted protect rc = %lx \n", lpar_rc); 		for (;;);	}}static unsigned long hpte_getword0_pSeriesLP(unsigned long slot){	unsigned long dword0;	unsigned long lpar_rc;	unsigned long dummy_word1;	unsigned long flags;	/* Read 1 pte at a time                        */	/* Do not need RPN to logical page translation */	/* No cross CEC PFT access                     */	flags = 0;		lpar_rc = plpar_pte_read(flags,				 slot,				 &dword0, &dummy_word1);	if (lpar_rc != H_Success) {		udbg_printf(" error on pte read in get_hpte0 rc = %lx \n", lpar_rc);		for (;;);	}	return(dword0);}static long hpte_selectslot_pSeriesLP(unsigned long vpn){	unsigned long primary_hash;	unsigned long hpteg_slot;	unsigned i, k;	unsigned long flags;	HPTE  pte_read;	unsigned long lpar_rc;	/* 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;	/* Read 1 pte at a time                        */	/* Do not need RPN to logical page translation */	/* No cross CEC PFT access                     */	flags = 0;	for (i=0; i<HPTES_PER_GROUP; ++i) {		/* read the hpte entry from the slot */		lpar_rc = plpar_pte_read(flags,					 hpteg_slot + i,					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);		if (lpar_rc != H_Success) {			udbg_printf(" read of hardware page table failed rc = %lx \n", lpar_rc); 			for (;;);		}		if ( pte_read.dw0.dw0.v == 0 ) {			/* If an available slot found, return it */			return hpteg_slot + i;		}	}	/* Search the secondary group for an available slot */	hpteg_slot = ( ~primary_hash & htab_data.htab_hash_mask ) * HPTES_PER_GROUP;	for (i=0; i<HPTES_PER_GROUP; ++i) {		/* read the hpte entry from the slot */		lpar_rc = plpar_pte_read(flags,					 hpteg_slot + i,					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);		if (lpar_rc != H_Success) {			udbg_printf(" read of hardware page table failed2 rc = %lx  \n", lpar_rc); 			for (;;);		}		if ( pte_read.dw0.dw0.v == 0 ) {			/* If an available slot found, return it */			return hpteg_slot + i;		}	}	/* No available entry found in secondary group */	/* Select an entry in the primary group to replace */	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;		lpar_rc = plpar_pte_read(flags,					 hpteg_slot + k,					 &pte_read.dw0.dword0, &pte_read.dw1.dword1);		if (lpar_rc != H_Success) {			udbg_printf( " pte read failed - rc = %lx", lpar_rc); 			for (;;);		}		if (  ! pte_read.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("select_hpte_slot - No non-bolted HPTE in group 0x%lx! \n", hpteg_slot/HPTES_PER_GROUP);	udbg_printf("No non-bolted HPTE in group %lx", (unsigned long)hpteg_slot/HPTES_PER_GROUP);	for (;;);	/* never executes - avoid compiler errors */	return 0;}static void hpte_create_valid_pSeriesLP(unsigned long slot, unsigned long vpn,					unsigned long prpn, unsigned hash, 					void *ptep, unsigned hpteflags, 					unsigned bolted){	/* Local copy of HPTE */	struct {		/* Local copy of first doubleword of HPTE */		union {			unsigned long d;			Hpte_dword0   h;		} dw0;		/* Local copy of second doubleword of HPTE */		union {			unsigned long     d;			Hpte_dword1       h;			Hpte_dword1_flags f;		} dw1;	} lhpte;		unsigned long avpn = vpn >> 11;	unsigned long arpn = physRpn_to_absRpn( prpn );	unsigned long lpar_rc;	unsigned long flags;	HPTE ret_hpte;

⌨️ 快捷键说明

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