X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2FpSeries_lpar.c;h=624acf0c8cec6ab792438660cd49e9cfe11638c0;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=68eeb7a811e207850546ead17c6e3cdcd858c73e;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index 68eeb7a81..624acf0c8 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -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);