aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/configs/cell_defconfig57
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c1
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c81
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c165
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h5
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c177
-rw-r--r--arch/powerpc/platforms/cell/ras.c160
-rw-r--r--arch/powerpc/sysdev/pmi.c29
-rw-r--r--include/asm-powerpc/cell-pmu.h5
-rw-r--r--include/asm-powerpc/prom.h11
10 files changed, 581 insertions, 110 deletions
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index cf7e316ad4f6..6061e5f7696e 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.21-rc3 3# Linux kernel version: 2.6.21-rc6
4# Fri Mar 9 23:34:53 2007 4# Mon Apr 23 20:46:48 2007
5# 5#
6CONFIG_PPC64=y 6CONFIG_PPC64=y
7CONFIG_64BIT=y 7CONFIG_64BIT=y
@@ -139,11 +139,31 @@ CONFIG_PPC_MULTIPLATFORM=y
139# CONFIG_PPC_PMAC is not set 139# CONFIG_PPC_PMAC is not set
140# CONFIG_PPC_MAPLE is not set 140# CONFIG_PPC_MAPLE is not set
141# CONFIG_PPC_PASEMI is not set 141# CONFIG_PPC_PASEMI is not set
142CONFIG_PPC_CELLEB=y
143CONFIG_PPC_PS3=y
144
145#
146# PS3 Platform Options
147#
148# CONFIG_PS3_ADVANCED is not set
149CONFIG_PS3_HTAB_SIZE=20
150# CONFIG_PS3_DYNAMIC_DMA is not set
151CONFIG_PS3_USE_LPAR_ADDR=y
152CONFIG_PS3_VUART=y
153CONFIG_PS3_PS3AV=y
154CONFIG_PS3_SYS_MANAGER=y
142CONFIG_PPC_CELL=y 155CONFIG_PPC_CELL=y
143CONFIG_PPC_CELL_NATIVE=y 156CONFIG_PPC_CELL_NATIVE=y
144CONFIG_PPC_IBM_CELL_BLADE=y 157CONFIG_PPC_IBM_CELL_BLADE=y
145CONFIG_PPC_PS3=y 158
146CONFIG_PPC_CELLEB=y 159#
160# Cell Broadband Engine options
161#
162CONFIG_SPU_FS=m
163CONFIG_SPU_BASE=y
164CONFIG_CBE_RAS=y
165CONFIG_CBE_THERM=m
166CONFIG_CBE_CPUFREQ=m
147CONFIG_PPC_NATIVE=y 167CONFIG_PPC_NATIVE=y
148CONFIG_UDBG_RTAS_CONSOLE=y 168CONFIG_UDBG_RTAS_CONSOLE=y
149CONFIG_PPC_UDBG_BEAT=y 169CONFIG_PPC_UDBG_BEAT=y
@@ -175,26 +195,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
175CONFIG_MPIC=y 195CONFIG_MPIC=y
176 196
177# 197#
178# Cell Broadband Engine options
179#
180CONFIG_SPU_FS=m
181CONFIG_SPU_BASE=y
182CONFIG_CBE_RAS=y
183CONFIG_CBE_THERM=m
184CONFIG_CBE_CPUFREQ=m
185
186#
187# PS3 Platform Options
188#
189# CONFIG_PS3_ADVANCED is not set
190CONFIG_PS3_HTAB_SIZE=20
191# CONFIG_PS3_DYNAMIC_DMA is not set
192CONFIG_PS3_USE_LPAR_ADDR=y
193CONFIG_PS3_VUART=y
194CONFIG_PS3_PS3AV=y
195CONFIG_PS3_SYS_MANAGER=y
196
197#
198# Kernel options 198# Kernel options
199# 199#
200# CONFIG_HZ_100 is not set 200# CONFIG_HZ_100 is not set
@@ -534,7 +534,6 @@ CONFIG_BLK_DEV_GENERIC=y
534# CONFIG_BLK_DEV_OPTI621 is not set 534# CONFIG_BLK_DEV_OPTI621 is not set
535CONFIG_BLK_DEV_IDEDMA_PCI=y 535CONFIG_BLK_DEV_IDEDMA_PCI=y
536# CONFIG_BLK_DEV_IDEDMA_FORCED is not set 536# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
537CONFIG_IDEDMA_PCI_AUTO=y
538# CONFIG_IDEDMA_ONLYDISK is not set 537# CONFIG_IDEDMA_ONLYDISK is not set
539CONFIG_BLK_DEV_AEC62XX=y 538CONFIG_BLK_DEV_AEC62XX=y
540# CONFIG_BLK_DEV_ALI15X3 is not set 539# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -561,11 +560,10 @@ CONFIG_BLK_DEV_SIIMAGE=y
561# CONFIG_BLK_DEV_TRM290 is not set 560# CONFIG_BLK_DEV_TRM290 is not set
562# CONFIG_BLK_DEV_VIA82CXXX is not set 561# CONFIG_BLK_DEV_VIA82CXXX is not set
563# CONFIG_BLK_DEV_TC86C001 is not set 562# CONFIG_BLK_DEV_TC86C001 is not set
564CONFIG_BLK_DEV_IDE_CELLEB=y 563CONFIG_BLK_DEV_CELLEB=y
565# CONFIG_IDE_ARM is not set 564# CONFIG_IDE_ARM is not set
566CONFIG_BLK_DEV_IDEDMA=y 565CONFIG_BLK_DEV_IDEDMA=y
567# CONFIG_IDEDMA_IVB is not set 566# CONFIG_IDEDMA_IVB is not set
568CONFIG_IDEDMA_AUTO=y
569# CONFIG_BLK_DEV_HD is not set 567# CONFIG_BLK_DEV_HD is not set
570 568
571# 569#
@@ -937,7 +935,7 @@ CONFIG_UNIX98_PTYS=y
937# CONFIG_LEGACY_PTYS is not set 935# CONFIG_LEGACY_PTYS is not set
938CONFIG_HVC_DRIVER=y 936CONFIG_HVC_DRIVER=y
939CONFIG_HVC_RTAS=y 937CONFIG_HVC_RTAS=y
940# CONFIG_HVC_BEAT is not set 938CONFIG_HVC_BEAT=y
941 939
942# 940#
943# IPMI 941# IPMI
@@ -1482,6 +1480,8 @@ CONFIG_NLS_ISO8859_15=m
1482# Distributed Lock Manager 1480# Distributed Lock Manager
1483# 1481#
1484# CONFIG_DLM is not set 1482# CONFIG_DLM is not set
1483# CONFIG_UCC_SLOW is not set
1484# CONFIG_UCC_FAST is not set
1485 1485
1486# 1486#
1487# Library routines 1487# Library routines
@@ -1540,6 +1540,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
1540# CONFIG_FAULT_INJECTION is not set 1540# CONFIG_FAULT_INJECTION is not set
1541# CONFIG_DEBUG_STACKOVERFLOW is not set 1541# CONFIG_DEBUG_STACKOVERFLOW is not set
1542# CONFIG_DEBUG_STACK_USAGE is not set 1542# CONFIG_DEBUG_STACK_USAGE is not set
1543# CONFIG_DEBUG_PAGEALLOC is not set
1543CONFIG_DEBUGGER=y 1544CONFIG_DEBUGGER=y
1544CONFIG_XMON=y 1545CONFIG_XMON=y
1545CONFIG_XMON_DEFAULT=y 1546CONFIG_XMON_DEFAULT=y
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index e08e1d7b3dc5..fb999e3e9f21 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -37,6 +37,7 @@
37#include <asm/system.h> 37#include <asm/system.h>
38 38
39#include "../platforms/cell/interrupt.h" 39#include "../platforms/cell/interrupt.h"
40#include "../platforms/cell/cbe_regs.h"
40 41
41#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ 42#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */
42#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying 43#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index 9c5d63b7e76c..4495973bff59 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -28,6 +28,8 @@
28#include <asm/processor.h> 28#include <asm/processor.h>
29#include <asm/prom.h> 29#include <asm/prom.h>
30#include <asm/time.h> 30#include <asm/time.h>
31#include <asm/pmi.h>
32#include <asm/of_platform.h>
31 33
32#include "cbe_regs.h" 34#include "cbe_regs.h"
33 35
@@ -68,6 +70,38 @@ static u64 MIC_Slow_Next_Timer_table[] = {
68 * hardware specific functions 70 * hardware specific functions
69 */ 71 */
70 72
73static struct of_device *pmi_dev;
74
75static int set_pmode_pmi(int cpu, unsigned int pmode)
76{
77 int ret;
78 pmi_message_t pmi_msg;
79#ifdef DEBUG
80 u64 time;
81#endif
82
83 pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
84 pmi_msg.data1 = cbe_cpu_to_node(cpu);
85 pmi_msg.data2 = pmode;
86
87#ifdef DEBUG
88 time = (u64) get_cycles();
89#endif
90
91 pmi_send_message(pmi_dev, pmi_msg);
92 ret = pmi_msg.data2;
93
94 pr_debug("PMI returned slow mode %d\n", ret);
95
96#ifdef DEBUG
97 time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
98 time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
99 pr_debug("had to wait %lu ns for a transition\n", time);
100#endif
101 return ret;
102}
103
104
71static int get_pmode(int cpu) 105static int get_pmode(int cpu)
72{ 106{
73 int ret; 107 int ret;
@@ -79,7 +113,7 @@ static int get_pmode(int cpu)
79 return ret; 113 return ret;
80} 114}
81 115
82static int set_pmode(int cpu, unsigned int pmode) 116static int set_pmode_reg(int cpu, unsigned int pmode)
83{ 117{
84 struct cbe_pmd_regs __iomem *pmd_regs; 118 struct cbe_pmd_regs __iomem *pmd_regs;
85 struct cbe_mic_tm_regs __iomem *mic_tm_regs; 119 struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,6 +154,39 @@ static int set_pmode(int cpu, unsigned int pmode)
120 return 0; 154 return 0;
121} 155}
122 156
157static int set_pmode(int cpu, unsigned int slow_mode) {
158 if(pmi_dev)
159 return set_pmode_pmi(cpu, slow_mode);
160 else
161 return set_pmode_reg(cpu, slow_mode);
162}
163
164static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
165{
166 struct cpufreq_policy policy;
167 u8 cpu;
168 u8 cbe_pmode_new;
169
170 BUG_ON (pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
171
172 cpu = cbe_node_to_cpu(pmi_msg.data1);
173 cbe_pmode_new = pmi_msg.data2;
174
175 cpufreq_get_policy(&policy, cpu);
176
177 policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
178 policy.min = min(policy.min, policy.max);
179
180 pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
181 cpufreq_set_policy(&policy);
182}
183
184static struct pmi_handler cbe_pmi_handler = {
185 .type = PMI_TYPE_FREQ_CHANGE,
186 .handle_pmi_message = cbe_cpufreq_handle_pmi,
187};
188
189
123/* 190/*
124 * cpufreq functions 191 * cpufreq functions
125 */ 192 */
@@ -234,11 +301,23 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
234 301
235static int __init cbe_cpufreq_init(void) 302static int __init cbe_cpufreq_init(void)
236{ 303{
304 struct device_node *np;
305
306 np = of_find_node_by_type(NULL, "ibm,pmi");
307
308 pmi_dev = of_find_device_by_node(np);
309
310 if (pmi_dev)
311 pmi_register_handler(pmi_dev, &cbe_pmi_handler);
312
237 return cpufreq_register_driver(&cbe_cpufreq_driver); 313 return cpufreq_register_driver(&cbe_cpufreq_driver);
238} 314}
239 315
240static void __exit cbe_cpufreq_exit(void) 316static void __exit cbe_cpufreq_exit(void)
241{ 317{
318 if(pmi_dev)
319 pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
320
242 cpufreq_unregister_driver(&cbe_cpufreq_driver); 321 cpufreq_unregister_driver(&cbe_cpufreq_driver);
243} 322}
244 323
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 7c94af4ac439..12c9674b4b1f 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -14,6 +14,8 @@
14#include <asm/pgtable.h> 14#include <asm/pgtable.h>
15#include <asm/prom.h> 15#include <asm/prom.h>
16#include <asm/ptrace.h> 16#include <asm/ptrace.h>
17#include <asm/of_device.h>
18#include <asm/of_platform.h>
17 19
18#include "cbe_regs.h" 20#include "cbe_regs.h"
19 21
@@ -27,6 +29,7 @@
27static struct cbe_regs_map 29static struct cbe_regs_map
28{ 30{
29 struct device_node *cpu_node; 31 struct device_node *cpu_node;
32 struct device_node *be_node;
30 struct cbe_pmd_regs __iomem *pmd_regs; 33 struct cbe_pmd_regs __iomem *pmd_regs;
31 struct cbe_iic_regs __iomem *iic_regs; 34 struct cbe_iic_regs __iomem *iic_regs;
32 struct cbe_mic_tm_regs __iomem *mic_tm_regs; 35 struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -37,30 +40,43 @@ static int cbe_regs_map_count;
37static struct cbe_thread_map 40static struct cbe_thread_map
38{ 41{
39 struct device_node *cpu_node; 42 struct device_node *cpu_node;
43 struct device_node *be_node;
40 struct cbe_regs_map *regs; 44 struct cbe_regs_map *regs;
45 unsigned int thread_id;
46 unsigned int cbe_id;
41} cbe_thread_map[NR_CPUS]; 47} cbe_thread_map[NR_CPUS];
42 48
49static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
50static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
51
43static struct cbe_regs_map *cbe_find_map(struct device_node *np) 52static struct cbe_regs_map *cbe_find_map(struct device_node *np)
44{ 53{
45 int i; 54 int i;
46 struct device_node *tmp_np; 55 struct device_node *tmp_np;
47 56
48 if (strcasecmp(np->type, "spe") == 0) { 57 if (strcasecmp(np->type, "spe")) {
49 if (np->data == NULL) { 58 for (i = 0; i < cbe_regs_map_count; i++)
50 /* walk up path until cpu node was found */ 59 if (cbe_regs_maps[i].cpu_node == np ||
51 tmp_np = np->parent; 60 cbe_regs_maps[i].be_node == np)
52 while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0) 61 return &cbe_regs_maps[i];
53 tmp_np = tmp_np->parent; 62 return NULL;
63 }
54 64
55 np->data = cbe_find_map(tmp_np); 65 if (np->data)
56 }
57 return np->data; 66 return np->data;
58 }
59 67
60 for (i = 0; i < cbe_regs_map_count; i++) 68 /* walk up path until cpu or be node was found */
61 if (cbe_regs_maps[i].cpu_node == np) 69 tmp_np = np;
62 return &cbe_regs_maps[i]; 70 do {
63 return NULL; 71 tmp_np = tmp_np->parent;
72 /* on a correct devicetree we wont get up to root */
73 BUG_ON(!tmp_np);
74 } while (strcasecmp(tmp_np->type, "cpu") &&
75 strcasecmp(tmp_np->type, "be"));
76
77 np->data = cbe_find_map(tmp_np);
78
79 return np->data;
64} 80}
65 81
66struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np) 82struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
@@ -130,49 +146,69 @@ struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
130} 146}
131EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs); 147EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
132 148
133/* FIXME
134 * This is little more than a stub at the moment. It should be
135 * fleshed out so that it works for both SMT and non-SMT, no
136 * matter if the passed cpu is odd or even.
137 * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
138 * For SMT disabled, returns 0 for all cpus.
139 */
140u32 cbe_get_hw_thread_id(int cpu) 149u32 cbe_get_hw_thread_id(int cpu)
141{ 150{
142 return (cpu & 1); 151 return cbe_thread_map[cpu].thread_id;
143} 152}
144EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id); 153EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
145 154
146void __init cbe_regs_init(void) 155u32 cbe_cpu_to_node(int cpu)
147{ 156{
148 int i; 157 return cbe_thread_map[cpu].cbe_id;
149 struct device_node *cpu; 158}
159EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
150 160
151 /* Build local fast map of CPUs */ 161u32 cbe_node_to_cpu(int node)
152 for_each_possible_cpu(i) 162{
153 cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL); 163 return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
164}
165EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
154 166
155 /* Find maps for each device tree CPU */ 167static struct device_node *cbe_get_be_node(int cpu_id)
156 for_each_node_by_type(cpu, "cpu") { 168{
157 struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++]; 169 struct device_node *np;
170
171 for_each_node_by_type (np, "be") {
172 int len,i;
173 const phandle *cpu_handle;
174
175 cpu_handle = of_get_property(np, "cpus", &len);
176
177 for (i=0; i<len; i++)
178 if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
179 return np;
180 }
181
182 return NULL;
183}
184
185void __init cbe_fill_regs_map(struct cbe_regs_map *map)
186{
187 if(map->be_node) {
188 struct device_node *be, *np;
189
190 be = map->be_node;
158 191
192 for_each_node_by_type(np, "pervasive")
193 if (of_get_parent(np) == be)
194 map->pmd_regs = of_iomap(np, 0);
195
196 for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller")
197 if (of_get_parent(np) == be)
198 map->iic_regs = of_iomap(np, 2);
199
200 for_each_node_by_type(np, "mic-tm")
201 if (of_get_parent(np) == be)
202 map->mic_tm_regs = of_iomap(np, 0);
203 } else {
204 struct device_node *cpu;
159 /* That hack must die die die ! */ 205 /* That hack must die die die ! */
160 const struct address_prop { 206 const struct address_prop {
161 unsigned long address; 207 unsigned long address;
162 unsigned int len; 208 unsigned int len;
163 } __attribute__((packed)) *prop; 209 } __attribute__((packed)) *prop;
164 210
165 211 cpu = map->cpu_node;
166 if (cbe_regs_map_count > MAX_CBE) {
167 printk(KERN_ERR "cbe_regs: More BE chips than supported"
168 "!\n");
169 cbe_regs_map_count--;
170 return;
171 }
172 map->cpu_node = cpu;
173 for_each_possible_cpu(i)
174 if (cbe_thread_map[i].cpu_node == cpu)
175 cbe_thread_map[i].regs = map;
176 212
177 prop = of_get_property(cpu, "pervasive", NULL); 213 prop = of_get_property(cpu, "pervasive", NULL);
178 if (prop != NULL) 214 if (prop != NULL)
@@ -188,3 +224,50 @@ void __init cbe_regs_init(void)
188 } 224 }
189} 225}
190 226
227
228void __init cbe_regs_init(void)
229{
230 int i;
231 unsigned int thread_id;
232 struct device_node *cpu;
233
234 /* Build local fast map of CPUs */
235 for_each_possible_cpu(i) {
236 cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
237 cbe_thread_map[i].be_node = cbe_get_be_node(i);
238 cbe_thread_map[i].thread_id = thread_id;
239 }
240
241 /* Find maps for each device tree CPU */
242 for_each_node_by_type(cpu, "cpu") {
243 struct cbe_regs_map *map;
244 unsigned int cbe_id;
245
246 cbe_id = cbe_regs_map_count++;
247 map = &cbe_regs_maps[cbe_id];
248
249 if (cbe_regs_map_count > MAX_CBE) {
250 printk(KERN_ERR "cbe_regs: More BE chips than supported"
251 "!\n");
252 cbe_regs_map_count--;
253 return;
254 }
255 map->cpu_node = cpu;
256
257 for_each_possible_cpu(i) {
258 struct cbe_thread_map *thread = &cbe_thread_map[i];
259
260 if (thread->cpu_node == cpu) {
261 thread->regs = map;
262 thread->cbe_id = cbe_id;
263 map->be_node = thread->be_node;
264 cpu_set(i, cbe_local_mask[cbe_id]);
265 if(thread->thread_id == 0)
266 cpu_set(i, cbe_first_online_cpu);
267 }
268 }
269
270 cbe_fill_regs_map(map);
271 }
272}
273
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
index 440a7ecc66ea..17d597144877 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.h
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -255,6 +255,11 @@ struct cbe_mic_tm_regs {
255extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); 255extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
256extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu); 256extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
257 257
258/* some utility functions to deal with SMT */
259extern u32 cbe_get_hw_thread_id(int cpu);
260extern u32 cbe_cpu_to_node(int cpu);
261extern u32 cbe_node_to_cpu(int node);
262
258/* Init this module early */ 263/* Init this module early */
259extern void cbe_regs_init(void); 264extern void cbe_regs_init(void);
260 265
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index e8bcd2a767ce..f370f0fa6f4c 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -1,6 +1,31 @@
1/* 1/*
2 * thermal support for the cell processor 2 * thermal support for the cell processor
3 * 3 *
4 * This module adds some sysfs attributes to cpu and spu nodes.
5 * Base for measurements are the digital thermal sensors (DTS)
6 * located on the chip.
7 * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
8 * The attributes can be found under
9 * /sys/devices/system/cpu/cpuX/thermal
10 * /sys/devices/system/spu/spuX/thermal
11 *
12 * The following attributes are added for each node:
13 * temperature:
14 * contains the current temperature measured by the DTS
15 * throttle_begin:
16 * throttling begins when temperature is greater or equal to
17 * throttle_begin. Setting this value to 125 prevents throttling.
18 * throttle_end:
19 * throttling is being ceased, if the temperature is lower than
20 * throttle_end. Due to a delay between applying throttling and
21 * a reduced temperature this value should be less than throttle_begin.
22 * A value equal to throttle_begin provides only a very little hysteresis.
23 * throttle_full_stop:
24 * If the temperatrue is greater or equal to throttle_full_stop,
25 * full throttling is applied to the cpu or spu. This value should be
26 * greater than throttle_begin and throttle_end. Setting this value to
27 * 65 prevents the unit from running code at all.
28 *
4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 29 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5 * 30 *
6 * Author: Christian Krafft <krafft@de.ibm.com> 31 * Author: Christian Krafft <krafft@de.ibm.com>
@@ -31,6 +56,26 @@
31#include "cbe_regs.h" 56#include "cbe_regs.h"
32#include "spu_priv1_mmio.h" 57#include "spu_priv1_mmio.h"
33 58
59#define TEMP_MIN 65
60#define TEMP_MAX 125
61
62#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode) \
63struct sysdev_attribute attr_ ## _prefix ## _ ## _name = { \
64 .attr = { .name = __stringify(_name), .mode = _mode }, \
65 .show = _prefix ## _show_ ## _name, \
66 .store = _prefix ## _store_ ## _name, \
67};
68
69static inline u8 reg_to_temp(u8 reg_value)
70{
71 return ((reg_value & 0x3f) << 1) + TEMP_MIN;
72}
73
74static inline u8 temp_to_reg(u8 temp)
75{
76 return ((temp - TEMP_MIN) >> 1) & 0x3f;
77}
78
34static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev) 79static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
35{ 80{
36 struct spu *spu; 81 struct spu *spu;
@@ -58,20 +103,81 @@ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iom
58 103
59static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf) 104static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
60{ 105{
61 int value; 106 u8 value;
62 struct cbe_pmd_regs __iomem *pmd_regs; 107 struct cbe_pmd_regs __iomem *pmd_regs;
63 108
64 pmd_regs = get_pmd_regs(sysdev); 109 pmd_regs = get_pmd_regs(sysdev);
65 110
66 value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1); 111 value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
67 /* clear all other bits */ 112
113 return sprintf(buf, "%d\n", reg_to_temp(value));
114}
115
116static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
117{
118 u64 value;
119
120 value = in_be64(&pmd_regs->tm_tpr.val);
121 /* access the corresponding byte */
122 value >>= pos;
68 value &= 0x3F; 123 value &= 0x3F;
69 /* temp is stored in steps of 2 degrees */
70 value *= 2;
71 /* base temp is 65 degrees */
72 value += 65;
73 124
74 return sprintf(buf, "%d\n", (int) value); 125 return sprintf(buf, "%d\n", reg_to_temp(value));
126}
127
128static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
129{
130 u64 reg_value;
131 int temp;
132 u64 new_value;
133 int ret;
134
135 ret = sscanf(buf, "%u", &temp);
136
137 if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
138 return -EINVAL;
139
140 new_value = temp_to_reg(temp);
141
142 reg_value = in_be64(&pmd_regs->tm_tpr.val);
143
144 /* zero out bits for new value */
145 reg_value &= ~(0xffull << pos);
146 /* set bits to new value */
147 reg_value |= new_value << pos;
148
149 out_be64(&pmd_regs->tm_tpr.val, reg_value);
150 return size;
151}
152
153static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf)
154{
155 return show_throttle(get_pmd_regs(sysdev), buf, 0);
156}
157
158static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf)
159{
160 return show_throttle(get_pmd_regs(sysdev), buf, 8);
161}
162
163static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
164{
165 return show_throttle(get_pmd_regs(sysdev), buf, 16);
166}
167
168static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
169{
170 return store_throttle(get_pmd_regs(sysdev), buf, size, 0);
171}
172
173static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
174{
175 return store_throttle(get_pmd_regs(sysdev), buf, size, 8);
176}
177
178static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
179{
180 return store_throttle(get_pmd_regs(sysdev), buf, size, 16);
75} 181}
76 182
77static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos) 183static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
@@ -82,16 +188,9 @@ static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
82 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); 188 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
83 value = in_be64(&pmd_regs->ts_ctsr2); 189 value = in_be64(&pmd_regs->ts_ctsr2);
84 190
85 /* access the corresponding byte */ 191 value = (value >> pos) & 0x3f;
86 value >>= pos;
87 /* clear all other bits */
88 value &= 0x3F;
89 /* temp is stored in steps of 2 degrees */
90 value *= 2;
91 /* base temp is 65 degrees */
92 value += 65;
93 192
94 return sprintf(buf, "%d\n", (int) value); 193 return sprintf(buf, "%d\n", reg_to_temp(value));
95} 194}
96 195
97 196
@@ -108,13 +207,52 @@ static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
108 return ppe_show_temp(sysdev, buf, 0); 207 return ppe_show_temp(sysdev, buf, 0);
109} 208}
110 209
210static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf)
211{
212 return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32);
213}
214
215static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf)
216{
217 return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40);
218}
219
220static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
221{
222 return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48);
223}
224
225static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
226{
227 return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32);
228}
229
230static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
231{
232 return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40);
233}
234
235static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
236{
237 return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48);
238}
239
240
111static struct sysdev_attribute attr_spu_temperature = { 241static struct sysdev_attribute attr_spu_temperature = {
112 .attr = {.name = "temperature", .mode = 0400 }, 242 .attr = {.name = "temperature", .mode = 0400 },
113 .show = spu_show_temp, 243 .show = spu_show_temp,
114}; 244};
115 245
246static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600);
247static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600);
248static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600);
249
250
116static struct attribute *spu_attributes[] = { 251static struct attribute *spu_attributes[] = {
117 &attr_spu_temperature.attr, 252 &attr_spu_temperature.attr,
253 &attr_spu_throttle_end.attr,
254 &attr_spu_throttle_begin.attr,
255 &attr_spu_throttle_full_stop.attr,
118 NULL, 256 NULL,
119}; 257};
120 258
@@ -133,9 +271,16 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
133 .show = ppe_show_temp1, 271 .show = ppe_show_temp1,
134}; 272};
135 273
274static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600);
275static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600);
276static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
277
136static struct attribute *ppe_attributes[] = { 278static struct attribute *ppe_attributes[] = {
137 &attr_ppe_temperature0.attr, 279 &attr_ppe_temperature0.attr,
138 &attr_ppe_temperature1.attr, 280 &attr_ppe_temperature1.attr,
281 &attr_ppe_throttle_end.attr,
282 &attr_ppe_throttle_begin.attr,
283 &attr_ppe_throttle_full_stop.attr,
139 NULL, 284 NULL,
140}; 285};
141 286
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 0984c7071695..b5ebc916388b 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -3,11 +3,13 @@
3#include <linux/types.h> 3#include <linux/types.h>
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/smp.h> 5#include <linux/smp.h>
6#include <linux/reboot.h>
6 7
7#include <asm/reg.h> 8#include <asm/reg.h>
8#include <asm/io.h> 9#include <asm/io.h>
9#include <asm/prom.h> 10#include <asm/prom.h>
10#include <asm/machdep.h> 11#include <asm/machdep.h>
12#include <asm/rtas.h>
11 13
12#include "ras.h" 14#include "ras.h"
13#include "cbe_regs.h" 15#include "cbe_regs.h"
@@ -82,6 +84,164 @@ static int cbe_machine_check_handler(struct pt_regs *regs)
82 return 0; 84 return 0;
83} 85}
84 86
87struct ptcal_area {
88 struct list_head list;
89 int nid;
90 int order;
91 struct page *pages;
92};
93
94static LIST_HEAD(ptcal_list);
95
96static int ptcal_start_tok, ptcal_stop_tok;
97
98static int __init cbe_ptcal_enable_on_node(int nid, int order)
99{
100 struct ptcal_area *area;
101 int ret = -ENOMEM;
102 unsigned long addr;
103
104#ifdef CONFIG_CRASH_DUMP
105 rtas_call(ptcal_stop_tok, 1, 1, NULL, nid);
106#endif
107
108 area = kmalloc(sizeof(*area), GFP_KERNEL);
109 if (!area)
110 goto out_err;
111
112 area->nid = nid;
113 area->order = order;
114 area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order);
115
116 if (!area->pages)
117 goto out_free_area;
118
119 addr = __pa(page_address(area->pages));
120
121 ret = -EIO;
122 if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid,
123 (unsigned int)(addr >> 32),
124 (unsigned int)(addr & 0xffffffff))) {
125 printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n",
126 __FUNCTION__, nid);
127 goto out_free_pages;
128 }
129
130 list_add(&area->list, &ptcal_list);
131
132 return 0;
133
134out_free_pages:
135 __free_pages(area->pages, area->order);
136out_free_area:
137 kfree(area);
138out_err:
139 return ret;
140}
141
142static int __init cbe_ptcal_enable(void)
143{
144 const u32 *size;
145 struct device_node *np;
146 int order, found_mic = 0;
147
148 np = of_find_node_by_path("/rtas");
149 if (!np)
150 return -ENODEV;
151
152 size = get_property(np, "ibm,cbe-ptcal-size", NULL);
153 if (!size)
154 return -ENODEV;
155
156 pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size);
157 order = get_order(*size);
158 of_node_put(np);
159
160 /* support for malta device trees, with be@/mic@ nodes */
161 for_each_node_by_type(np, "mic-tm") {
162 cbe_ptcal_enable_on_node(of_node_to_nid(np), order);
163 found_mic = 1;
164 }
165
166 if (found_mic)
167 return 0;
168
169 /* support for older device tree - use cpu nodes */
170 for_each_node_by_type(np, "cpu") {
171 const u32 *nid = get_property(np, "node-id", NULL);
172 if (!nid) {
173 printk(KERN_ERR "%s: node %s is missing node-id?\n",
174 __FUNCTION__, np->full_name);
175 continue;
176 }
177 cbe_ptcal_enable_on_node(*nid, order);
178 found_mic = 1;
179 }
180
181 return found_mic ? 0 : -ENODEV;
182}
183
184static int cbe_ptcal_disable(void)
185{
186 struct ptcal_area *area, *tmp;
187 int ret = 0;
188
189 pr_debug("%s: disabling PTCAL\n", __FUNCTION__);
190
191 list_for_each_entry_safe(area, tmp, &ptcal_list, list) {
192 /* disable ptcal on this node */
193 if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) {
194 printk(KERN_ERR "%s: error disabling PTCAL "
195 "on node %d!\n", __FUNCTION__,
196 area->nid);
197 ret = -EIO;
198 continue;
199 }
200
201 /* ensure we can access the PTCAL area */
202 memset(page_address(area->pages), 0,
203 1 << (area->order + PAGE_SHIFT));
204
205 /* clean up */
206 list_del(&area->list);
207 __free_pages(area->pages, area->order);
208 kfree(area);
209 }
210
211 return ret;
212}
213
214static int cbe_ptcal_notify_reboot(struct notifier_block *nb,
215 unsigned long code, void *data)
216{
217 return cbe_ptcal_disable();
218}
219
220static struct notifier_block cbe_ptcal_reboot_notifier = {
221 .notifier_call = cbe_ptcal_notify_reboot
222};
223
224int __init cbe_ptcal_init(void)
225{
226 int ret;
227 ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
228 ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
229
230 if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
231 || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)
232 return -ENODEV;
233
234 ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier);
235 if (ret) {
236 printk(KERN_ERR "Can't disable PTCAL, so not enabling\n");
237 return ret;
238 }
239
240 return cbe_ptcal_enable();
241}
242
243arch_initcall(cbe_ptcal_init);
244
85void __init cbe_ras_init(void) 245void __init cbe_ras_init(void)
86{ 246{
87 unsigned long hid0; 247 unsigned long hid0;
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index a5282011d39e..85a7c99c1003 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -33,7 +33,7 @@
33#include <asm/of_platform.h> 33#include <asm/of_platform.h>
34#include <asm/io.h> 34#include <asm/io.h>
35#include <asm/pmi.h> 35#include <asm/pmi.h>
36 36#include <asm/prom.h>
37 37
38struct pmi_data { 38struct pmi_data {
39 struct list_head handler; 39 struct list_head handler;
@@ -49,21 +49,6 @@ struct pmi_data {
49}; 49};
50 50
51 51
52
53static void __iomem *of_iomap(struct device_node *np)
54{
55 struct resource res;
56
57 if (of_address_to_resource(np, 0, &res))
58 return NULL;
59
60 pr_debug("Resource start: 0x%lx\n", res.start);
61 pr_debug("Resource end: 0x%lx\n", res.end);
62
63 return ioremap(res.start, 1 + res.end - res.start);
64}
65
66
67static int pmi_irq_handler(int irq, void *dev_id) 52static int pmi_irq_handler(int irq, void *dev_id)
68{ 53{
69 struct pmi_data *data; 54 struct pmi_data *data;
@@ -118,6 +103,7 @@ out:
118 103
119static struct of_device_id pmi_match[] = { 104static struct of_device_id pmi_match[] = {
120 { .type = "ibm,pmi", .name = "ibm,pmi" }, 105 { .type = "ibm,pmi", .name = "ibm,pmi" },
106 { .type = "ibm,pmi" },
121 {}, 107 {},
122}; 108};
123 109
@@ -153,7 +139,7 @@ static int pmi_of_probe(struct of_device *dev,
153 goto out; 139 goto out;
154 } 140 }
155 141
156 data->pmi_reg = of_iomap(np); 142 data->pmi_reg = of_iomap(np, 0);
157 if (!data->pmi_reg) { 143 if (!data->pmi_reg) {
158 printk(KERN_ERR "pmi: invalid register address.\n"); 144 printk(KERN_ERR "pmi: invalid register address.\n");
159 rc = -EFAULT; 145 rc = -EFAULT;
@@ -279,6 +265,9 @@ void pmi_register_handler(struct of_device *device,
279 struct pmi_data *data; 265 struct pmi_data *data;
280 data = device->dev.driver_data; 266 data = device->dev.driver_data;
281 267
268 if (!data)
269 return;
270
282 spin_lock(&data->handler_spinlock); 271 spin_lock(&data->handler_spinlock);
283 list_add_tail(&handler->node, &data->handler); 272 list_add_tail(&handler->node, &data->handler);
284 spin_unlock(&data->handler_spinlock); 273 spin_unlock(&data->handler_spinlock);
@@ -289,10 +278,12 @@ void pmi_unregister_handler(struct of_device *device,
289 struct pmi_handler *handler) 278 struct pmi_handler *handler)
290{ 279{
291 struct pmi_data *data; 280 struct pmi_data *data;
281 data = device->dev.driver_data;
292 282
293 pr_debug("pmi: unregistering handler %p\n", handler); 283 if (!data)
284 return;
294 285
295 data = device->dev.driver_data; 286 pr_debug("pmi: unregistering handler %p\n", handler);
296 287
297 spin_lock(&data->handler_spinlock); 288 spin_lock(&data->handler_spinlock);
298 list_del(&handler->node); 289 list_del(&handler->node);
diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h
index 35b95773746c..8066eede3a0c 100644
--- a/include/asm-powerpc/cell-pmu.h
+++ b/include/asm-powerpc/cell-pmu.h
@@ -97,11 +97,6 @@ extern void cbe_disable_pm_interrupts(u32 cpu);
97extern u32 cbe_get_and_clear_pm_interrupts(u32 cpu); 97extern u32 cbe_get_and_clear_pm_interrupts(u32 cpu);
98extern void cbe_sync_irq(int node); 98extern void cbe_sync_irq(int node);
99 99
100/* Utility functions, macros */
101extern u32 cbe_get_hw_thread_id(int cpu);
102
103#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
104
105#define CBE_COUNT_SUPERVISOR_MODE 0 100#define CBE_COUNT_SUPERVISOR_MODE 0
106#define CBE_COUNT_HYPERVISOR_MODE 1 101#define CBE_COUNT_HYPERVISOR_MODE 1
107#define CBE_COUNT_PROBLEM_MODE 2 102#define CBE_COUNT_PROBLEM_MODE 2
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index e73a2b482a15..f31af713e6a4 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -20,6 +20,7 @@
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <asm/irq.h> 21#include <asm/irq.h>
22#include <asm/atomic.h> 22#include <asm/atomic.h>
23#include <asm/io.h>
23 24
24/* Definitions used by the flattened device tree */ 25/* Definitions used by the flattened device tree */
25#define OF_DT_HEADER 0xd00dfeed /* marker */ 26#define OF_DT_HEADER 0xd00dfeed /* marker */
@@ -355,6 +356,16 @@ static inline int of_irq_to_resource(struct device_node *dev, int index, struct
355 return irq; 356 return irq;
356} 357}
357 358
359static inline void __iomem *of_iomap(struct device_node *np, int index)
360{
361 struct resource res;
362
363 if (of_address_to_resource(np, index, &res))
364 return NULL;
365
366 return ioremap(res.start, 1 + res.end - res.start);
367}
368
358 369
359#endif /* __KERNEL__ */ 370#endif /* __KERNEL__ */
360#endif /* _POWERPC_PROM_H */ 371#endif /* _POWERPC_PROM_H */