aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/configs/cell_defconfig1
-rw-r--r--arch/powerpc/kernel/head_64.S29
-rw-r--r--arch/powerpc/kernel/prom.c43
-rw-r--r--arch/powerpc/platforms/cell/Kconfig4
-rw-r--r--arch/powerpc/platforms/cell/Makefile3
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c128
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h129
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c37
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c104
-rw-r--r--arch/powerpc/platforms/cell/pervasive.h37
-rw-r--r--arch/powerpc/platforms/cell/ras.c112
-rw-r--r--arch/powerpc/platforms/cell/ras.h9
-rw-r--r--arch/powerpc/platforms/cell/setup.c10
-rw-r--r--include/asm-powerpc/prom.h3
-rw-r--r--include/asm-powerpc/reg.h2
15 files changed, 505 insertions, 146 deletions
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index dbe421dc3c11..5b8599d03f16 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -133,6 +133,7 @@ CONFIG_CELL_IIC=y
133# 133#
134CONFIG_SPU_FS=m 134CONFIG_SPU_FS=m
135CONFIG_SPUFS_MMAP=y 135CONFIG_SPUFS_MMAP=y
136CONFIG_CBE_RAS=y
136 137
137# 138#
138# Kernel options 139# Kernel options
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index b7d140430a41..831acbdf2592 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -316,6 +316,21 @@ label##_pSeries: \
316 mtspr SPRN_SPRG1,r13; /* save r13 */ \ 316 mtspr SPRN_SPRG1,r13; /* save r13 */ \
317 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) 317 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
318 318
319#define HSTD_EXCEPTION_PSERIES(n, label) \
320 . = n; \
321 .globl label##_pSeries; \
322label##_pSeries: \
323 HMT_MEDIUM; \
324 mtspr SPRN_SPRG1,r20; /* save r20 */ \
325 mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \
326 mtspr SPRN_SRR0,r20; \
327 mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \
328 mtspr SPRN_SRR1,r20; \
329 mfspr r20,SPRN_SPRG1; /* restore r20 */ \
330 mtspr SPRN_SPRG1,r13; /* save r13 */ \
331 EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
332
333
319#define STD_EXCEPTION_ISERIES(n, label, area) \ 334#define STD_EXCEPTION_ISERIES(n, label, area) \
320 .globl label##_iSeries; \ 335 .globl label##_iSeries; \
321label##_iSeries: \ 336label##_iSeries: \
@@ -544,8 +559,17 @@ system_call_pSeries:
544 559
545 STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable) 560 STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable)
546 561
562#ifdef CONFIG_CBE_RAS
563 HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error)
564#endif /* CONFIG_CBE_RAS */
547 STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) 565 STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
566#ifdef CONFIG_CBE_RAS
567 HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance)
568#endif /* CONFIG_CBE_RAS */
548 STD_EXCEPTION_PSERIES(0x1700, altivec_assist) 569 STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
570#ifdef CONFIG_CBE_RAS
571 HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal)
572#endif /* CONFIG_CBE_RAS */
549 573
550 . = 0x3000 574 . = 0x3000
551 575
@@ -827,6 +851,11 @@ machine_check_common:
827#else 851#else
828 STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception) 852 STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception)
829#endif 853#endif
854#ifdef CONFIG_CBE_RAS
855 STD_EXCEPTION_COMMON(0x1200, cbe_system_error, .cbe_system_error_exception)
856 STD_EXCEPTION_COMMON(0x1600, cbe_maintenance, .cbe_maintenance_exception)
857 STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
858#endif /* CONFIG_CBE_RAS */
830 859
831/* 860/*
832 * Here we have detected that the kernel stack pointer is bad. 861 * Here we have detected that the kernel stack pointer is bad.
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 629023240ece..483455c5bb02 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -2105,3 +2105,46 @@ int prom_update_property(struct device_node *np,
2105 return 0; 2105 return 0;
2106} 2106}
2107 2107
2108
2109/* Find the device node for a given logical cpu number, also returns the cpu
2110 * local thread number (index in ibm,interrupt-server#s) if relevant and
2111 * asked for (non NULL)
2112 */
2113struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
2114{
2115 int hardid;
2116 struct device_node *np;
2117
2118 hardid = get_hard_smp_processor_id(cpu);
2119
2120 for_each_node_by_type(np, "cpu") {
2121 u32 *intserv;
2122 unsigned int plen, t;
2123
2124 /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
2125 * fallback to "reg" property and assume no threads
2126 */
2127 intserv = (u32 *)get_property(np, "ibm,ppc-interrupt-server#s",
2128 &plen);
2129 if (intserv == NULL) {
2130 u32 *reg = (u32 *)get_property(np, "reg", NULL);
2131 if (reg == NULL)
2132 continue;
2133 if (*reg == hardid) {
2134 if (thread)
2135 *thread = 0;
2136 return np;
2137 }
2138 } else {
2139 plen /= sizeof(u32);
2140 for (t = 0; t < plen; t++) {
2141 if (hardid == intserv[t]) {
2142 if (thread)
2143 *thread = t;
2144 return np;
2145 }
2146 }
2147 }
2148 }
2149 return NULL;
2150}
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 6a02d51086c8..00b83db2ce73 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -16,4 +16,8 @@ config SPUFS_MMAP
16 select MEMORY_HOTPLUG 16 select MEMORY_HOTPLUG
17 default y 17 default y
18 18
19config CBE_RAS
20 bool "RAS features for bare metal Cell BE"
21 default y
22
19endmenu 23endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index e570bad06394..6b11f6adca08 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,5 +1,6 @@
1obj-y += interrupt.o iommu.o setup.o spider-pic.o 1obj-y += interrupt.o iommu.o setup.o spider-pic.o
2obj-y += pervasive.o 2obj-y += cbe_regs.o pervasive.o
3obj-$(CONFIG_CBE_RAS) += ras.o
3 4
4obj-$(CONFIG_SMP) += smp.o 5obj-$(CONFIG_SMP) += smp.o
5obj-$(CONFIG_SPU_FS) += spu-base.o spufs/ 6obj-$(CONFIG_SPU_FS) += spu-base.o spufs/
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
new file mode 100644
index 000000000000..2dfde61c8412
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -0,0 +1,128 @@
1/*
2 * cbe_regs.c
3 *
4 * Accessor routines for the various MMIO register blocks of the CBE
5 *
6 * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
7 */
8
9
10#include <linux/config.h>
11#include <linux/percpu.h>
12#include <linux/types.h>
13
14#include <asm/io.h>
15#include <asm/pgtable.h>
16#include <asm/prom.h>
17#include <asm/ptrace.h>
18
19#include "cbe_regs.h"
20
21#define MAX_CBE 2
22
23/*
24 * Current implementation uses "cpu" nodes. We build our own mapping
25 * array of cpu numbers to cpu nodes locally for now to allow interrupt
26 * time code to have a fast path rather than call of_get_cpu_node(). If
27 * we implement cpu hotplug, we'll have to install an appropriate norifier
28 * in order to release references to the cpu going away
29 */
30static struct cbe_regs_map
31{
32 struct device_node *cpu_node;
33 struct cbe_pmd_regs __iomem *pmd_regs;
34 struct cbe_iic_regs __iomem *iic_regs;
35} cbe_regs_maps[MAX_CBE];
36static int cbe_regs_map_count;
37
38static struct cbe_thread_map
39{
40 struct device_node *cpu_node;
41 struct cbe_regs_map *regs;
42} cbe_thread_map[NR_CPUS];
43
44static struct cbe_regs_map *cbe_find_map(struct device_node *np)
45{
46 int i;
47
48 for (i = 0; i < cbe_regs_map_count; i++)
49 if (cbe_regs_maps[i].cpu_node == np)
50 return &cbe_regs_maps[i];
51 return NULL;
52}
53
54struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
55{
56 struct cbe_regs_map *map = cbe_find_map(np);
57 if (map == NULL)
58 return NULL;
59 return map->pmd_regs;
60}
61
62struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
63{
64 struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
65 if (map == NULL)
66 return NULL;
67 return map->pmd_regs;
68}
69
70
71struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
72{
73 struct cbe_regs_map *map = cbe_find_map(np);
74 if (map == NULL)
75 return NULL;
76 return map->iic_regs;
77}
78struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
79{
80 struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
81 if (map == NULL)
82 return NULL;
83 return map->iic_regs;
84}
85
86void __init cbe_regs_init(void)
87{
88 int i;
89 struct device_node *cpu;
90
91 /* Build local fast map of CPUs */
92 for_each_cpu(i)
93 cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
94
95 /* Find maps for each device tree CPU */
96 for_each_node_by_type(cpu, "cpu") {
97 struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
98
99 /* That hack must die die die ! */
100 struct address_prop {
101 unsigned long address;
102 unsigned int len;
103 } __attribute__((packed)) *prop;
104
105
106 if (cbe_regs_map_count > MAX_CBE) {
107 printk(KERN_ERR "cbe_regs: More BE chips than supported"
108 "!\n");
109 cbe_regs_map_count--;
110 return;
111 }
112 map->cpu_node = cpu;
113 for_each_cpu(i)
114 if (cbe_thread_map[i].cpu_node == cpu)
115 cbe_thread_map[i].regs = map;
116
117 prop = (struct address_prop *)get_property(cpu, "pervasive",
118 NULL);
119 if (prop != NULL)
120 map->pmd_regs = ioremap(prop->address, prop->len);
121
122 prop = (struct address_prop *)get_property(cpu, "iic",
123 NULL);
124 if (prop != NULL)
125 map->iic_regs = ioremap(prop->address, prop->len);
126 }
127}
128
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
new file mode 100644
index 000000000000..e76e4a6af5bc
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -0,0 +1,129 @@
1/*
2 * cbe_regs.h
3 *
4 * This file is intended to hold the various register definitions for CBE
5 * on-chip system devices (memory controller, IO controller, etc...)
6 *
7 * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
8 */
9
10#ifndef CBE_REGS_H
11#define CBE_REGS_H
12
13/*
14 *
15 * Some HID register definitions
16 *
17 */
18
19/* CBE specific HID0 bits */
20#define HID0_CBE_THERM_WAKEUP 0x0000020000000000ul
21#define HID0_CBE_SYSERR_WAKEUP 0x0000008000000000ul
22#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul
23#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul
24
25
26/*
27 *
28 * Pervasive unit register definitions
29 *
30 */
31
32struct cbe_pmd_regs {
33 u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
34
35 /* Thermal Sensor Registers */
36 u64 ts_ctsr1; /* 0x0800 */
37 u64 ts_ctsr2; /* 0x0808 */
38 u64 ts_mtsr1; /* 0x0810 */
39 u64 ts_mtsr2; /* 0x0818 */
40 u64 ts_itr1; /* 0x0820 */
41 u64 ts_itr2; /* 0x0828 */
42 u64 ts_gitr; /* 0x0830 */
43 u64 ts_isr; /* 0x0838 */
44 u64 ts_imr; /* 0x0840 */
45 u64 tm_cr1; /* 0x0848 */
46 u64 tm_cr2; /* 0x0850 */
47 u64 tm_simr; /* 0x0858 */
48 u64 tm_tpr; /* 0x0860 */
49 u64 tm_str1; /* 0x0868 */
50 u64 tm_str2; /* 0x0870 */
51 u64 tm_tsr; /* 0x0878 */
52
53 /* Power Management */
54 u64 pm_control; /* 0x0880 */
55#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000
56 u64 pm_status; /* 0x0888 */
57
58 /* Time Base Register */
59 u64 tbr; /* 0x0890 */
60
61 u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */
62
63 /* Fault Isolation Registers */
64 u64 checkstop_fir; /* 0x0c00 */
65 u64 recoverable_fir;
66 u64 spec_att_mchk_fir;
67 u64 fir_mode_reg;
68 u64 fir_enable_mask;
69
70 u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */
71};
72
73extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np);
74extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu);
75
76/*
77 *
78 * IIC unit register definitions
79 *
80 */
81
82struct cbe_iic_pending_bits {
83 u32 data;
84 u8 flags;
85 u8 class;
86 u8 source;
87 u8 prio;
88};
89
90#define CBE_IIC_IRQ_VALID 0x80
91#define CBE_IIC_IRQ_IPI 0x40
92
93struct cbe_iic_thread_regs {
94 struct cbe_iic_pending_bits pending;
95 struct cbe_iic_pending_bits pending_destr;
96 u64 generate;
97 u64 prio;
98};
99
100struct cbe_iic_regs {
101 u8 pad_0x0000_0x0400[0x0400 - 0x0000]; /* 0x0000 */
102
103 /* IIC interrupt registers */
104 struct cbe_iic_thread_regs thread[2]; /* 0x0400 */
105 u64 iic_ir; /* 0x0440 */
106 u64 iic_is; /* 0x0448 */
107
108 u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */
109
110 /* IOC FIR */
111 u64 ioc_fir_reset; /* 0x0500 */
112 u64 ioc_fir_set;
113 u64 ioc_checkstop_enable;
114 u64 ioc_fir_error_mask;
115 u64 ioc_syserr_enable;
116 u64 ioc_fir;
117
118 u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */
119};
120
121extern struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np);
122extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
123
124
125/* Init this module early */
126extern void cbe_regs_init(void);
127
128
129#endif /* CBE_REGS_H */
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 978be1c30c1b..0a707bcabef6 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -33,29 +33,10 @@
33#include <asm/ptrace.h> 33#include <asm/ptrace.h>
34 34
35#include "interrupt.h" 35#include "interrupt.h"
36 36#include "cbe_regs.h"
37struct iic_pending_bits {
38 u32 data;
39 u8 flags;
40 u8 class;
41 u8 source;
42 u8 prio;
43};
44
45enum iic_pending_flags {
46 IIC_VALID = 0x80,
47 IIC_IPI = 0x40,
48};
49
50struct iic_regs {
51 struct iic_pending_bits pending;
52 struct iic_pending_bits pending_destr;
53 u64 generate;
54 u64 prio;
55};
56 37
57struct iic { 38struct iic {
58 struct iic_regs __iomem *regs; 39 struct cbe_iic_thread_regs __iomem *regs;
59 u8 target_id; 40 u8 target_id;
60}; 41};
61 42
@@ -115,7 +96,7 @@ static struct hw_interrupt_type iic_pic = {
115 .end = iic_end, 96 .end = iic_end,
116}; 97};
117 98
118static int iic_external_get_irq(struct iic_pending_bits pending) 99static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
119{ 100{
120 int irq; 101 int irq;
121 unsigned char node, unit; 102 unsigned char node, unit;
@@ -168,15 +149,15 @@ int iic_get_irq(struct pt_regs *regs)
168{ 149{
169 struct iic *iic; 150 struct iic *iic;
170 int irq; 151 int irq;
171 struct iic_pending_bits pending; 152 struct cbe_iic_pending_bits pending;
172 153
173 iic = &__get_cpu_var(iic); 154 iic = &__get_cpu_var(iic);
174 *(unsigned long *) &pending = 155 *(unsigned long *) &pending =
175 in_be64((unsigned long __iomem *) &iic->regs->pending_destr); 156 in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
176 157
177 irq = -1; 158 irq = -1;
178 if (pending.flags & IIC_VALID) { 159 if (pending.flags & CBE_IIC_IRQ_VALID) {
179 if (pending.flags & IIC_IPI) { 160 if (pending.flags & CBE_IIC_IRQ_IPI) {
180 irq = IIC_IPI_OFFSET + (pending.prio >> 4); 161 irq = IIC_IPI_OFFSET + (pending.prio >> 4);
181/* 162/*
182 if (irq > 0x80) 163 if (irq > 0x80)
@@ -226,7 +207,7 @@ static int setup_iic_hardcoded(void)
226 regs += 0x20; 207 regs += 0x20;
227 208
228 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); 209 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
229 iic->regs = ioremap(regs, sizeof(struct iic_regs)); 210 iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
230 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); 211 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
231 } 212 }
232 213
@@ -267,12 +248,12 @@ static int setup_iic(void)
267 } 248 }
268 249
269 iic = &per_cpu(iic, np[0]); 250 iic = &per_cpu(iic, np[0]);
270 iic->regs = ioremap(regs[0], sizeof(struct iic_regs)); 251 iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
271 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); 252 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
272 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); 253 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
273 254
274 iic = &per_cpu(iic, np[1]); 255 iic = &per_cpu(iic, np[1]);
275 iic->regs = ioremap(regs[2], sizeof(struct iic_regs)); 256 iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
276 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); 257 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
277 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); 258 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
278 259
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index 7eed8c624517..695ac4e1617e 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -37,36 +37,28 @@
37#include <asm/reg.h> 37#include <asm/reg.h>
38 38
39#include "pervasive.h" 39#include "pervasive.h"
40#include "cbe_regs.h"
40 41
41static DEFINE_SPINLOCK(cbe_pervasive_lock); 42static DEFINE_SPINLOCK(cbe_pervasive_lock);
42struct cbe_pervasive {
43 struct pmd_regs __iomem *regs;
44 unsigned int thread;
45};
46
47/* can't use per_cpu from setup_arch */
48static struct cbe_pervasive cbe_pervasive[NR_CPUS];
49 43
50static void __init cbe_enable_pause_zero(void) 44static void __init cbe_enable_pause_zero(void)
51{ 45{
52 unsigned long thread_switch_control; 46 unsigned long thread_switch_control;
53 unsigned long temp_register; 47 unsigned long temp_register;
54 struct cbe_pervasive *p; 48 struct cbe_pmd_regs __iomem *pregs;
55 int thread;
56 49
57 spin_lock_irq(&cbe_pervasive_lock); 50 spin_lock_irq(&cbe_pervasive_lock);
58 p = &cbe_pervasive[smp_processor_id()]; 51 pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
59 52 if (pregs == NULL)
60 if (!cbe_pervasive->regs)
61 goto out; 53 goto out;
62 54
63 pr_debug("Power Management: CPU %d\n", smp_processor_id()); 55 pr_debug("Power Management: CPU %d\n", smp_processor_id());
64 56
65 /* Enable Pause(0) control bit */ 57 /* Enable Pause(0) control bit */
66 temp_register = in_be64(&p->regs->pm_control); 58 temp_register = in_be64(&pregs->pm_control);
67 59
68 out_be64(&p->regs->pm_control, 60 out_be64(&pregs->pm_control,
69 temp_register|PMD_PAUSE_ZERO_CONTROL); 61 temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
70 62
71 /* Enable DEC and EE interrupt request */ 63 /* Enable DEC and EE interrupt request */
72 thread_switch_control = mfspr(SPRN_TSC_CELL); 64 thread_switch_control = mfspr(SPRN_TSC_CELL);
@@ -75,25 +67,16 @@ static void __init cbe_enable_pause_zero(void)
75 switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { 67 switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
76 case CTRL_CT0: 68 case CTRL_CT0:
77 thread_switch_control |= TSC_CELL_DEC_ENABLE_0; 69 thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
78 thread = 0;
79 break; 70 break;
80 case CTRL_CT1: 71 case CTRL_CT1:
81 thread_switch_control |= TSC_CELL_DEC_ENABLE_1; 72 thread_switch_control |= TSC_CELL_DEC_ENABLE_1;
82 thread = 1;
83 break; 73 break;
84 default: 74 default:
85 printk(KERN_WARNING "%s: unknown configuration\n", 75 printk(KERN_WARNING "%s: unknown configuration\n",
86 __FUNCTION__); 76 __FUNCTION__);
87 thread = -1;
88 break; 77 break;
89 } 78 }
90 79
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); 80 mtspr(SPRN_TSC_CELL, thread_switch_control);
98 81
99out: 82out:
@@ -104,6 +87,11 @@ static void cbe_idle(void)
104{ 87{
105 unsigned long ctrl; 88 unsigned long ctrl;
106 89
90 /* Why do we do that on every idle ? Couldn't that be done once for
91 * all or do we lose the state some way ? Also, the pm_control
92 * register setting, that can't be set once at boot ? We really want
93 * to move that away in order to implement a simple powersave
94 */
107 cbe_enable_pause_zero(); 95 cbe_enable_pause_zero();
108 96
109 while (1) { 97 while (1) {
@@ -152,8 +140,15 @@ static int cbe_system_reset_exception(struct pt_regs *regs)
152 timer_interrupt(regs); 140 timer_interrupt(regs);
153 break; 141 break;
154 case SRR1_WAKEMT: 142 case SRR1_WAKEMT:
155 /* no action required */
156 break; 143 break;
144#ifdef CONFIG_CBE_RAS
145 case SRR1_WAKESYSERR:
146 cbe_system_error_exception(regs);
147 break;
148 case SRR1_WAKETHERM:
149 cbe_thermal_exception(regs);
150 break;
151#endif /* CONFIG_CBE_RAS */
157 default: 152 default:
158 /* do system reset */ 153 /* do system reset */
159 return 0; 154 return 0;
@@ -162,68 +157,11 @@ static int cbe_system_reset_exception(struct pt_regs *regs)
162 return 1; 157 return 1;
163} 158}
164 159
165static int __init cbe_find_pmd_mmio(int cpu, struct cbe_pervasive *p) 160void __init cbe_pervasive_init(void)
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
199found:
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);
207 p->thread = thread;
208 return 0;
209}
210
211void __init cell_pervasive_init(void)
212{ 161{
213 struct cbe_pervasive *p;
214 int cpu;
215 int ret;
216
217 if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) 162 if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
218 return; 163 return;
219 164
220 for_each_possible_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; 165 ppc_md.idle_loop = cbe_idle;
228 ppc_md.system_reset_exception = cbe_system_reset_exception; 166 ppc_md.system_reset_exception = cbe_system_reset_exception;
229} 167}
diff --git a/arch/powerpc/platforms/cell/pervasive.h b/arch/powerpc/platforms/cell/pervasive.h
index da1fb85ca3e8..7b50947f8044 100644
--- a/arch/powerpc/platforms/cell/pervasive.h
+++ b/arch/powerpc/platforms/cell/pervasive.h
@@ -25,38 +25,9 @@
25#ifndef PERVASIVE_H 25#ifndef PERVASIVE_H
26#define PERVASIVE_H 26#define PERVASIVE_H
27 27
28struct pmd_regs { 28extern void cbe_pervasive_init(void);
29 u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */ 29extern void cbe_system_error_exception(struct pt_regs *regs);
30 30extern void cbe_maintenance_exception(struct pt_regs *regs);
31 /* Thermal Sensor Registers */ 31extern void cbe_thermal_exception(struct pt_regs *regs);
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
60void __init cell_pervasive_init(void);
61 32
62#endif 33#endif
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
new file mode 100644
index 000000000000..033ad6e2827b
--- /dev/null
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -0,0 +1,112 @@
1#define DEBUG
2
3#include <linux/config.h>
4#include <linux/types.h>
5#include <linux/kernel.h>
6#include <linux/smp.h>
7
8#include <asm/reg.h>
9#include <asm/io.h>
10#include <asm/prom.h>
11#include <asm/machdep.h>
12
13#include "ras.h"
14#include "cbe_regs.h"
15
16
17static void dump_fir(int cpu)
18{
19 struct cbe_pmd_regs __iomem *pregs = cbe_get_cpu_pmd_regs(cpu);
20 struct cbe_iic_regs __iomem *iregs = cbe_get_cpu_iic_regs(cpu);
21
22 if (pregs == NULL)
23 return;
24
25 /* Todo: do some nicer parsing of bits and based on them go down
26 * to other sub-units FIRs and not only IIC
27 */
28 printk(KERN_ERR "Global Checkstop FIR : 0x%016lx\n",
29 in_be64(&pregs->checkstop_fir));
30 printk(KERN_ERR "Global Recoverable FIR : 0x%016lx\n",
31 in_be64(&pregs->checkstop_fir));
32 printk(KERN_ERR "Global MachineCheck FIR : 0x%016lx\n",
33 in_be64(&pregs->spec_att_mchk_fir));
34
35 if (iregs == NULL)
36 return;
37 printk(KERN_ERR "IOC FIR : 0x%016lx\n",
38 in_be64(&iregs->ioc_fir));
39
40}
41
42void cbe_system_error_exception(struct pt_regs *regs)
43{
44 int cpu = smp_processor_id();
45
46 printk(KERN_ERR "System Error Interrupt on CPU %d !\n", cpu);
47 dump_fir(cpu);
48 dump_stack();
49}
50
51void cbe_maintenance_exception(struct pt_regs *regs)
52{
53 int cpu = smp_processor_id();
54
55 /*
56 * Nothing implemented for the maintenance interrupt at this point
57 */
58
59 printk(KERN_ERR "Unhandled Maintenance interrupt on CPU %d !\n", cpu);
60 dump_stack();
61}
62
63void cbe_thermal_exception(struct pt_regs *regs)
64{
65 int cpu = smp_processor_id();
66
67 /*
68 * Nothing implemented for the thermal interrupt at this point
69 */
70
71 printk(KERN_ERR "Unhandled Thermal interrupt on CPU %d !\n", cpu);
72 dump_stack();
73}
74
75static int cbe_machine_check_handler(struct pt_regs *regs)
76{
77 int cpu = smp_processor_id();
78
79 printk(KERN_ERR "Machine Check Interrupt on CPU %d !\n", cpu);
80 dump_fir(cpu);
81
82 /* No recovery from this code now, lets continue */
83 return 0;
84}
85
86void __init cbe_ras_init(void)
87{
88 unsigned long hid0;
89
90 /*
91 * Enable System Error & thermal interrupts and wakeup conditions
92 */
93
94 hid0 = mfspr(SPRN_HID0);
95 hid0 |= HID0_CBE_THERM_INT_EN | HID0_CBE_THERM_WAKEUP |
96 HID0_CBE_SYSERR_INT_EN | HID0_CBE_SYSERR_WAKEUP;
97 mtspr(SPRN_HID0, hid0);
98 mb();
99
100 /*
101 * Install machine check handler. Leave setting of precise mode to
102 * what the firmware did for now
103 */
104 ppc_md.machine_check_exception = cbe_machine_check_handler;
105 mb();
106
107 /*
108 * For now, we assume that IOC_FIR is already set to forward some
109 * error conditions to the System Error handler. If that is not true
110 * then it will have to be fixed up here.
111 */
112}
diff --git a/arch/powerpc/platforms/cell/ras.h b/arch/powerpc/platforms/cell/ras.h
new file mode 100644
index 000000000000..eb7ee54c82a0
--- /dev/null
+++ b/arch/powerpc/platforms/cell/ras.h
@@ -0,0 +1,9 @@
1#ifndef RAS_H
2#define RAS_H
3
4extern void cbe_system_error_exception(struct pt_regs *regs);
5extern void cbe_maintenance_exception(struct pt_regs *regs);
6extern void cbe_thermal_exception(struct pt_regs *regs);
7extern void cbe_ras_init(void);
8
9#endif /* RAS_H */
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fd3e5609e3e0..eb8ab9bbf744 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -52,7 +52,9 @@
52 52
53#include "interrupt.h" 53#include "interrupt.h"
54#include "iommu.h" 54#include "iommu.h"
55#include "cbe_regs.h"
55#include "pervasive.h" 56#include "pervasive.h"
57#include "ras.h"
56 58
57#ifdef DEBUG 59#ifdef DEBUG
58#define DBG(fmt...) udbg_printf(fmt) 60#define DBG(fmt...) udbg_printf(fmt)
@@ -82,6 +84,12 @@ static void __init cell_setup_arch(void)
82 ppc_md.init_IRQ = iic_init_IRQ; 84 ppc_md.init_IRQ = iic_init_IRQ;
83 ppc_md.get_irq = iic_get_irq; 85 ppc_md.get_irq = iic_get_irq;
84 86
87 cbe_regs_init();
88
89#ifdef CONFIG_CBE_RAS
90 cbe_ras_init();
91#endif
92
85#ifdef CONFIG_SMP 93#ifdef CONFIG_SMP
86 smp_init_cell(); 94 smp_init_cell();
87#endif 95#endif
@@ -98,7 +106,7 @@ static void __init cell_setup_arch(void)
98 init_pci_config_tokens(); 106 init_pci_config_tokens();
99 find_and_init_phbs(); 107 find_and_init_phbs();
100 spider_init_IRQ(); 108 spider_init_IRQ();
101 cell_pervasive_init(); 109 cbe_pervasive_init();
102#ifdef CONFIG_DUMMY_CONSOLE 110#ifdef CONFIG_DUMMY_CONSOLE
103 conswitchp = &dummy_con; 111 conswitchp = &dummy_con;
104#endif 112#endif
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index c79d58ab7441..8bdcd5178302 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -238,5 +238,8 @@ void of_parse_dma_window(struct device_node *dn, unsigned char *dma_window_prop,
238 238
239extern void kdump_move_device_tree(void); 239extern void kdump_move_device_tree(void);
240 240
241/* CPU OF node matching */
242struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
243
241#endif /* __KERNEL__ */ 244#endif /* __KERNEL__ */
242#endif /* _POWERPC_PROM_H */ 245#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index f2ed7577aa35..cf73475a0c69 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -386,6 +386,8 @@
386#define SRR1_WAKEMT 0x00280000 /* mtctrl */ 386#define SRR1_WAKEMT 0x00280000 /* mtctrl */
387#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ 387#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
388#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ 388#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */
389#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
390#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
389 391
390#ifndef SPRN_SVR 392#ifndef SPRN_SVR
391#define SPRN_SVR 0x11E /* System Version Register */ 393#define SPRN_SVR 0x11E /* System Version Register */