.oprofile_model         = &op_model_power4,
 #endif
        },
-       {       /* BE DD1.x */
+       {       /* Cell Broadband Engine */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00700000,
                .cpu_name               = "Cell Broadband Engine",
 
 void system_reset_exception(struct pt_regs *regs)
 {
        /* See if any machine dependent calls */
-       if (ppc_md.system_reset_exception)
-               ppc_md.system_reset_exception(regs);
+       if (ppc_md.system_reset_exception) {
+               if (ppc_md.system_reset_exception(regs))
+                       return;
+       }
 
        die("System Reset", regs, SIGABRT);
 
 
 obj-y                  += interrupt.o iommu.o setup.o spider-pic.o
+obj-y                  += pervasive.o
+
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_SPU_FS)   += spufs/ spu_base.o
 builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
 
--- /dev/null
+/*
+ * CBE Pervasive Monitor and Debug
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          Michael N. Day (mnday@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/kallsyms.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/reg.h>
+
+#include "pervasive.h"
+
+static DEFINE_SPINLOCK(cbe_pervasive_lock);
+struct cbe_pervasive {
+       struct pmd_regs __iomem *regs;
+       unsigned int thread;
+};
+
+/* can't use per_cpu from setup_arch */
+static struct cbe_pervasive cbe_pervasive[NR_CPUS];
+
+static void __init cbe_enable_pause_zero(void)
+{
+       unsigned long thread_switch_control;
+       unsigned long temp_register;
+       struct cbe_pervasive *p;
+       int thread;
+
+       spin_lock_irq(&cbe_pervasive_lock);
+       p = &cbe_pervasive[smp_processor_id()];
+
+       if (!cbe_pervasive->regs)
+               goto out;
+
+       pr_debug("Power Management: CPU %d\n", smp_processor_id());
+
+        /* Enable Pause(0) control bit */
+       temp_register = in_be64(&p->regs->pm_control);
+
+       out_be64(&p->regs->pm_control,
+                temp_register|PMD_PAUSE_ZERO_CONTROL);
+
+       /* Enable DEC and EE interrupt request */
+       thread_switch_control  = mfspr(SPRN_TSC_CELL);
+       thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
+
+       switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+       case CTRL_CT0:
+               thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
+               thread = 0;
+               break;
+       case CTRL_CT1:
+               thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
+               thread = 1;
+               break;
+       default:
+               printk(KERN_WARNING "%s: unknown configuration\n",
+                       __FUNCTION__);
+               thread = -1;
+               break;
+       }
+
+       if (p->thread != thread)
+               printk(KERN_WARNING "%s: device tree inconsistant, "
+                                    "cpu %i: %d/%d\n", __FUNCTION__,
+                                    smp_processor_id(),
+                                    p->thread, thread);
+
+       mtspr(SPRN_TSC_CELL, thread_switch_control);
+
+out:
+       spin_unlock_irq(&cbe_pervasive_lock);
+}
+
+static void cbe_idle(void)
+{
+       unsigned long ctrl;
+
+       cbe_enable_pause_zero();
+
+       while (1) {
+               if (!need_resched()) {
+                       local_irq_disable();
+                       while (!need_resched()) {
+                               /* go into low thread priority */
+                               HMT_low();
+
+                               /*
+                                * atomically disable thread execution
+                                * and runlatch.
+                                * External and Decrementer exceptions
+                                * are still handled when the thread
+                                * is disabled but now enter in
+                                * cbe_system_reset_exception()
+                                */
+                               ctrl = mfspr(SPRN_CTRLF);
+                               ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+                               mtspr(SPRN_CTRLT, ctrl);
+                       }
+                       /* restore thread prio */
+                       HMT_medium();
+                       local_irq_enable();
+               }
+
+               /*
+                * turn runlatch on again before scheduling the
+                * process we just woke up
+                */
+               ppc64_runlatch_on();
+
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+int cbe_system_reset_exception(struct pt_regs *regs)
+{
+       switch (regs->msr & SRR1_WAKEMASK) {
+       case SRR1_WAKEEE:
+               do_IRQ(regs);
+               break;
+       case SRR1_WAKEDEC:
+               timer_interrupt(regs);
+               break;
+       case SRR1_WAKEMT:
+               /* no action required */
+               break;
+       default:
+               /* do system reset */
+               return 0;
+       }
+       /* everything handled */
+       return 1;
+}
+
+static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
+{
+       struct device_node *node;
+       unsigned int *int_servers;
+       char *addr;
+       unsigned long real_address;
+       unsigned int size;
+
+       struct pmd_regs __iomem *pmd_mmio_area;
+       int hardid, thread;
+       int proplen;
+
+       pmd_mmio_area = NULL;
+       hardid = get_hard_smp_processor_id(cpu);
+       for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
+               int_servers = (void *) get_property(node,
+                               "ibm,ppc-interrupt-server#s", &proplen);
+               if (!int_servers) {
+                       printk(KERN_WARNING "%s misses "
+                               "ibm,ppc-interrupt-server#s property",
+                               node->full_name);
+                       continue;
+               }
+               for (thread = 0; thread < proplen / sizeof (int); thread++) {
+                       if (hardid == int_servers[thread]) {
+                               addr = get_property(node, "pervasive", NULL);
+                               goto found;
+                       }
+               }
+       }
+
+       printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
+       return -EINVAL;
+
+found:
+       real_address = *(unsigned long*) addr;
+       addr += sizeof (unsigned long);
+       size = *(unsigned int*) addr;
+
+       pr_debug("pervasive area for CPU %d at %lx, size %x\n",
+                       cpu, real_address, size);
+       p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
+       p->thread = thread;
+       return 0;
+}
+
+void __init cell_pervasive_init(void)
+{
+       struct cbe_pervasive *p;
+       int cpu;
+       int ret;
+
+       if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
+               return;
+
+       for_each_cpu(cpu) {
+               p = &cbe_pervasive[cpu];
+               ret = cbe_find_pmd_mmio(cpu, p);
+               if (ret)
+                       return;
+       }
+
+       ppc_md.idle_loop = cbe_idle;
+       ppc_md.system_reset_exception = cbe_system_reset_exception;
+}
 
--- /dev/null
+/*
+ * Cell Pervasive Monitor and Debug interface and HW structures
+ *
+ * (C) Copyright IBM Corporation 2005
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ *          David J. Erb (djerb@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef PERVASIVE_H
+#define PERVASIVE_H
+
+struct pmd_regs {
+       u8 pad_0x0000_0x0800[0x0800 - 0x0000];                  /* 0x0000 */
+
+       /* Thermal Sensor Registers */
+       u64  ts_ctsr1;                                          /* 0x0800 */
+       u64  ts_ctsr2;                                          /* 0x0808 */
+       u64  ts_mtsr1;                                          /* 0x0810 */
+       u64  ts_mtsr2;                                          /* 0x0818 */
+       u64  ts_itr1;                                           /* 0x0820 */
+       u64  ts_itr2;                                           /* 0x0828 */
+       u64  ts_gitr;                                           /* 0x0830 */
+       u64  ts_isr;                                            /* 0x0838 */
+       u64  ts_imr;                                            /* 0x0840 */
+       u64  tm_cr1;                                            /* 0x0848 */
+       u64  tm_cr2;                                            /* 0x0850 */
+       u64  tm_simr;                                           /* 0x0858 */
+       u64  tm_tpr;                                            /* 0x0860 */
+       u64  tm_str1;                                           /* 0x0868 */
+       u64  tm_str2;                                           /* 0x0870 */
+       u64  tm_tsr;                                            /* 0x0878 */
+
+       /* Power Management */
+       u64  pm_control;                                        /* 0x0880 */
+#define PMD_PAUSE_ZERO_CONTROL         0x10000
+       u64  pm_status;                                         /* 0x0888 */
+
+       /* Time Base Register */
+       u64  tbr;                                               /* 0x0890 */
+
+       u8   pad_0x0898_0x1000 [0x1000 - 0x0898];               /* 0x0898 */
+};
+
+void __init cell_pervasive_init(void);
+
+#endif
 
 
 #include "interrupt.h"
 #include "iommu.h"
+#include "pervasive.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
        init_pci_config_tokens();
        find_and_init_phbs();
        spider_init_IRQ();
+       cell_pervasive_init();
 #ifdef CONFIG_DUMMY_CONSOLE
        conswitchp = &dummy_con;
 #endif
 
 #include <asm/udbg.h>
 #include <asm/firmware.h>
 
+#include "ras.h"
+
 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
 static DEFINE_SPINLOCK(ras_log_buf_lock);
 
                printk("FWNMI: nmi-interlock failed: %d\n", ret);
 }
 
-void pSeries_system_reset_exception(struct pt_regs *regs)
+int pSeries_system_reset_exception(struct pt_regs *regs)
 {
        if (fwnmi_active) {
                struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
                }
                fwnmi_release_errinfo();
        }
+       return 0; /* need to perform reset */
 }
 
 /*
 
--- /dev/null
+#ifndef _PSERIES_RAS_H
+#define _PSERIES_RAS_H
+
+struct pt_regs;
+
+extern int pSeries_system_reset_exception(struct pt_regs *regs);
+extern int pSeries_machine_check_exception(struct pt_regs *regs);
+
+#endif /* _PSERIES_RAS_H */
 
 #include <asm/smp.h>
 
 #include "plpar_wrappers.h"
+#include "ras.h"
 
 #ifdef DEBUG
 #define DBG(fmt...) udbg_printf(fmt)
 
 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);
 
 
 #define CPU_FTR_LOCKLESS_TLBIE         ASM_CONST(0x0000040000000000)
 #define CPU_FTR_MMCRA_SIHV             ASM_CONST(0x0000080000000000)
 #define CPU_FTR_CI_LARGE_PAGE          ASM_CONST(0x0000100000000000)
+#define CPU_FTR_PAUSE_ZERO             ASM_CONST(0x0000200000000000)
 #else
 /* ensure on 32b processors the flags are available for compiling but
  * don't do anything */
            CPU_FTR_MMCRA_SIHV,
        CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
-           CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
+           CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
+           CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
        CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
            CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
 #endif
 
        void            (*nvram_sync)(void);
 
        /* Exception handlers */
-       void            (*system_reset_exception)(struct pt_regs *regs);
+       int             (*system_reset_exception)(struct pt_regs *regs);
        int             (*machine_check_exception)(struct pt_regs *regs);
 
        /* Motherboard/chipset features. This is a kind of general purpose
 
 #define SPRN_CTR       0x009   /* Count Register */
 #define SPRN_CTRLF     0x088
 #define SPRN_CTRLT     0x098
+#define   CTRL_CT      0xc0000000      /* current thread */
+#define   CTRL_CT0     0x80000000      /* thread 0 */
+#define   CTRL_CT1     0x40000000      /* thread 1 */
+#define   CTRL_TE      0x00c00000      /* thread enable */
 #define   CTRL_RUNLATCH        0x1
 #define SPRN_DABR      0x3F5   /* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION     (1UL << 2)
 #define        SPRN_HID6       0x3F9   /* BE HID 6 */
 #define          HID6_LB       (0x0F<<12) /* Concurrent Large Page Modes */
 #define          HID6_DLP      (1<<20) /* Disable all large page modes (4K only) */
-#define        SPRN_TSCR       0x399   /* Thread switch control on BE */
-#define        SPRN_TTR        0x39A   /* Thread switch timeout on BE */
-#define          TSCR_DEC_ENABLE       0x200000 /* Decrementer Interrupt */
-#define          TSCR_EE_ENABLE        0x100000 /* External Interrupt */
-#define          TSCR_EE_BOOST         0x080000 /* External Interrupt Boost */
+#define        SPRN_TSC_CELL   0x399   /* Thread switch control on Cell */
+#define          TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
+#define          TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
+#define          TSC_CELL_EE_ENABLE    0x100000 /* External Interrupt */
+#define          TSC_CELL_EE_BOOST     0x080000 /* External Interrupt Boost */
 #define        SPRN_TSC        0x3FD   /* Thread switch control on others */
 #define        SPRN_TST        0x3FC   /* Thread switch timeout on others */
 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
 #define SPRN_SPRG7     0x117   /* Special Purpose Register General 7 */
 #define SPRN_SRR0      0x01A   /* Save/Restore Register 0 */
 #define SPRN_SRR1      0x01B   /* Save/Restore Register 1 */
+#define   SRR1_WAKEMASK                0x00380000 /* reason for wakeup */
+#define   SRR1_WAKERESET       0x00380000 /* System reset */
+#define   SRR1_WAKESYSERR      0x00300000 /* System error */
+#define   SRR1_WAKEEE          0x00200000 /* External interrupt */
+#define   SRR1_WAKEMT          0x00280000 /* mtctrl */
+#define   SRR1_WAKEDEC         0x00180000 /* Decrementer interrupt */
+#define   SRR1_WAKETHERM       0x00100000 /* Thermal management interrupt */
+
 #ifndef SPRN_SVR
 #define SPRN_SVR       0x11E   /* System Version Register */
 #endif