pseries_lpar.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 855 行 · 第 1/2 页
C
855 行
/* * 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/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>#include <asm/tlbflush.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_ANDCOND (1UL<<(63-33))#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);}static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, unsigned long uaddr, int direction ){ u64 setTceRc; union Tce tce; PPCDBG(PPCDBG_TCE, "build_tce: uaddr = 0x%lx\n", uaddr); PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx, tbl = 0x%lx, index=%lx\n", tcenum, tbl, tbl->index); tce.wholeTce = 0; tce.tceBits.rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT; tce.tceBits.readWrite = 1; if ( direction != PCI_DMA_TODEVICE ) tce.tceBits.pciWrite = 1; setTceRc = plpar_tce_put((u64)tbl->index, (u64)tcenum << 12, tce.wholeTce ); /* Make sure the update is visible to hardware. * ToDo: sync after setting *all* the tce's. */ __asm__ __volatile__ ("sync" : : : "memory"); if(setTceRc) { PPCDBG(PPCDBG_TCE, "setTce failed. rc=%ld\n", setTceRc); PPCDBG(PPCDBG_TCE, "\tindex = 0x%lx\n", (u64)tbl->index); PPCDBG(PPCDBG_TCE, "\ttcenum = 0x%lx\n", (u64)tcenum); PPCDBG(PPCDBG_TCE, "\ttce val = 0x%lx\n", tce.wholeTce ); }}static inline void free_tce_range(struct TceTable *tbl, long tcenum, unsigned order ){ unsigned long flags; /* Lock the tce allocation bitmap */ spin_lock_irqsave( &(tbl->lock), flags ); /* Do the actual work */ free_tce_range_nolock( tbl, tcenum, order ); /* Unlock the tce allocation bitmap */ spin_unlock_irqrestore( &(tbl->lock), flags );}static void tce_free_pSeriesLP(struct TceTable *tbl, dma_addr_t dma_addr, unsigned order, unsigned numPages){ u64 setTceRc; long tcenum, freeTce, maxTcenum; unsigned i; union Tce tce; maxTcenum = (tbl->size * (PAGE_SIZE / sizeof(union Tce))) - 1; tcenum = dma_addr >> PAGE_SHIFT; freeTce = tcenum - tbl->startOffset; if ( freeTce > maxTcenum ) { printk("free_tces: tcenum > maxTcenum\n"); printk("\ttcenum = 0x%lx\n", tcenum); printk("\tfreeTce = 0x%lx\n", freeTce); printk("\tmaxTcenum = 0x%lx\n", maxTcenum); printk("\tTCE Table = 0x%lx\n", (u64)tbl); printk("\tbus# = 0x%lx\n", (u64)tbl->busNumber ); printk("\tsize = 0x%lx\n", (u64)tbl->size); printk("\tstartOff = 0x%lx\n", (u64)tbl->startOffset ); printk("\tindex = 0x%lx\n", (u64)tbl->index); return; } for (i=0; i<numPages; ++i) { tce.wholeTce = 0; setTceRc = plpar_tce_put((u64)tbl->index, (u64)tcenum << 12, /* note: not freeTce */ tce.wholeTce ); if ( setTceRc ) { printk("tce_free: setTce failed\n"); printk("\trc = %ld\n", setTceRc); printk("\tindex = 0x%lx\n", (u64)tbl->index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); printk("\tfreeTce = 0x%lx\n", (u64)freeTce); printk("\ttce val = 0x%lx\n", tce.wholeTce ); } ++tcenum; } /* Make sure the update is visible to hardware. */ __asm__ __volatile__ ("sync" : : : "memory"); free_tce_range( tbl, freeTce, order );}/* PowerPC Interrupts for lpar. *//* NOTE: this typedef is duplicated (for now) from xics.c! */typedef struct { int (*xirr_info_get)(int cpu); void (*xirr_info_set)(int cpu, int val); void (*cppr_info)(int cpu, u8 val); void (*qirr_info)(int cpu, u8 val);} xics_ops;static int pSeriesLP_xirr_info_get(int n_cpu){ unsigned long lpar_rc; unsigned long return_value; lpar_rc = plpar_xirr(&return_value); if (lpar_rc != H_Success) { panic(" bad return code xirr - rc = %lx \n", lpar_rc); } return ((int)(return_value));}static void pSeriesLP_xirr_info_set(int n_cpu, int value){ unsigned long lpar_rc; unsigned long val64 = value & 0xffffffff; lpar_rc = plpar_eoi(val64); if (lpar_rc != H_Success) { panic(" bad return code EOI - rc = %ld, value=%lx \n", lpar_rc, val64); }}static void pSeriesLP_cppr_info(int n_cpu, u8 value){ unsigned long lpar_rc; lpar_rc = plpar_cppr(value); if (lpar_rc != H_Success) { panic(" bad return code cppr - rc = %lx \n", lpar_rc); }}static void pSeriesLP_qirr_info(int n_cpu , u8 value){ unsigned long lpar_rc; lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu),value); if (lpar_rc != H_Success) { panic(" bad return code qirr -ipi - rc = %lx \n", lpar_rc); }}xics_ops pSeriesLP_ops = { pSeriesLP_xirr_info_get, pSeriesLP_xirr_info_set, pSeriesLP_cppr_info, pSeriesLP_qirr_info};/* end TAI-LPAR */int vtermno; /* virtual terminal# for udbg */static void udbg_putcLP(unsigned char c){ char buf[16]; unsigned long rc; if (c == '\n') udbg_putcLP('\r'); buf[0] = c; do { rc = plpar_put_term_char(vtermno, 1, buf); } while(rc == H_Busy);}/* Buffered chars getc */static long inbuflen;static long inbuf[2]; /* must be 2 longs */static int udbg_getc_pollLP(void){ /* The interface is tricky because it may return up to 16 chars. * We save them statically for future calls to udbg_getc(). */ char ch, *buf = (char *)inbuf; int i; long rc; if (inbuflen == 0) { /* get some more chars. */ inbuflen = 0; rc = plpar_get_term_char(vtermno, &inbuflen, buf); if (inbuflen == 0 && rc == H_Success) return -1; } ch = buf[0]; for (i = 1; i < inbuflen; i++) /* shuffle them down. */ buf[i-1] = buf[i]; inbuflen--; return ch;}static unsigned char udbg_getcLP(void){ int ch; for (;;) { ch = udbg_getc_pollLP(); if (ch == -1) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?