[PATCH] PowerPC/PCI Hotplug build break
[safe/jmp/linux-2.6] / arch / powerpc / platforms / pseries / setup.c
index c53dbbb..da6ceba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/setup.c
+ *  64-bit pSeries and RS/6000 setup code.
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
+#include <asm/kexec.h>
 #include <asm/time.h>
 #include <asm/nvram.h>
-#include <asm/plpar_wrappers.h>
-#include <asm/xics.h>
+#include "xics.h"
 #include <asm/firmware.h>
 #include <asm/pmc.h>
 #include <asm/mpic.h>
 #include <asm/ppc-pci.h>
 #include <asm/i8259.h>
 #include <asm/udbg.h>
+#include <asm/smp.h>
+
+#include "plpar_wrappers.h"
+#include "ras.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
 #endif
 
 extern void find_udbg_vterm(void);
-extern void system_reset_fwnmi(void);  /* from head.S */
-extern void machine_check_fwnmi(void); /* from head.S */
-extern void generic_find_legacy_serial_ports(u64 *physport,
-               unsigned int *default_speed);
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
 
-extern void pSeries_system_reset_exception(struct pt_regs *regs);
-extern int pSeries_machine_check_exception(struct pt_regs *regs);
-
 static void pseries_shared_idle(void);
 static void pseries_dedicated_idle(void);
 
-static volatile void __iomem * chrp_int_ack_special;
 struct mpic *pSeries_mpic;
 
-void pSeries_show_cpuinfo(struct seq_file *m)
+static void pSeries_show_cpuinfo(struct seq_file *m)
 {
        struct device_node *root;
        const char *model = "";
@@ -104,34 +100,30 @@ void pSeries_show_cpuinfo(struct seq_file *m)
 
 /* Initialize firmware assisted non-maskable interrupts if
  * the firmware supports this feature.
- *
  */
 static void __init fwnmi_init(void)
 {
-       int ret;
+       unsigned long system_reset_addr, machine_check_addr;
+
        int ibm_nmi_register = rtas_token("ibm,nmi-register");
        if (ibm_nmi_register == RTAS_UNKNOWN_SERVICE)
                return;
-       ret = rtas_call(ibm_nmi_register, 2, 1, NULL,
-                       __pa((unsigned long)system_reset_fwnmi),
-                       __pa((unsigned long)machine_check_fwnmi));
-       if (ret == 0)
-               fwnmi_active = 1;
-}
 
-static int pSeries_irq_cascade(struct pt_regs *regs, void *data)
-{
-       if (chrp_int_ack_special)
-               return readb(chrp_int_ack_special);
-       else
-               return i8259_irq(regs);
+       /* If the kernel's not linked at zero we point the firmware at low
+        * addresses anyway, and use a trampoline to get to the real code. */
+       system_reset_addr  = __pa(system_reset_fwnmi) - PHYSICAL_START;
+       machine_check_addr = __pa(machine_check_fwnmi) - PHYSICAL_START;
+
+       if (0 == rtas_call(ibm_nmi_register, 2, 1, NULL, system_reset_addr,
+                               machine_check_addr))
+               fwnmi_active = 1;
 }
 
 static void __init pSeries_init_mpic(void)
 {
         unsigned int *addrp;
        struct device_node *np;
-        int i;
+       unsigned long intack = 0;
 
        /* All ISUs are setup, complete initialization */
        mpic_init(pSeries_mpic);
@@ -142,16 +134,14 @@ static void __init pSeries_init_mpic(void)
                  get_property(np, "8259-interrupt-acknowledge", NULL)))
                 printk(KERN_ERR "Cannot find pci to get ack address\n");
         else
-               chrp_int_ack_special = ioremap(addrp[prom_n_addr_cells(np)-1], 1);
+               intack = addrp[prom_n_addr_cells(np)-1];
        of_node_put(np);
 
        /* Setup the legacy interrupts & controller */
-        for (i = 0; i < NUM_ISA_INTERRUPTS; i++)
-                irq_desc[i].handler = &i8259_pic;
-       i8259_init(0);
+       i8259_init(intack, 0);
 
        /* Hook cascade to mpic */
-       mpic_setup_cascade(NUM_ISA_INTERRUPTS, pSeries_irq_cascade, NULL);
+       mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL);
 }
 
 static void __init pSeries_setup_mpic(void)
@@ -200,7 +190,7 @@ static void pseries_lpar_enable_pmcs(void)
 
        /* instruct hypervisor to maintain PMCs */
        if (firmware_has_feature(FW_FEATURE_SPLPAR))
-               get_paca()->lppaca.pmcregs_in_use = 1;
+               get_lppaca()->pmcregs_in_use = 1;
 }
 
 static void __init pSeries_setup_arch(void)
@@ -209,14 +199,12 @@ static void __init pSeries_setup_arch(void)
        if (ppc64_interrupt_controller == IC_OPEN_PIC) {
                ppc_md.init_IRQ       = pSeries_init_mpic;
                ppc_md.get_irq        = mpic_get_irq;
-               ppc_md.cpu_irq_down   = mpic_teardown_this_cpu;
                /* 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;
-               ppc_md.cpu_irq_down   = xics_teardown_cpu;
        }
 
 #ifdef CONFIG_SMP
@@ -241,16 +229,12 @@ static void __init pSeries_setup_arch(void)
        find_and_init_phbs();
        eeh_init();
 
-#ifdef CONFIG_DUMMY_CONSOLE
-       conswitchp = &dummy_con;
-#endif
-
        pSeries_nvram_init();
 
        /* Choose an idle loop */
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                vpa_init(boot_cpuid);
-               if (get_paca()->lppaca.shared_proc) {
+               if (get_lppaca()->shared_proc) {
                        printk(KERN_INFO "Using shared processor idle loop\n");
                        ppc_md.idle_loop = pseries_shared_idle;
                } else {
@@ -262,7 +246,7 @@ static void __init pSeries_setup_arch(void)
                ppc_md.idle_loop = default_idle;
        }
 
-       if (systemcfg->platform & PLATFORM_LPAR)
+       if (platform_is_lpar())
                ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
        else
                ppc_md.enable_pmcs = power4_enable_pmcs;
@@ -319,9 +303,7 @@ static void __init fw_feature_init(void)
        }
 
        of_node_put(dn);
- no_rtas:
-       printk(KERN_INFO "firmware_features = 0x%lx\n", 
-              ppc64_firmware_features);
+no_rtas:
 
        DBG(" <- fw_feature_init()\n");
 }
@@ -340,15 +322,18 @@ static  void __init pSeries_discover_pic(void)
        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"))
+               if (strstr(typep, "open-pic")) {
                        ppc64_interrupt_controller = IC_OPEN_PIC;
-               else if (strstr(typep, "ppc-xicp"))
+                       break;
+               } else if (strstr(typep, "ppc-xicp")) {
                        ppc64_interrupt_controller = IC_PPC_XIC;
-               else
-                       printk("pSeries_discover_pic: failed to recognize"
-                              " interrupt-controller\n");
-               break;
+                       break;
+               }
        }
+       if (ppc64_interrupt_controller == IC_INVALID)
+               printk("pSeries_discover_pic: failed to recognize"
+                       " interrupt-controller\n");
+
 }
 
 static void pSeries_mach_cpu_die(void)
@@ -365,22 +350,30 @@ static void pSeries_mach_cpu_die(void)
        for(;;);
 }
 
+static int pseries_set_dabr(unsigned long dabr)
+{
+       return plpar_hcall_norets(H_SET_DABR, dabr);
+}
+
+static int pseries_set_xdabr(unsigned long dabr)
+{
+       /* We want to catch accesses from kernel and userspace */
+       return plpar_hcall_norets(H_SET_XDABR, dabr,
+                       H_DABRX_KERNEL | H_DABRX_USER);
+}
 
 /*
  * Early initialization.  Relocation is on but do not reference unbolted pages
  */
 static void __init pSeries_init_early(void)
 {
-       void *comport;
        int iommu_off = 0;
-       unsigned int default_speed;
-       u64 physport;
 
        DBG(" -> pSeries_init_early()\n");
 
        fw_feature_init();
        
-       if (systemcfg->platform & PLATFORM_LPAR)
+       if (platform_is_lpar())
                hpte_init_lpar();
        else {
                hpte_init_native();
@@ -388,18 +381,13 @@ static void __init pSeries_init_early(void)
                             get_property(of_chosen, "linux,iommu-off", NULL));
        }
 
-       generic_find_legacy_serial_ports(&physport, &default_speed);
-
-       if (systemcfg->platform & PLATFORM_LPAR)
+       if (platform_is_lpar())
                find_udbg_vterm();
-       else if (physport) {
-               /* Map the uart for udbg. */
-               comport = (void *)ioremap(physport, 16);
-               udbg_init_uart(comport, default_speed);
-
-               DBG("Hello World !\n");
-       }
 
+       if (firmware_has_feature(FW_FEATURE_DABR))
+               ppc_md.set_dabr = pseries_set_dabr;
+       else if (firmware_has_feature(FW_FEATURE_XDABR))
+               ppc_md.set_dabr = pseries_set_xdabr;
 
        iommu_init_early_pSeries();
 
@@ -456,10 +444,10 @@ DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
 
 static inline void dedicated_idle_sleep(unsigned int cpu)
 {
-       struct paca_struct *ppaca = &paca[cpu ^ 1];
+       struct lppaca *plppaca = &lppaca[cpu ^ 1];
 
        /* Only sleep if the other thread is not idle */
-       if (!(ppaca->lppaca.idle)) {
+       if (!(plppaca->idle)) {
                local_irq_disable();
 
                /*
@@ -467,6 +455,7 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
                 * more.
                 */
                clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
 
                /*
                 * SMT dynamic mode. Cede will result in this thread going
@@ -479,6 +468,7 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
                        cede_processor();
                else
                        local_irq_enable();
+               set_thread_flag(TIF_POLLING_NRFLAG);
        } else {
                /*
                 * Give the HV an opportunity at the processor, since we are
@@ -490,24 +480,20 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
 
 static void pseries_dedicated_idle(void)
 { 
-       long oldval;
-       struct paca_struct *lpaca = get_paca();
        unsigned int cpu = smp_processor_id();
        unsigned long start_snooze;
        unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+       set_thread_flag(TIF_POLLING_NRFLAG);
 
        while (1) {
                /*
                 * Indicate to the HV that we are idle. Now would be
                 * a good time to find other work to dispatch.
                 */
-               lpaca->lppaca.idle = 1;
-
-               oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-               if (!oldval) {
-                       set_thread_flag(TIF_POLLING_NRFLAG);
+               get_lppaca()->idle = 1;
 
-                       start_snooze = __get_tb() +
+               if (!need_resched()) {
+                       start_snooze = get_tb() +
                                *smt_snooze_delay * tb_ticks_per_usec;
 
                        while (!need_resched() && !cpu_is_offline(cpu)) {
@@ -521,7 +507,7 @@ static void pseries_dedicated_idle(void)
                                HMT_very_low();
 
                                if (*smt_snooze_delay != 0 &&
-                                   __get_tb() > start_snooze) {
+                                   get_tb() > start_snooze) {
                                        HMT_medium();
                                        dedicated_idle_sleep(cpu);
                                }
@@ -529,15 +515,14 @@ static void pseries_dedicated_idle(void)
                        }
 
                        HMT_medium();
-                       clear_thread_flag(TIF_POLLING_NRFLAG);
-               } else {
-                       set_need_resched();
                }
 
-               lpaca->lppaca.idle = 0;
+               get_lppaca()->idle = 0;
                ppc64_runlatch_on();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
 
                if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
                        cpu_die();
@@ -546,7 +531,6 @@ static void pseries_dedicated_idle(void)
 
 static void pseries_shared_idle(void)
 {
-       struct paca_struct *lpaca = get_paca();
        unsigned int cpu = smp_processor_id();
 
        while (1) {
@@ -554,7 +538,7 @@ static void pseries_shared_idle(void)
                 * Indicate to the HV that we are idle. Now would be
                 * a good time to find other work to dispatch.
                 */
-               lpaca->lppaca.idle = 1;
+               get_lppaca()->idle = 1;
 
                while (!need_resched() && !cpu_is_offline(cpu)) {
                        local_irq_disable();
@@ -578,10 +562,12 @@ static void pseries_shared_idle(void)
                        HMT_medium();
                }
 
-               lpaca->lppaca.idle = 0;
+               get_lppaca()->idle = 0;
                ppc64_runlatch_on();
 
+               preempt_enable_no_resched();
                schedule();
+               preempt_disable();
 
                if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
                        cpu_die();
@@ -590,11 +576,32 @@ static void pseries_shared_idle(void)
 
 static int pSeries_pci_probe_mode(struct pci_bus *bus)
 {
-       if (systemcfg->platform & PLATFORM_LPAR)
+       if (platform_is_lpar())
                return PCI_PROBE_DEVTREE;
        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 (!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
+
 struct machdep_calls __initdata pSeries_md = {
        .probe                  = pSeries_probe,
        .setup_arch             = pSeries_setup_arch,
@@ -617,4 +624,10 @@ struct machdep_calls __initdata pSeries_md = {
        .check_legacy_ioport    = pSeries_check_legacy_ioport,
        .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,
+#endif
 };