|  | /* | 
|  | * 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/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" | 
|  | #include "cbe_regs.h" | 
|  |  | 
|  | static void cbe_power_save(void) | 
|  | { | 
|  | unsigned long ctrl, thread_switch_control; | 
|  |  | 
|  | /* | 
|  | * We need to hard disable interrupts, but we also need to mark them | 
|  | * hard disabled in the PACA so that the local_irq_enable() done by | 
|  | * our caller upon return propertly hard enables. | 
|  | */ | 
|  | hard_irq_disable(); | 
|  | get_paca()->hard_enabled = 0; | 
|  |  | 
|  | ctrl = mfspr(SPRN_CTRLF); | 
|  |  | 
|  | /* 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 (ctrl & CTRL_CT) { | 
|  | case CTRL_CT0: | 
|  | thread_switch_control |= TSC_CELL_DEC_ENABLE_0; | 
|  | break; | 
|  | case CTRL_CT1: | 
|  | thread_switch_control |= TSC_CELL_DEC_ENABLE_1; | 
|  | break; | 
|  | default: | 
|  | printk(KERN_WARNING "%s: unknown configuration\n", | 
|  | __FUNCTION__); | 
|  | break; | 
|  | } | 
|  | mtspr(SPRN_TSC_CELL, thread_switch_control); | 
|  |  | 
|  | /* | 
|  | * go into low thread priority, medium priority will be | 
|  | * restored for us after wake-up. | 
|  | */ | 
|  | 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 &= ~(CTRL_RUNLATCH | CTRL_TE); | 
|  | mtspr(SPRN_CTRLT, ctrl); | 
|  | } | 
|  |  | 
|  | static 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: | 
|  | break; | 
|  | #ifdef CONFIG_CBE_RAS | 
|  | case SRR1_WAKESYSERR: | 
|  | cbe_system_error_exception(regs); | 
|  | break; | 
|  | case SRR1_WAKETHERM: | 
|  | cbe_thermal_exception(regs); | 
|  | break; | 
|  | #endif /* CONFIG_CBE_RAS */ | 
|  | default: | 
|  | /* do system reset */ | 
|  | return 0; | 
|  | } | 
|  | /* everything handled */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void __init cbe_pervasive_init(void) | 
|  | { | 
|  | int cpu; | 
|  | if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) | 
|  | return; | 
|  |  | 
|  | for_each_possible_cpu(cpu) { | 
|  | struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu); | 
|  | if (!regs) | 
|  | continue; | 
|  |  | 
|  | /* Enable Pause(0) control bit */ | 
|  | out_be64(®s->pmcr, in_be64(®s->pmcr) | | 
|  | CBE_PMD_PAUSE_ZERO_CONTROL); | 
|  | } | 
|  |  | 
|  | ppc_md.power_save = cbe_power_save; | 
|  | ppc_md.system_reset_exception = cbe_system_reset_exception; | 
|  | } |