X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2FpSeries_lpar.c;h=68eeb7a811e207850546ead17c6e3cdcd858c73e;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=a44c3326805e286f1c181609195ad072603ff827;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index a44c33268..68eeb7a81 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define DEBUG + #include #include #include @@ -34,10 +36,16 @@ #include #include #include -#include #include #include #include +#include + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif /* in pSeries_hvCall.S */ EXPORT_SYMBOL(plpar_hcall); @@ -45,146 +53,9 @@ EXPORT_SYMBOL(plpar_hcall_4out); EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); -long poll_pending(void) -{ - unsigned long dummy; - return plpar_hcall(H_POLL_PENDING, 0, 0, 0, 0, - &dummy, &dummy, &dummy); -} - -long prod_processor(void) -{ - plpar_hcall_norets(H_PROD); - return(0); -} - -long cede_processor(void) -{ - plpar_hcall_norets(H_CEDE); - return(0); -} - -long register_vpa(unsigned long flags, unsigned long proc, unsigned long vpa) -{ - plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa); - return(0); -} - -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, avpn); -} - -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); -} +extern void fw_feature_init(void); +extern void pSeries_find_serial_port(void); -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 *lbuf = (unsigned long *)buffer; /* ToDo: alignment? */ - return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0], - lbuf[1]); -} - -static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum, - long npages, unsigned long uaddr, - enum dma_data_direction direction) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT; - tce.te_rdwr = 1; - if (direction != DMA_TO_DEVICE) - tce.te_pciwr = 1; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - tce.te_rpn++; - } -} - -static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) -{ - u64 rc; - union tce_entry tce; - - tce.te_word = 0; - - while (npages--) { - rc = plpar_tce_put((u64)tbl->it_index, - (u64)tcenum << 12, - tce.te_word ); - - if (rc && printk_ratelimit()) { - printk("tce_free_pSeriesLP: plpar_tce_put failed\n"); - printk("\trc = %ld\n", rc); - printk("\tindex = 0x%lx\n", (u64)tbl->it_index); - printk("\ttcenum = 0x%lx\n", (u64)tcenum); - printk("\ttce val = 0x%lx\n", tce.te_word ); - show_stack(current, (unsigned long *)__get_SP()); - } - - tcenum++; - } -} int vtermno; /* virtual terminal# for udbg */ @@ -249,8 +120,19 @@ static unsigned char udbg_getcLP(void) } } +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +void udbg_init_debug_lpar(void) +{ + vtermno = 0; + ppc_md.udbg_putc = udbg_putcLP; + ppc_md.udbg_getc = udbg_getcLP; + ppc_md.udbg_getc_poll = udbg_getc_pollLP; +} + /* returns 0 if couldn't find or use /chosen/stdout as console */ -static int find_udbg_vterm(void) +int find_udbg_vterm(void) { struct device_node *stdout_node; u32 *termno; @@ -258,15 +140,14 @@ static int find_udbg_vterm(void) int found = 0; /* find the boot console from /chosen/stdout */ - if (!of_stdout_device) { - printk(KERN_WARNING "couldn't get path from /chosen/stdout!\n"); - return found; - } - stdout_node = of_find_node_by_path(of_stdout_device); - if (!stdout_node) { - printk(KERN_WARNING "couldn't find node from /chosen/stdout\n"); - return found; - } + if (!of_chosen) + return 0; + name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return 0; + stdout_node = of_find_node_by_path(name); + if (!stdout_node) + return 0; /* now we have the stdout node; figure out what type of device it is. */ name = (char *)get_property(stdout_node, "name", NULL); @@ -288,15 +169,17 @@ static int find_udbg_vterm(void) } else { /* XXX implement udbg_putcLP_vtty for hvterm-protocol1 case */ printk(KERN_WARNING "%s doesn't speak hvterm1; " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } } else if (strncmp(name, "serial", 6)) { /* XXX fix ISA serial console */ printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } else { printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - of_stdout_device); + stdout_node->full_name); } out: @@ -304,35 +187,6 @@ out: return found; } -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(); - - tce_init_pSeries(); - - ppc_md.tce_build = tce_build_pSeriesLP; - ppc_md.tce_free = tce_free_pSeriesLP; - - pci_iommu_init(); - -#ifdef CONFIG_SMP - smp_init_pSeries(); -#endif - - /* The keyboard is not useful in the LPAR environment. - * Leave all the ppc_md keyboard interfaces NULL. - */ - - if (0 == find_udbg_vterm()) { - printk(KERN_WARNING - "can't use stdout; can't print early debug messages.\n"); - } -} long pSeries_lpar_hpte_insert(unsigned long hpte_group, unsigned long va, unsigned long prpn, @@ -377,7 +231,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, lhpte.dw0.dword0, lhpte.dw1.dword1, &slot, &dummy0, &dummy1); - if (lpar_rc == H_PTEG_Full) + if (unlikely(lpar_rc == H_PTEG_Full)) return -1; /* @@ -385,7 +239,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, * will fail. However we must catch the failure in hash_page * or we will loop forever, so return -2 in this case. */ - if (lpar_rc != H_Success) + if (unlikely(lpar_rc != H_Success)) return -2; /* Because of iSeries, we have to pass down the secondary @@ -415,9 +269,7 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) if (lpar_rc == H_Success) return i; - if (lpar_rc != H_Not_Found) - panic("Bad return code from pte remove rc = %lx\n", - lpar_rc); + BUG_ON(lpar_rc != H_Not_Found); slot_offset++; slot_offset &= 0x7; @@ -426,6 +278,18 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) return -1; } +static void pSeries_lpar_hptab_clear(void) +{ + unsigned long size_bytes = 1UL << naca->pftSize; + unsigned long hpte_count = size_bytes >> 4; + unsigned long dummy1, dummy2; + int i; + + /* TODO: Use bulk call */ + for (i = 0; i < hpte_count; i++) + plpar_pte_remove(0, i, 0, &dummy1, &dummy2); +} + /* * 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. @@ -447,8 +311,7 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp, if (lpar_rc == H_Not_Found) return -1; - if (lpar_rc != H_Success) - panic("bad return code from pte protect rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); return 0; } @@ -464,11 +327,10 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) /* 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) - panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); return dword0; } @@ -519,15 +381,12 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, vpn = va >> PAGE_SHIFT; slot = pSeries_lpar_hpte_find(vpn); - if (slot == -1) - panic("updateboltedpp: Could not find page to bolt\n"); + BUG_ON(slot == -1); flags = newpp & 3; lpar_rc = plpar_pte_protect(flags, slot, 0); - if (lpar_rc != H_Success) - panic("Bad return code from pte bolted protect rc = %lx\n", - lpar_rc); + BUG_ON(lpar_rc != H_Success); } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, @@ -546,8 +405,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, if (lpar_rc == H_Not_Found) return; - if (lpar_rc != H_Success) - panic("Bad return code from invalidate rc = %lx\n", lpar_rc); + BUG_ON(lpar_rc != H_Success); } /* @@ -560,18 +418,19 @@ void pSeries_lpar_flush_hash_range(unsigned long context, unsigned long number, int i; unsigned long flags; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); for (i = 0; i < number; i++) flush_hash_page(context, batch->addr[i], batch->pte[i], local); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); } -void pSeries_lpar_mm_init(void) +void hpte_init_lpar(void) { ppc_md.hpte_invalidate = pSeries_lpar_hpte_invalidate; ppc_md.hpte_updatepp = pSeries_lpar_hpte_updatepp; @@ -579,4 +438,7 @@ void pSeries_lpar_mm_init(void) ppc_md.hpte_insert = pSeries_lpar_hpte_insert; ppc_md.hpte_remove = pSeries_lpar_hpte_remove; ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range; + ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear; + + htab_finish_init(); }