Commit c902be71dc6d5e8473bd021feafc8c3608e2b82a

Authored by Arnd Bergmann
Committed by Paul Mackerras
1 parent 017e0fad3e

[PATCH] cell: enable pause(0) in cpu_idle

This patch enables support for pause(0) power management state
for the Cell Broadband Processor, which is import for power efficient
operation. The pervasive infrastructure will in the future enable
us to introduce more functionality specific to the Cell's
pervasive unit.

From: Maximino Aguilar <maguilar@us.ibm.com>
Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

Showing 12 changed files with 335 additions and 14 deletions Side-by-side Diff

arch/powerpc/kernel/cputable.c
... ... @@ -273,7 +273,7 @@
273 273 .oprofile_model = &op_model_power4,
274 274 #endif
275 275 },
276   - { /* BE DD1.x */
  276 + { /* Cell Broadband Engine */
277 277 .pvr_mask = 0xffff0000,
278 278 .pvr_value = 0x00700000,
279 279 .cpu_name = "Cell Broadband Engine",
arch/powerpc/kernel/traps.c
... ... @@ -230,8 +230,10 @@
230 230 void system_reset_exception(struct pt_regs *regs)
231 231 {
232 232 /* See if any machine dependent calls */
233   - if (ppc_md.system_reset_exception)
234   - ppc_md.system_reset_exception(regs);
  233 + if (ppc_md.system_reset_exception) {
  234 + if (ppc_md.system_reset_exception(regs))
  235 + return;
  236 + }
235 237  
236 238 die("System Reset", regs, SIGABRT);
237 239  
arch/powerpc/platforms/cell/Makefile
1 1 obj-y += interrupt.o iommu.o setup.o spider-pic.o
  2 +obj-y += pervasive.o
  3 +
2 4 obj-$(CONFIG_SMP) += smp.o
3 5 obj-$(CONFIG_SPU_FS) += spufs/ spu_base.o
4 6 builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o
arch/powerpc/platforms/cell/pervasive.c
  1 +/*
  2 + * CBE Pervasive Monitor and Debug
  3 + *
  4 + * (C) Copyright IBM Corporation 2005
  5 + *
  6 + * Authors: Maximino Aguilar (maguilar@us.ibm.com)
  7 + * Michael N. Day (mnday@us.ibm.com)
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation; either version 2, or (at your option)
  12 + * any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22 + */
  23 +
  24 +#undef DEBUG
  25 +
  26 +#include <linux/config.h>
  27 +#include <linux/interrupt.h>
  28 +#include <linux/irq.h>
  29 +#include <linux/percpu.h>
  30 +#include <linux/types.h>
  31 +#include <linux/kallsyms.h>
  32 +
  33 +#include <asm/io.h>
  34 +#include <asm/machdep.h>
  35 +#include <asm/prom.h>
  36 +#include <asm/pgtable.h>
  37 +#include <asm/reg.h>
  38 +
  39 +#include "pervasive.h"
  40 +
  41 +static DEFINE_SPINLOCK(cbe_pervasive_lock);
  42 +struct cbe_pervasive {
  43 + struct pmd_regs __iomem *regs;
  44 + unsigned int thread;
  45 +};
  46 +
  47 +/* can't use per_cpu from setup_arch */
  48 +static struct cbe_pervasive cbe_pervasive[NR_CPUS];
  49 +
  50 +static void __init cbe_enable_pause_zero(void)
  51 +{
  52 + unsigned long thread_switch_control;
  53 + unsigned long temp_register;
  54 + struct cbe_pervasive *p;
  55 + int thread;
  56 +
  57 + spin_lock_irq(&cbe_pervasive_lock);
  58 + p = &cbe_pervasive[smp_processor_id()];
  59 +
  60 + if (!cbe_pervasive->regs)
  61 + goto out;
  62 +
  63 + pr_debug("Power Management: CPU %d\n", smp_processor_id());
  64 +
  65 + /* Enable Pause(0) control bit */
  66 + temp_register = in_be64(&p->regs->pm_control);
  67 +
  68 + out_be64(&p->regs->pm_control,
  69 + temp_register|PMD_PAUSE_ZERO_CONTROL);
  70 +
  71 + /* Enable DEC and EE interrupt request */
  72 + thread_switch_control = mfspr(SPRN_TSC_CELL);
  73 + thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
  74 +
  75 + switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
  76 + case CTRL_CT0:
  77 + thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
  78 + thread = 0;
  79 + break;
  80 + case CTRL_CT1:
  81 + thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
  82 + thread = 1;
  83 + break;
  84 + default:
  85 + printk(KERN_WARNING "%s: unknown configuration\n",
  86 + __FUNCTION__);
  87 + thread = -1;
  88 + break;
  89 + }
  90 +
  91 + if (p->thread != thread)
  92 + printk(KERN_WARNING "%s: device tree inconsistant, "
  93 + "cpu %i: %d/%d\n", __FUNCTION__,
  94 + smp_processor_id(),
  95 + p->thread, thread);
  96 +
  97 + mtspr(SPRN_TSC_CELL, thread_switch_control);
  98 +
  99 +out:
  100 + spin_unlock_irq(&cbe_pervasive_lock);
  101 +}
  102 +
  103 +static void cbe_idle(void)
  104 +{
  105 + unsigned long ctrl;
  106 +
  107 + cbe_enable_pause_zero();
  108 +
  109 + while (1) {
  110 + if (!need_resched()) {
  111 + local_irq_disable();
  112 + while (!need_resched()) {
  113 + /* go into low thread priority */
  114 + HMT_low();
  115 +
  116 + /*
  117 + * atomically disable thread execution
  118 + * and runlatch.
  119 + * External and Decrementer exceptions
  120 + * are still handled when the thread
  121 + * is disabled but now enter in
  122 + * cbe_system_reset_exception()
  123 + */
  124 + ctrl = mfspr(SPRN_CTRLF);
  125 + ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
  126 + mtspr(SPRN_CTRLT, ctrl);
  127 + }
  128 + /* restore thread prio */
  129 + HMT_medium();
  130 + local_irq_enable();
  131 + }
  132 +
  133 + /*
  134 + * turn runlatch on again before scheduling the
  135 + * process we just woke up
  136 + */
  137 + ppc64_runlatch_on();
  138 +
  139 + preempt_enable_no_resched();
  140 + schedule();
  141 + preempt_disable();
  142 + }
  143 +}
  144 +
  145 +int cbe_system_reset_exception(struct pt_regs *regs)
  146 +{
  147 + switch (regs->msr & SRR1_WAKEMASK) {
  148 + case SRR1_WAKEEE:
  149 + do_IRQ(regs);
  150 + break;
  151 + case SRR1_WAKEDEC:
  152 + timer_interrupt(regs);
  153 + break;
  154 + case SRR1_WAKEMT:
  155 + /* no action required */
  156 + break;
  157 + default:
  158 + /* do system reset */
  159 + return 0;
  160 + }
  161 + /* everything handled */
  162 + return 1;
  163 +}
  164 +
  165 +static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p)
  166 +{
  167 + struct device_node *node;
  168 + unsigned int *int_servers;
  169 + char *addr;
  170 + unsigned long real_address;
  171 + unsigned int size;
  172 +
  173 + struct pmd_regs __iomem *pmd_mmio_area;
  174 + int hardid, thread;
  175 + int proplen;
  176 +
  177 + pmd_mmio_area = NULL;
  178 + hardid = get_hard_smp_processor_id(cpu);
  179 + for (node = NULL; (node = of_find_node_by_type(node, "cpu"));) {
  180 + int_servers = (void *) get_property(node,
  181 + "ibm,ppc-interrupt-server#s", &proplen);
  182 + if (!int_servers) {
  183 + printk(KERN_WARNING "%s misses "
  184 + "ibm,ppc-interrupt-server#s property",
  185 + node->full_name);
  186 + continue;
  187 + }
  188 + for (thread = 0; thread < proplen / sizeof (int); thread++) {
  189 + if (hardid == int_servers[thread]) {
  190 + addr = get_property(node, "pervasive", NULL);
  191 + goto found;
  192 + }
  193 + }
  194 + }
  195 +
  196 + printk(KERN_WARNING "%s: CPU %d not found\n", __FUNCTION__, cpu);
  197 + return -EINVAL;
  198 +
  199 +found:
  200 + real_address = *(unsigned long*) addr;
  201 + addr += sizeof (unsigned long);
  202 + size = *(unsigned int*) addr;
  203 +
  204 + pr_debug("pervasive area for CPU %d at %lx, size %x\n",
  205 + cpu, real_address, size);
  206 + p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE);
  207 + p->thread = thread;
  208 + return 0;
  209 +}
  210 +
  211 +void __init cell_pervasive_init(void)
  212 +{
  213 + struct cbe_pervasive *p;
  214 + int cpu;
  215 + int ret;
  216 +
  217 + if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
  218 + return;
  219 +
  220 + for_each_cpu(cpu) {
  221 + p = &cbe_pervasive[cpu];
  222 + ret = cbe_find_pmd_mmio(cpu, p);
  223 + if (ret)
  224 + return;
  225 + }
  226 +
  227 + ppc_md.idle_loop = cbe_idle;
  228 + ppc_md.system_reset_exception = cbe_system_reset_exception;
  229 +}
arch/powerpc/platforms/cell/pervasive.h
  1 +/*
  2 + * Cell Pervasive Monitor and Debug interface and HW structures
  3 + *
  4 + * (C) Copyright IBM Corporation 2005
  5 + *
  6 + * Authors: Maximino Aguilar (maguilar@us.ibm.com)
  7 + * David J. Erb (djerb@us.ibm.com)
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation; either version 2, or (at your option)
  12 + * any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22 + */
  23 +
  24 +
  25 +#ifndef PERVASIVE_H
  26 +#define PERVASIVE_H
  27 +
  28 +struct pmd_regs {
  29 + u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
  30 +
  31 + /* Thermal Sensor Registers */
  32 + u64 ts_ctsr1; /* 0x0800 */
  33 + u64 ts_ctsr2; /* 0x0808 */
  34 + u64 ts_mtsr1; /* 0x0810 */
  35 + u64 ts_mtsr2; /* 0x0818 */
  36 + u64 ts_itr1; /* 0x0820 */
  37 + u64 ts_itr2; /* 0x0828 */
  38 + u64 ts_gitr; /* 0x0830 */
  39 + u64 ts_isr; /* 0x0838 */
  40 + u64 ts_imr; /* 0x0840 */
  41 + u64 tm_cr1; /* 0x0848 */
  42 + u64 tm_cr2; /* 0x0850 */
  43 + u64 tm_simr; /* 0x0858 */
  44 + u64 tm_tpr; /* 0x0860 */
  45 + u64 tm_str1; /* 0x0868 */
  46 + u64 tm_str2; /* 0x0870 */
  47 + u64 tm_tsr; /* 0x0878 */
  48 +
  49 + /* Power Management */
  50 + u64 pm_control; /* 0x0880 */
  51 +#define PMD_PAUSE_ZERO_CONTROL 0x10000
  52 + u64 pm_status; /* 0x0888 */
  53 +
  54 + /* Time Base Register */
  55 + u64 tbr; /* 0x0890 */
  56 +
  57 + u8 pad_0x0898_0x1000 [0x1000 - 0x0898]; /* 0x0898 */
  58 +};
  59 +
  60 +void __init cell_pervasive_init(void);
  61 +
  62 +#endif
arch/powerpc/platforms/cell/setup.c
... ... @@ -49,6 +49,7 @@
49 49  
50 50 #include "interrupt.h"
51 51 #include "iommu.h"
  52 +#include "pervasive.h"
52 53  
53 54 #ifdef DEBUG
54 55 #define DBG(fmt...) udbg_printf(fmt)
... ... @@ -165,6 +166,7 @@
165 166 init_pci_config_tokens();
166 167 find_and_init_phbs();
167 168 spider_init_IRQ();
  169 + cell_pervasive_init();
168 170 #ifdef CONFIG_DUMMY_CONSOLE
169 171 conswitchp = &dummy_con;
170 172 #endif
arch/powerpc/platforms/pseries/ras.c
... ... @@ -51,6 +51,8 @@
51 51 #include <asm/udbg.h>
52 52 #include <asm/firmware.h>
53 53  
  54 +#include "ras.h"
  55 +
54 56 static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
55 57 static DEFINE_SPINLOCK(ras_log_buf_lock);
56 58  
... ... @@ -278,7 +280,7 @@
278 280 printk("FWNMI: nmi-interlock failed: %d\n", ret);
279 281 }
280 282  
281   -void pSeries_system_reset_exception(struct pt_regs *regs)
  283 +int pSeries_system_reset_exception(struct pt_regs *regs)
282 284 {
283 285 if (fwnmi_active) {
284 286 struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
... ... @@ -287,6 +289,7 @@
287 289 }
288 290 fwnmi_release_errinfo();
289 291 }
  292 + return 0; /* need to perform reset */
290 293 }
291 294  
292 295 /*
arch/powerpc/platforms/pseries/ras.h
  1 +#ifndef _PSERIES_RAS_H
  2 +#define _PSERIES_RAS_H
  3 +
  4 +struct pt_regs;
  5 +
  6 +extern int pSeries_system_reset_exception(struct pt_regs *regs);
  7 +extern int pSeries_machine_check_exception(struct pt_regs *regs);
  8 +
  9 +#endif /* _PSERIES_RAS_H */
arch/powerpc/platforms/pseries/setup.c
... ... @@ -69,6 +69,7 @@
69 69 #include <asm/smp.h>
70 70  
71 71 #include "plpar_wrappers.h"
  72 +#include "ras.h"
72 73  
73 74 #ifdef DEBUG
74 75 #define DBG(fmt...) udbg_printf(fmt)
... ... @@ -79,9 +80,6 @@
79 80 extern void find_udbg_vterm(void);
80 81  
81 82 int fwnmi_active; /* TRUE if an FWNMI handler is present */
82   -
83   -extern void pSeries_system_reset_exception(struct pt_regs *regs);
84   -extern int pSeries_machine_check_exception(struct pt_regs *regs);
85 83  
86 84 static void pseries_shared_idle(void);
87 85 static void pseries_dedicated_idle(void);
include/asm-powerpc/cputable.h
... ... @@ -105,6 +105,7 @@
105 105 #define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
106 106 #define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
107 107 #define CPU_FTR_CI_LARGE_PAGE ASM_CONST(0x0000100000000000)
  108 +#define CPU_FTR_PAUSE_ZERO ASM_CONST(0x0000200000000000)
108 109 #else
109 110 /* ensure on 32b processors the flags are available for compiling but
110 111 * don't do anything */
... ... @@ -304,7 +305,8 @@
304 305 CPU_FTR_MMCRA_SIHV,
305 306 CPU_FTRS_CELL = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
306 307 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 |
307   - CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT,
  308 + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT |
  309 + CPU_FTR_CTRL | CPU_FTR_PAUSE_ZERO,
308 310 CPU_FTRS_COMPATIBLE = CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
309 311 CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2,
310 312 #endif
include/asm-powerpc/machdep.h
... ... @@ -134,7 +134,7 @@
134 134 void (*nvram_sync)(void);
135 135  
136 136 /* Exception handlers */
137   - void (*system_reset_exception)(struct pt_regs *regs);
  137 + int (*system_reset_exception)(struct pt_regs *regs);
138 138 int (*machine_check_exception)(struct pt_regs *regs);
139 139  
140 140 /* Motherboard/chipset features. This is a kind of general purpose
include/asm-powerpc/reg.h
... ... @@ -145,6 +145,10 @@
145 145 #define SPRN_CTR 0x009 /* Count Register */
146 146 #define SPRN_CTRLF 0x088
147 147 #define SPRN_CTRLT 0x098
  148 +#define CTRL_CT 0xc0000000 /* current thread */
  149 +#define CTRL_CT0 0x80000000 /* thread 0 */
  150 +#define CTRL_CT1 0x40000000 /* thread 1 */
  151 +#define CTRL_TE 0x00c00000 /* thread enable */
148 152 #define CTRL_RUNLATCH 0x1
149 153 #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */
150 154 #define DABR_TRANSLATION (1UL << 2)
... ... @@ -257,11 +261,11 @@
257 261 #define SPRN_HID6 0x3F9 /* BE HID 6 */
258 262 #define HID6_LB (0x0F<<12) /* Concurrent Large Page Modes */
259 263 #define HID6_DLP (1<<20) /* Disable all large page modes (4K only) */
260   -#define SPRN_TSCR 0x399 /* Thread switch control on BE */
261   -#define SPRN_TTR 0x39A /* Thread switch timeout on BE */
262   -#define TSCR_DEC_ENABLE 0x200000 /* Decrementer Interrupt */
263   -#define TSCR_EE_ENABLE 0x100000 /* External Interrupt */
264   -#define TSCR_EE_BOOST 0x080000 /* External Interrupt Boost */
  264 +#define SPRN_TSC_CELL 0x399 /* Thread switch control on Cell */
  265 +#define TSC_CELL_DEC_ENABLE_0 0x400000 /* Decrementer Interrupt */
  266 +#define TSC_CELL_DEC_ENABLE_1 0x200000 /* Decrementer Interrupt */
  267 +#define TSC_CELL_EE_ENABLE 0x100000 /* External Interrupt */
  268 +#define TSC_CELL_EE_BOOST 0x080000 /* External Interrupt Boost */
265 269 #define SPRN_TSC 0x3FD /* Thread switch control on others */
266 270 #define SPRN_TST 0x3FC /* Thread switch timeout on others */
267 271 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
... ... @@ -375,6 +379,14 @@
375 379 #define SPRN_SPRG7 0x117 /* Special Purpose Register General 7 */
376 380 #define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
377 381 #define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
  382 +#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
  383 +#define SRR1_WAKERESET 0x00380000 /* System reset */
  384 +#define SRR1_WAKESYSERR 0x00300000 /* System error */
  385 +#define SRR1_WAKEEE 0x00200000 /* External interrupt */
  386 +#define SRR1_WAKEMT 0x00280000 /* mtctrl */
  387 +#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
  388 +#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */
  389 +
378 390 #ifndef SPRN_SVR
379 391 #define SPRN_SVR 0x11E /* System Version Register */
380 392 #endif