X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fpowerpc%2Fplatforms%2Fpseries%2Fsetup.c;h=3ba87835757e2cfd5319d54e6992dd2d313488e7;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=31867a701fcbfe25b20b29ae02a3c4b04e714515;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 31867a701..3ba878357 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -18,6 +18,7 @@ #undef DEBUG +#include #include #include #include @@ -76,9 +77,6 @@ #define DBG(fmt...) #endif -/* move those away to a .h */ -extern void smp_init_pseries_mpic(void); -extern void smp_init_pseries_xics(void); extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ @@ -86,7 +84,7 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ static void pseries_shared_idle_sleep(void); static void pseries_dedicated_idle_sleep(void); -static struct device_node *pSeries_mpic_node; +struct mpic *pSeries_mpic; static void pSeries_show_cpuinfo(struct seq_file *m) { @@ -121,98 +119,71 @@ static void __init fwnmi_init(void) fwnmi_active = 1; } -void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc, - struct pt_regs *regs) +static void __init pSeries_init_mpic(void) { - unsigned int cascade_irq = i8259_irq(regs); - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq, regs); - desc->chip->eoi(irq); + unsigned int *addrp; + struct device_node *np; + unsigned long intack = 0; + + /* All ISUs are setup, complete initialization */ + mpic_init(pSeries_mpic); + + /* Check what kind of cascade ACK we have */ + if (!(np = of_find_node_by_name(NULL, "pci")) + || !(addrp = (unsigned int *) + get_property(np, "8259-interrupt-acknowledge", NULL))) + printk(KERN_ERR "Cannot find pci to get ack address\n"); + else + intack = addrp[prom_n_addr_cells(np)-1]; + of_node_put(np); + + /* Setup the legacy interrupts & controller */ + i8259_init(intack, 0); + + /* Hook cascade to mpic */ + mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); } -static void __init pseries_mpic_init_IRQ(void) +static void __init pSeries_setup_mpic(void) { - struct device_node *np, *old, *cascade = NULL; - unsigned int *addrp; - unsigned long intack = 0; unsigned int *opprop; unsigned long openpic_addr = 0; - unsigned int cascade_irq; - int naddr, n, i, opplen; - struct mpic *mpic; + unsigned char senses[NR_IRQS - NUM_ISA_INTERRUPTS]; + struct device_node *root; + int irq_count; - np = of_find_node_by_path("/"); - naddr = prom_n_addr_cells(np); - opprop = (unsigned int *) get_property(np, "platform-open-pic", &opplen); + /* Find the Open PIC if present */ + root = of_find_node_by_path("/"); + opprop = (unsigned int *) get_property(root, "platform-open-pic", NULL); if (opprop != 0) { - openpic_addr = of_read_number(opprop, naddr); + int n = prom_n_addr_cells(root); + + for (openpic_addr = 0; n > 0; --n) + openpic_addr = (openpic_addr << 32) + *opprop++; printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); } - of_node_put(np); + of_node_put(root); BUG_ON(openpic_addr == 0); + /* Get the sense values from OF */ + prom_get_irq_senses(senses, NUM_ISA_INTERRUPTS, NR_IRQS); + /* Setup the openpic driver */ - mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, - MPIC_PRIMARY, - 16, 250, /* isu size, irq count */ - " MPIC "); - BUG_ON(mpic == NULL); - - /* Add ISUs */ - opplen /= sizeof(u32); - for (n = 0, i = naddr; i < opplen; i += naddr, n++) { - unsigned long isuaddr = of_read_number(opprop + i, naddr); - mpic_assign_isu(mpic, n, isuaddr); - } - - /* All ISUs are setup, complete initialization */ - mpic_init(mpic); - - /* Look for cascade */ - for_each_node_by_type(np, "interrupt-controller") - if (device_is_compatible(np, "chrp,iic")) { - cascade = np; - break; - } - if (cascade == NULL) - return; - - cascade_irq = irq_of_parse_and_map(cascade, 0); - if (cascade == NO_IRQ) { - printk(KERN_ERR "xics: failed to map cascade interrupt"); - return; - } - - /* Check ACK type */ - for (old = of_node_get(cascade); old != NULL ; old = np) { - np = of_get_parent(old); - of_node_put(old); - if (np == NULL) - break; - if (strcmp(np->name, "pci") != 0) - continue; - addrp = (u32 *)get_property(np, "8259-interrupt-acknowledge", - NULL); - if (addrp == NULL) - continue; - naddr = prom_n_addr_cells(np); - intack = addrp[naddr-1]; - if (naddr > 1) - intack |= ((unsigned long)addrp[naddr-2]) << 32; - } - if (intack) - printk(KERN_DEBUG "mpic: PCI 8259 intack at 0x%016lx\n", - intack); - i8259_init(cascade, intack); - of_node_put(cascade); - set_irq_chained_handler(cascade_irq, pseries_8259_cascade); + irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ + pSeries_mpic = mpic_alloc(openpic_addr, MPIC_PRIMARY, + 16, 16, irq_count, /* isu size, irq offset, irq count */ + NR_IRQS - 4, /* ipi offset */ + senses, irq_count, /* sense & sense size */ + " MPIC "); } static void pseries_lpar_enable_pmcs(void) { unsigned long set, reset; + power4_enable_pmcs(); + set = 1UL << 63; reset = 0; plpar_hcall_norets(H_PERFMON, set, reset); @@ -222,67 +193,23 @@ static void pseries_lpar_enable_pmcs(void) get_lppaca()->pmcregs_in_use = 1; } -#ifdef CONFIG_KEXEC -static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) -{ - mpic_teardown_this_cpu(secondary); -} - -static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) +static void __init pSeries_setup_arch(void) { - /* Don't risk a hypervisor call if we're crashing */ - if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { - unsigned long vpa = __pa(get_lppaca()); - - if (unregister_vpa(hard_smp_processor_id(), vpa)) { - printk("VPA deregistration of cpu %u (hw_cpu_id %d) " - "failed\n", smp_processor_id(), - hard_smp_processor_id()); - } + /* Fixup ppc_md depending on the type of interrupt controller */ + if (ppc64_interrupt_controller == IC_OPEN_PIC) { + ppc_md.init_IRQ = pSeries_init_mpic; + ppc_md.get_irq = mpic_get_irq; + /* Allocate the mpic now, so that find_and_init_phbs() can + * fill the ISUs */ + pSeries_setup_mpic(); + } else { + ppc_md.init_IRQ = xics_init_IRQ; + ppc_md.get_irq = xics_get_irq; } - xics_teardown_cpu(secondary); -} -#endif /* CONFIG_KEXEC */ - -static void __init pseries_discover_pic(void) -{ - struct device_node *np; - char *typep; - for (np = NULL; (np = of_find_node_by_name(np, - "interrupt-controller"));) { - typep = (char *)get_property(np, "compatible", NULL); - if (strstr(typep, "open-pic")) { - pSeries_mpic_node = of_node_get(np); - ppc_md.init_IRQ = pseries_mpic_init_IRQ; - ppc_md.get_irq = mpic_get_irq; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; -#endif #ifdef CONFIG_SMP - smp_init_pseries_mpic(); + smp_init_pSeries(); #endif - return; - } else if (strstr(typep, "ppc-xicp")) { - ppc_md.init_IRQ = xics_init_IRQ; -#ifdef CONFIG_KEXEC - ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; -#endif -#ifdef CONFIG_SMP - smp_init_pseries_xics(); -#endif - return; - } - } - printk(KERN_ERR "pSeries_discover_pic: failed to recognize" - " interrupt-controller\n"); -} - -static void __init pSeries_setup_arch(void) -{ - /* Discover PIC type and setup ppc_md accordingly */ - pseries_discover_pic(); - /* openpic global configuration register (64-bit format). */ /* openpic Interrupt Source Unit pointer (64-bit format). */ /* python0 facility area (mmio) (64-bit format) REAL address. */ @@ -308,14 +235,14 @@ static void __init pSeries_setup_arch(void) if (firmware_has_feature(FW_FEATURE_SPLPAR)) { vpa_init(boot_cpuid); if (get_lppaca()->shared_proc) { - printk(KERN_DEBUG "Using shared processor idle loop\n"); + printk(KERN_INFO "Using shared processor idle loop\n"); ppc_md.power_save = pseries_shared_idle_sleep; } else { - printk(KERN_DEBUG "Using dedicated idle loop\n"); + printk(KERN_INFO "Using dedicated idle loop\n"); ppc_md.power_save = pseries_dedicated_idle_sleep; } } else { - printk(KERN_DEBUG "Using default idle loop\n"); + printk(KERN_INFO "Using default idle loop\n"); } if (firmware_has_feature(FW_FEATURE_LPAR)) @@ -334,11 +261,41 @@ static int __init pSeries_init_panel(void) } arch_initcall(pSeries_init_panel); +static void __init pSeries_discover_pic(void) +{ + struct device_node *np; + char *typep; + + /* + * Setup interrupt mapping options that are needed for finish_device_tree + * to properly parse the OF interrupt tree & do the virtual irq mapping + */ + __irq_offset_value = NUM_ISA_INTERRUPTS; + ppc64_interrupt_controller = IC_INVALID; + for (np = NULL; (np = of_find_node_by_name(np, "interrupt-controller"));) { + typep = (char *)get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) { + ppc64_interrupt_controller = IC_OPEN_PIC; + break; + } else if (strstr(typep, "ppc-xicp")) { + ppc64_interrupt_controller = IC_PPC_XIC; + break; + } + } + if (ppc64_interrupt_controller == IC_INVALID) + printk("pSeries_discover_pic: failed to recognize" + " interrupt-controller\n"); + +} + static void pSeries_mach_cpu_die(void) { local_irq_disable(); idle_task_exit(); - xics_teardown_cpu(0); + /* Some hardware requires clearing the CPPR, while other hardware does not + * it is safe either way + */ + pSeriesLP_cppr_info(0, 0); rtas_stop_self(); /* Should never get here... */ BUG(); @@ -365,6 +322,11 @@ static void __init pSeries_init_early(void) DBG(" -> pSeries_init_early()\n"); fw_feature_init(); + + if (firmware_has_feature(FW_FEATURE_LPAR)) + hpte_init_lpar(); + else + hpte_init_native(); if (firmware_has_feature(FW_FEATURE_LPAR)) find_udbg_vterm(); @@ -376,6 +338,8 @@ static void __init pSeries_init_early(void) iommu_init_early_pSeries(); + pSeries_discover_pic(); + DBG(" <- pSeries_init_early()\n"); } @@ -420,11 +384,6 @@ static int __init pSeries_probe_hypertas(unsigned long node, if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL) powerpc_firmware_features |= FW_FEATURE_LPAR; - if (firmware_has_feature(FW_FEATURE_LPAR)) - hpte_init_lpar(); - else - hpte_init_native(); - return 1; } @@ -499,8 +458,7 @@ static void pseries_dedicated_idle_sleep(void) } /* - * If not SMT, cede processor. If CPU is running SMT - * cede if the other thread is not idle, so that it can + * Cede if the other thread is not idle, so that it can * go single-threaded. If the other thread is idle, * we ask the hypervisor if it has pending work it * wants to do and cede if it does. Otherwise we keep @@ -513,8 +471,7 @@ static void pseries_dedicated_idle_sleep(void) * very low priority. The cede enables interrupts, which * doesn't matter here. */ - if (!cpu_has_feature(CPU_FTR_SMT) || !lppaca[cpu ^ 1].idle - || poll_pending() == H_PENDING) + if (!lppaca[cpu ^ 1].idle || poll_pending() == H_PENDING) cede_processor(); out: @@ -549,6 +506,27 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) return PCI_PROBE_NORMAL; } +#ifdef CONFIG_KEXEC +static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) +{ + /* Don't risk a hypervisor call if we're crashing */ + if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { + unsigned long vpa = __pa(get_lppaca()); + + if (unregister_vpa(hard_smp_processor_id(), vpa)) { + printk("VPA deregistration of cpu %u (hw_cpu_id %d) " + "failed\n", smp_processor_id(), + hard_smp_processor_id()); + } + } + + if (ppc64_interrupt_controller == IC_OPEN_PIC) + mpic_teardown_this_cpu(secondary); + else + xics_teardown_cpu(secondary); +} +#endif + define_machine(pseries) { .name = "pSeries", .probe = pSeries_probe, @@ -573,6 +551,7 @@ define_machine(pseries) { .system_reset_exception = pSeries_system_reset_exception, .machine_check_exception = pSeries_machine_check_exception, #ifdef CONFIG_KEXEC + .kexec_cpu_down = pseries_kexec_cpu_down, .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, .machine_crash_shutdown = default_machine_crash_shutdown,