📄 pseries_lpar.c
字号:
/* Fill in the local HPTE with absolute rpn, avpn and flags */ lhpte.dw1.d = 0; lhpte.dw1.h.rpn = arpn; lhpte.dw1.f.flags = hpteflags; lhpte.dw0.d = 0; lhpte.dw0.h.avpn = avpn; lhpte.dw0.h.h = hash; lhpte.dw0.h.bolted = bolted; lhpte.dw0.h.v = 1; /* Now fill in the actual HPTE */ /* Set CEC cookie to 0 */ /* Large page = 0 */ /* Zero page = 0 */ /* I-cache Invalidate = 0 */ /* I-cache synchronize = 0 */ /* Exact = 1 - only modify exact entry */ flags = H_EXACT; if (hpteflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) lhpte.dw1.f.flags &= ~_PAGE_COHERENT;#if 1 __asm__ __volatile__ ( H_ENTER_r3 "mr 4, %1\n" "mr 5, %2\n" "mr 6, %3\n" "mr 7, %4\n" HSC "mr %0, 3\n" : "=r" (lpar_rc) : "r" (flags), "r" (slot), "r" (lhpte.dw0.d), "r" (lhpte.dw1.d) : "r3", "r4", "r5", "r6", "r7", "cc");#else lpar_rc = plpar_pte_enter(flags, slot, lhpte.dw0.d, lhpte.dw1.d, &ret_hpte.dw0.dword0, &ret_hpte.dw1.dword1);#endif if (lpar_rc != H_Success) { udbg_printf("error on pte enter lapar rc = %ld\n",lpar_rc); udbg_printf("ent: s=%lx, dw0=%lx, dw1=%lx\n", slot, lhpte.dw0.d, lhpte.dw1.d); /* xmon_backtrace("backtrace"); */ for (;;); }}static long hpte_find_pSeriesLP(unsigned long vpn){ union { unsigned long d; Hpte_dword0 h; } hpte_dw0; long slot; unsigned long hash; unsigned long i,j; hash = hpt_hash(vpn, 0); for ( j=0; j<2; ++j ) { slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP; for ( i=0; i<HPTES_PER_GROUP; ++i ) { hpte_dw0.d = hpte_getword0_pSeriesLP( slot ); if ( ( hpte_dw0.h.avpn == ( vpn >> 11 ) ) && ( hpte_dw0.h.v ) && ( hpte_dw0.h.h == j ) ) { /* HPTE matches */ if ( j ) slot = -slot; return slot; } ++slot; } hash = ~hash; } return -1;} /* * Create a pte - LPAR . Used during initialization only. * We assume the PTE will fit in the primary PTEG. */void make_pte_LPAR(HPTE *htab, unsigned long va, unsigned long pa, int mode, unsigned long hash_mask, int large){ HPTE local_hpte, ret_hpte; unsigned long hash, slot, flags,lpar_rc, vpn; if (large) vpn = va >> 24; else vpn = va >> 12; hash = hpt_hash(vpn, large); slot = ((hash & hash_mask)*HPTES_PER_GROUP); local_hpte.dw1.dword1 = pa | mode; local_hpte.dw0.dword0 = 0; local_hpte.dw0.dw0.avpn = va >> 23; local_hpte.dw0.dw0.bolted = 1; /* bolted */ if (large) local_hpte.dw0.dw0.l = 1; /* large page */ local_hpte.dw0.dw0.v = 1; /* Set CEC cookie to 0 */ /* Zero page = 0 */ /* I-cache Invalidate = 0 */ /* I-cache synchronize = 0 */ /* Exact = 0 - modify any entry in group */ flags = 0;#if 1 __asm__ __volatile__ ( H_ENTER_r3 "mr 4, %1\n" "mr 5, %2\n" "mr 6, %3\n" "mr 7, %4\n" HSC "mr %0, 3\n" : "=r" (lpar_rc) : "r" (flags), "r" (slot), "r" (local_hpte.dw0.dword0), "r" (local_hpte.dw1.dword1) : "r3", "r4", "r5", "r6", "r7", "cc");#else lpar_rc = plpar_pte_enter(flags, slot, local_hpte.dw0.dword0, local_hpte.dw1.dword1, &ret_hpte.dw0.dword0, &ret_hpte.dw1.dword1);#endif#if 0 /* NOTE: we explicitly do not check return status here because it is * "normal" for early boot code to map io regions for which a partition * has no access. However, we will die if we actually fault on these * "permission denied" pages. */ if (lpar_rc != H_Success) { /* pSeriesLP_init_early(); */ udbg_printf("flags=%lx, slot=%lx, dword0=%lx, dword1=%lx, rc=%d\n", flags, slot, local_hpte.dw0.dword0,local_hpte.dw1.dword1, lpar_rc); BUG(); }#endif}static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, unsigned long uaddr, int direction ){ u64 set_tce_rc; 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; set_tce_rc = plpar_tce_put((u64)tbl->index, (u64)tcenum << 12, tce.wholeTce ); if(set_tce_rc) { printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", set_tce_rc); printk("\tindex = 0x%lx\n", (u64)tbl->index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); printk("\ttce val = 0x%lx\n", tce.wholeTce ); }}static void tce_free_one_pSeriesLP(struct TceTable *tbl, long tcenum){ u64 set_tce_rc; union Tce tce; tce.wholeTce = 0; set_tce_rc = plpar_tce_put((u64)tbl->index, (u64)tcenum << 12, tce.wholeTce ); if ( set_tce_rc ) { printk("tce_free_one_pSeriesLP: plpar_tce_put failed\n"); printk("\trc = %ld\n", set_tce_rc); printk("\tindex = 0x%lx\n", (u64)tbl->index); printk("\ttcenum = 0x%lx\n", (u64)tcenum); printk("\ttce val = 0x%lx\n", tce.wholeTce ); }}/* 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) { udbg_printf("pSeriesLP_qirr_info - plpar_ipi failed!!!!!!!! \n"); 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 (rc != H_Success) inbuflen = 0; /* otherwise inbuflen is garbage */ } if (inbuflen <= 0 || inbuflen > 16) { /* Catch error case as well as other oddities (corruption) */ inbuflen = 0; 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) { /* This shouldn't be needed...but... */ volatile unsigned long delay; for (delay=0; delay < 2000000; delay++) ; } else { return ch; } }}/* This is called early in setup.c. * Use it to setup page table ppc_md stuff as well as udbg. */void pSeriesLP_init_early(void){ ppc_md.hpte_invalidate = hpte_invalidate_pSeriesLP; ppc_md.hpte_updatepp = hpte_updatepp_pSeriesLP; ppc_md.hpte_updateboltedpp = hpte_updateboltedpp_pSeriesLP; ppc_md.hpte_getword0 = hpte_getword0_pSeriesLP; ppc_md.hpte_selectslot = hpte_selectslot_pSeriesLP; ppc_md.hpte_create_valid = hpte_create_valid_pSeriesLP; ppc_md.hpte_find = hpte_find_pSeriesLP; ppc_md.tce_build = tce_build_pSeriesLP; ppc_md.tce_free_one = tce_free_one_pSeriesLP;#ifdef CONFIG_SMP smp_init_pSeries();#endif pSeries_pcibios_init_early(); /* The keyboard is not useful in the LPAR environment. * Leave all the interfaces NULL. */ if (naca->serialPortAddr) { void *comport = (void *)__ioremap(naca->serialPortAddr, 16, _PAGE_NO_CACHE); udbg_init_uart(comport); ppc_md.udbg_putc = udbg_putc; ppc_md.udbg_getc = udbg_getc; ppc_md.udbg_getc_poll = udbg_getc_poll; } else { /* lookup the first virtual terminal number in case we don't have a com port. * Zero is probably correct in case someone calls udbg before the init. * The property is a pair of numbers. The first is the starting termno (the * one we use) and the second is the number of terminals. */ u32 *termno; struct device_node *np = find_path_device("/rtas"); if (np) { termno = (u32 *)get_property(np, "ibm,termno", 0); if (termno) vtermno = termno[0]; } ppc_md.udbg_putc = udbg_putcLP; ppc_md.udbg_getc = udbg_getcLP; ppc_md.udbg_getc_poll = udbg_getc_pollLP; }}/* Code for hvc_console. Should move it back eventually. */int hvc_get_chars(int index, char *buf, int count){ unsigned long got; if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { /* * Work around a HV bug where it gives us a null * after every \r. -- paulus */ if (got > 0) { int i; for (i = 1; i < got; ++i) { if (buf[i] == 0 && buf[i-1] == '\r') { --got; if (i < got) memmove(&buf[i], &buf[i+1], got - i); } } } return got; } return 0;}int hvc_put_chars(int index, const char *buf, int count){ unsigned long dummy; unsigned long *lbuf = (unsigned long *) buf; long ret; ret = plpar_hcall(H_PUT_TERM_CHAR, index, count, lbuf[0], lbuf[1], &dummy, &dummy, &dummy); if (ret == H_Success) return count; if (ret == H_Busy) return 0; return -1;}int hvc_count(int *start_termno){ u32 *termno; struct device_node *dn; if ((dn = find_path_device("/rtas")) != NULL) { if ((termno = (u32 *)get_property(dn, "ibm,termno", 0)) != NULL) { if (start_termno) *start_termno = termno[0]; return termno[1]; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -