vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc64 / kernel / pSeries_lpar.c
index 68eeb7a..624acf0 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/mmu_context.h>
 #include <asm/ppcdebug.h>
 #include <asm/iommu.h>
-#include <asm/naca.h>
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 #include <asm/prom.h>
@@ -59,6 +58,74 @@ extern void pSeries_find_serial_port(void);
 
 int vtermno;   /* virtual terminal# for udbg  */
 
+#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
+static void udbg_hvsi_putc(unsigned char c)
+{
+       /* packet's seqno isn't used anyways */
+       uint8_t packet[] __ALIGNED__ = { 0xff, 5, 0, 0, c };
+       int rc;
+
+       if (c == '\n')
+               udbg_hvsi_putc('\r');
+
+       do {
+               rc = plpar_put_term_char(vtermno, sizeof(packet), packet);
+       } while (rc == H_Busy);
+}
+
+static long hvsi_udbg_buf_len;
+static uint8_t hvsi_udbg_buf[256];
+
+static int udbg_hvsi_getc_poll(void)
+{
+       unsigned char ch;
+       int rc, i;
+
+       if (hvsi_udbg_buf_len == 0) {
+               rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf);
+               if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) {
+                       /* bad read or non-data packet */
+                       hvsi_udbg_buf_len = 0;
+               } else {
+                       /* remove the packet header */
+                       for (i = 4; i < hvsi_udbg_buf_len; i++)
+                               hvsi_udbg_buf[i-4] = hvsi_udbg_buf[i];
+                       hvsi_udbg_buf_len -= 4;
+               }
+       }
+
+       if (hvsi_udbg_buf_len <= 0 || hvsi_udbg_buf_len > 256) {
+               /* no data ready */
+               hvsi_udbg_buf_len = 0;
+               return -1;
+       }
+
+       ch = hvsi_udbg_buf[0];
+       /* shift remaining data down */
+       for (i = 1; i < hvsi_udbg_buf_len; i++) {
+               hvsi_udbg_buf[i-1] = hvsi_udbg_buf[i];
+       }
+       hvsi_udbg_buf_len--;
+
+       return ch;
+}
+
+static unsigned char udbg_hvsi_getc(void)
+{
+       int ch;
+       for (;;) {
+               ch = udbg_hvsi_getc_poll();
+               if (ch == -1) {
+                       /* This shouldn't be needed...but... */
+                       volatile unsigned long delay;
+                       for (delay=0; delay < 2000000; delay++)
+                               ;
+               } else {
+                       return ch;
+               }
+       }
+}
+
 static void udbg_putcLP(unsigned char c)
 {
        char buf[16];
@@ -166,11 +233,15 @@ int find_udbg_vterm(void)
                                ppc_md.udbg_getc_poll = udbg_getc_pollLP;
                                found = 1;
                        }
-               } else {
-                       /* XXX implement udbg_putcLP_vtty for hvterm-protocol1 case */
-                       printk(KERN_WARNING "%s doesn't speak hvterm1; "
-                                       "can't print udbg messages\n",
-                              stdout_node->full_name);
+               } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+                       termno = (u32 *)get_property(stdout_node, "reg", NULL);
+                       if (termno) {
+                               vtermno = termno[0];
+                               ppc_md.udbg_putc = udbg_hvsi_putc;
+                               ppc_md.udbg_getc = udbg_hvsi_getc;
+                               ppc_md.udbg_getc_poll = udbg_hvsi_getc_poll;
+                               found = 1;
+                       }
                }
        } else if (strncmp(name, "serial", 6)) {
                /* XXX fix ISA serial console */
@@ -187,6 +258,22 @@ out:
        return found;
 }
 
+void vpa_init(int cpu)
+{
+       int hwcpu = get_hard_smp_processor_id(cpu);
+       unsigned long vpa = (unsigned long)&(paca[cpu].lppaca);
+       long ret;
+       unsigned long flags;
+
+       /* Register the Virtual Processor Area (VPA) */
+       flags = 1UL << (63 - 18);
+       ret = register_vpa(flags, hwcpu, __pa(vpa));
+
+       if (ret)
+               printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
+                               "cpu %d (hw %d) of area %lx returns %ld\n",
+                               cpu, hwcpu, __pa(vpa), ret);
+}
 
 long pSeries_lpar_hpte_insert(unsigned long hpte_group,
                              unsigned long va, unsigned long prpn,
@@ -248,7 +335,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group,
        return (slot & 7) | (secondary << 3);
 }
 
-static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pSeries_lpar_tlbie_lock);
 
 static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
 {
@@ -280,7 +367,7 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
 
 static void pSeries_lpar_hptab_clear(void)
 {
-       unsigned long size_bytes = 1UL << naca->pftSize;
+       unsigned long size_bytes = 1UL << ppc64_pft_size;
        unsigned long hpte_count = size_bytes >> 4;
        unsigned long dummy1, dummy2;
        int i;
@@ -349,7 +436,7 @@ static long pSeries_lpar_hpte_find(unsigned long vpn)
        hash = hpt_hash(vpn, 0);
 
        for (j = 0; j < 2; j++) {
-               slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
+               slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
                for (i = 0; i < HPTES_PER_GROUP; i++) {
                        hpte_dw0.dword0 = pSeries_lpar_hpte_getword0(slot);
                        dw0 = hpte_dw0.dw0;
@@ -416,7 +503,7 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number,
                                   int local)
 {
        int i;
-       unsigned long flags;
+       unsigned long flags = 0;
        struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
        int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE);