patch-2.4.20 linux-2.4.20/arch/ppc64/kernel/pSeries_lpar.c
Next file: linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c
Previous file: linux-2.4.20/arch/ppc64/kernel/open_pic.c
Back to the patch index
Back to the overall index
- Lines: 596
- Date:
Thu Nov 28 15:53:11 2002
- Orig file:
linux-2.4.19/arch/ppc64/kernel/pSeries_lpar.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/ppc64/kernel/pSeries_lpar.c linux-2.4.20/arch/ppc64/kernel/pSeries_lpar.c
@@ -21,6 +21,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/fs.h>
#include <asm/processor.h>
#include <asm/semaphore.h>
#include <asm/mmu.h>
@@ -33,128 +34,7 @@
#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);
-}
+#include <asm/hvcall.h>
long plpar_tce_get(unsigned long liobn,
unsigned long ioba,
@@ -222,357 +102,6 @@
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;
-
- /* 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 )
@@ -746,55 +275,6 @@
}
-/* 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. */
@@ -853,3 +333,43 @@
}
return 0;
}
+
+#ifndef CONFIG_PPC_ISERIES
+void pSeries_lpar_mm_init(void);
+
+/* 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)
+{
+ pSeries_lpar_mm_init();
+
+ 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.
+ */
+
+ /* 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;
+}
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)