aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig14
-rw-r--r--arch/powerpc/platforms/cell/Makefile6
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c248
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c59
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h201
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c225
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c96
-rw-r--r--arch/powerpc/platforms/cell/pmu.c328
-rw-r--r--arch/powerpc/platforms/cell/pmu.h57
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c110
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1_mmio.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c27
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c54
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c5
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c143
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c12
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h8
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c63
-rw-r--r--arch/powerpc/platforms/efika/Makefile1
-rw-r--r--arch/powerpc/platforms/efika/efika.h19
-rw-r--r--arch/powerpc/platforms/efika/pci.c119
-rw-r--r--arch/powerpc/platforms/efika/setup.c149
-rw-r--r--arch/powerpc/platforms/iseries/dt.c15
-rw-r--r--arch/powerpc/platforms/iseries/ksyms.c6
-rw-r--r--arch/powerpc/platforms/iseries/misc.S35
-rw-r--r--arch/powerpc/platforms/iseries/setup.c32
-rw-r--r--arch/powerpc/platforms/powermac/feature.c8
-rw-r--r--arch/powerpc/platforms/powermac/setup.c2
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c4
30 files changed, 1823 insertions, 230 deletions
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index e58fa953a50b..7ad2673d0aa5 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -5,6 +5,7 @@ ifeq ($(CONFIG_PPC64),y)
5obj-$(CONFIG_PPC_PMAC) += powermac/ 5obj-$(CONFIG_PPC_PMAC) += powermac/
6endif 6endif
7endif 7endif
8obj-$(CONFIG_PPC_EFIKA) += efika/
8obj-$(CONFIG_PPC_CHRP) += chrp/ 9obj-$(CONFIG_PPC_CHRP) += chrp/
9obj-$(CONFIG_4xx) += 4xx/ 10obj-$(CONFIG_4xx) += 4xx/
10obj-$(CONFIG_PPC_83xx) += 83xx/ 11obj-$(CONFIG_PPC_83xx) += 83xx/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 3e430b489bb7..06a85b704331 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -20,4 +20,18 @@ config CBE_RAS
20 bool "RAS features for bare metal Cell BE" 20 bool "RAS features for bare metal Cell BE"
21 default y 21 default y
22 22
23config CBE_THERM
24 tristate "CBE thermal support"
25 default m
26 depends on CBE_RAS
27
28config CBE_CPUFREQ
29 tristate "CBE frequency scaling"
30 depends on CBE_RAS && CPU_FREQ
31 default m
32 help
33 This adds the cpufreq driver for Cell BE processors.
34 For details, take a look at <file:Documentation/cpu-freq/>.
35 If you don't have such processor, say N
36
23endmenu 37endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index c89cdd67383b..0f31db7a50a3 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,7 +1,11 @@
1obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \ 1obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
2 cbe_regs.o spider-pic.o pervasive.o 2 cbe_regs.o spider-pic.o pervasive.o \
3 pmu.o
3obj-$(CONFIG_CBE_RAS) += ras.o 4obj-$(CONFIG_CBE_RAS) += ras.o
4 5
6obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
7obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o
8
5ifeq ($(CONFIG_SMP),y) 9ifeq ($(CONFIG_SMP),y)
6obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o 10obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
7endif 11endif
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
new file mode 100644
index 000000000000..a3850fd1e94c
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -0,0 +1,248 @@
1/*
2 * cpufreq driver for the cell processor
3 *
4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5 *
6 * Author: Christian Krafft <krafft@de.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/cpufreq.h>
24#include <linux/timer.h>
25
26#include <asm/hw_irq.h>
27#include <asm/io.h>
28#include <asm/processor.h>
29#include <asm/prom.h>
30#include <asm/time.h>
31
32#include "cbe_regs.h"
33
34static DEFINE_MUTEX(cbe_switch_mutex);
35
36
37/* the CBE supports an 8 step frequency scaling */
38static struct cpufreq_frequency_table cbe_freqs[] = {
39 {1, 0},
40 {2, 0},
41 {3, 0},
42 {4, 0},
43 {5, 0},
44 {6, 0},
45 {8, 0},
46 {10, 0},
47 {0, CPUFREQ_TABLE_END},
48};
49
50/* to write to MIC register */
51static u64 MIC_Slow_Fast_Timer_table[] = {
52 [0 ... 7] = 0x007fc00000000000ull,
53};
54
55/* more values for the MIC */
56static u64 MIC_Slow_Next_Timer_table[] = {
57 0x0000240000000000ull,
58 0x0000268000000000ull,
59 0x000029C000000000ull,
60 0x00002D0000000000ull,
61 0x0000300000000000ull,
62 0x0000334000000000ull,
63 0x000039C000000000ull,
64 0x00003FC000000000ull,
65};
66
67/*
68 * hardware specific functions
69 */
70
71static int get_pmode(int cpu)
72{
73 int ret;
74 struct cbe_pmd_regs __iomem *pmd_regs;
75
76 pmd_regs = cbe_get_cpu_pmd_regs(cpu);
77 ret = in_be64(&pmd_regs->pmsr) & 0x07;
78
79 return ret;
80}
81
82static int set_pmode(int cpu, unsigned int pmode)
83{
84 struct cbe_pmd_regs __iomem *pmd_regs;
85 struct cbe_mic_tm_regs __iomem *mic_tm_regs;
86 u64 flags;
87 u64 value;
88
89 local_irq_save(flags);
90
91 mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
92 pmd_regs = cbe_get_cpu_pmd_regs(cpu);
93
94 pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
95 pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
96
97 out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
98 out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
99
100 out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
101 out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
102
103 value = in_be64(&pmd_regs->pmcr);
104 /* set bits to zero */
105 value &= 0xFFFFFFFFFFFFFFF8ull;
106 /* set bits to next pmode */
107 value |= pmode;
108
109 out_be64(&pmd_regs->pmcr, value);
110
111 /* wait until new pmode appears in status register */
112 value = in_be64(&pmd_regs->pmsr) & 0x07;
113 while(value != pmode) {
114 cpu_relax();
115 value = in_be64(&pmd_regs->pmsr) & 0x07;
116 }
117
118 local_irq_restore(flags);
119
120 return 0;
121}
122
123/*
124 * cpufreq functions
125 */
126
127static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
128{
129 u32 *max_freq;
130 int i, cur_pmode;
131 struct device_node *cpu;
132
133 cpu = of_get_cpu_node(policy->cpu, NULL);
134
135 if(!cpu)
136 return -ENODEV;
137
138 pr_debug("init cpufreq on CPU %d\n", policy->cpu);
139
140 max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
141
142 if(!max_freq)
143 return -EINVAL;
144
145 // we need the freq in kHz
146 *max_freq /= 1000;
147
148 pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
149 pr_debug("initializing frequency table\n");
150
151 // initialize frequency table
152 for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
153 cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
154 pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
155 }
156
157 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
158 /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
159 policy->cpuinfo.transition_latency = 25000;
160
161 cur_pmode = get_pmode(policy->cpu);
162 pr_debug("current pmode is at %d\n",cur_pmode);
163
164 policy->cur = cbe_freqs[cur_pmode].frequency;
165
166#ifdef CONFIG_SMP
167 policy->cpus = cpu_sibling_map[policy->cpu];
168#endif
169
170 cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
171
172 /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
173 return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
174}
175
176static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
177{
178 cpufreq_frequency_table_put_attr(policy->cpu);
179 return 0;
180}
181
182static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
183{
184 return cpufreq_frequency_table_verify(policy, cbe_freqs);
185}
186
187
188static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
189 unsigned int relation)
190{
191 int rc;
192 struct cpufreq_freqs freqs;
193 int cbe_pmode_new;
194
195 cpufreq_frequency_table_target(policy,
196 cbe_freqs,
197 target_freq,
198 relation,
199 &cbe_pmode_new);
200
201 freqs.old = policy->cur;
202 freqs.new = cbe_freqs[cbe_pmode_new].frequency;
203 freqs.cpu = policy->cpu;
204
205 mutex_lock (&cbe_switch_mutex);
206 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
207
208 pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
209 policy->cpu,
210 cbe_freqs[cbe_pmode_new].frequency,
211 cbe_freqs[cbe_pmode_new].index);
212
213 rc = set_pmode(policy->cpu, cbe_pmode_new);
214 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
215 mutex_unlock(&cbe_switch_mutex);
216
217 return rc;
218}
219
220static struct cpufreq_driver cbe_cpufreq_driver = {
221 .verify = cbe_cpufreq_verify,
222 .target = cbe_cpufreq_target,
223 .init = cbe_cpufreq_cpu_init,
224 .exit = cbe_cpufreq_cpu_exit,
225 .name = "cbe-cpufreq",
226 .owner = THIS_MODULE,
227 .flags = CPUFREQ_CONST_LOOPS,
228};
229
230/*
231 * module init and destoy
232 */
233
234static int __init cbe_cpufreq_init(void)
235{
236 return cpufreq_register_driver(&cbe_cpufreq_driver);
237}
238
239static void __exit cbe_cpufreq_exit(void)
240{
241 cpufreq_unregister_driver(&cbe_cpufreq_driver);
242}
243
244module_init(cbe_cpufreq_init);
245module_exit(cbe_cpufreq_exit);
246
247MODULE_LICENSE("GPL");
248MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 2f194ba29899..5a91b75c2f01 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -8,6 +8,7 @@
8 8
9#include <linux/percpu.h> 9#include <linux/percpu.h>
10#include <linux/types.h> 10#include <linux/types.h>
11#include <linux/module.h>
11 12
12#include <asm/io.h> 13#include <asm/io.h>
13#include <asm/pgtable.h> 14#include <asm/pgtable.h>
@@ -16,8 +17,6 @@
16 17
17#include "cbe_regs.h" 18#include "cbe_regs.h"
18 19
19#define MAX_CBE 2
20
21/* 20/*
22 * Current implementation uses "cpu" nodes. We build our own mapping 21 * Current implementation uses "cpu" nodes. We build our own mapping
23 * array of cpu numbers to cpu nodes locally for now to allow interrupt 22 * array of cpu numbers to cpu nodes locally for now to allow interrupt
@@ -30,6 +29,8 @@ static struct cbe_regs_map
30 struct device_node *cpu_node; 29 struct device_node *cpu_node;
31 struct cbe_pmd_regs __iomem *pmd_regs; 30 struct cbe_pmd_regs __iomem *pmd_regs;
32 struct cbe_iic_regs __iomem *iic_regs; 31 struct cbe_iic_regs __iomem *iic_regs;
32 struct cbe_mic_tm_regs __iomem *mic_tm_regs;
33 struct cbe_pmd_shadow_regs pmd_shadow_regs;
33} cbe_regs_maps[MAX_CBE]; 34} cbe_regs_maps[MAX_CBE];
34static int cbe_regs_map_count; 35static int cbe_regs_map_count;
35 36
@@ -42,6 +43,19 @@ static struct cbe_thread_map
42static struct cbe_regs_map *cbe_find_map(struct device_node *np) 43static struct cbe_regs_map *cbe_find_map(struct device_node *np)
43{ 44{
44 int i; 45 int i;
46 struct device_node *tmp_np;
47
48 if (strcasecmp(np->type, "spe") == 0) {
49 if (np->data == NULL) {
50 /* walk up path until cpu node was found */
51 tmp_np = np->parent;
52 while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
53 tmp_np = tmp_np->parent;
54
55 np->data = cbe_find_map(tmp_np);
56 }
57 return np->data;
58 }
45 59
46 for (i = 0; i < cbe_regs_map_count; i++) 60 for (i = 0; i < cbe_regs_map_count; i++)
47 if (cbe_regs_maps[i].cpu_node == np) 61 if (cbe_regs_maps[i].cpu_node == np)
@@ -56,6 +70,7 @@ struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
56 return NULL; 70 return NULL;
57 return map->pmd_regs; 71 return map->pmd_regs;
58} 72}
73EXPORT_SYMBOL_GPL(cbe_get_pmd_regs);
59 74
60struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu) 75struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
61{ 76{
@@ -64,7 +79,23 @@ struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
64 return NULL; 79 return NULL;
65 return map->pmd_regs; 80 return map->pmd_regs;
66} 81}
82EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
83
84struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np)
85{
86 struct cbe_regs_map *map = cbe_find_map(np);
87 if (map == NULL)
88 return NULL;
89 return &map->pmd_shadow_regs;
90}
67 91
92struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu)
93{
94 struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
95 if (map == NULL)
96 return NULL;
97 return &map->pmd_shadow_regs;
98}
68 99
69struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np) 100struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
70{ 101{
@@ -73,6 +104,7 @@ struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
73 return NULL; 104 return NULL;
74 return map->iic_regs; 105 return map->iic_regs;
75} 106}
107
76struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu) 108struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
77{ 109{
78 struct cbe_regs_map *map = cbe_thread_map[cpu].regs; 110 struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
@@ -81,6 +113,24 @@ struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
81 return map->iic_regs; 113 return map->iic_regs;
82} 114}
83 115
116struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np)
117{
118 struct cbe_regs_map *map = cbe_find_map(np);
119 if (map == NULL)
120 return NULL;
121 return map->mic_tm_regs;
122}
123
124struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
125{
126 struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
127 if (map == NULL)
128 return NULL;
129 return map->mic_tm_regs;
130}
131EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
132
133
84void __init cbe_regs_init(void) 134void __init cbe_regs_init(void)
85{ 135{
86 int i; 136 int i;
@@ -119,6 +169,11 @@ void __init cbe_regs_init(void)
119 prop = get_property(cpu, "iic", NULL); 169 prop = get_property(cpu, "iic", NULL);
120 if (prop != NULL) 170 if (prop != NULL)
121 map->iic_regs = ioremap(prop->address, prop->len); 171 map->iic_regs = ioremap(prop->address, prop->len);
172
173 prop = (struct address_prop *)get_property(cpu, "mic-tm",
174 NULL);
175 if (prop != NULL)
176 map->mic_tm_regs = ioremap(prop->address, prop->len);
122 } 177 }
123} 178}
124 179
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
index e76e4a6af5bc..91083f51a0cb 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.h
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -4,6 +4,11 @@
4 * This file is intended to hold the various register definitions for CBE 4 * This file is intended to hold the various register definitions for CBE
5 * on-chip system devices (memory controller, IO controller, etc...) 5 * on-chip system devices (memory controller, IO controller, etc...)
6 * 6 *
7 * (C) Copyright IBM Corporation 2001,2006
8 *
9 * Authors: Maximino Aguilar (maguilar@us.ibm.com)
10 * David J. Erb (djerb@us.ibm.com)
11 *
7 * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. 12 * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
8 */ 13 */
9 14
@@ -22,6 +27,7 @@
22#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul 27#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul
23#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul 28#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul
24 29
30#define MAX_CBE 2
25 31
26/* 32/*
27 * 33 *
@@ -29,51 +35,132 @@
29 * 35 *
30 */ 36 */
31 37
38/* Macros for the pm_control register. */
39#define CBE_PM_16BIT_CTR(ctr) (1 << (24 - ((ctr) & (NR_PHYS_CTRS - 1))))
40#define CBE_PM_ENABLE_PERF_MON 0x80000000
41
42
43union spe_reg {
44 u64 val;
45 u8 spe[8];
46};
47
48union ppe_spe_reg {
49 u64 val;
50 struct {
51 u32 ppe;
52 u32 spe;
53 };
54};
55
56
32struct cbe_pmd_regs { 57struct cbe_pmd_regs {
33 u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */ 58 /* Debug Bus Control */
59 u64 pad_0x0000; /* 0x0000 */
60
61 u64 group_control; /* 0x0008 */
62
63 u8 pad_0x0010_0x00a8 [0x00a8 - 0x0010]; /* 0x0010 */
64
65 u64 debug_bus_control; /* 0x00a8 */
66
67 u8 pad_0x00b0_0x0100 [0x0100 - 0x00b0]; /* 0x00b0 */
68
69 u64 trace_aux_data; /* 0x0100 */
70 u64 trace_buffer_0_63; /* 0x0108 */
71 u64 trace_buffer_64_127; /* 0x0110 */
72 u64 trace_address; /* 0x0118 */
73 u64 ext_tr_timer; /* 0x0120 */
74
75 u8 pad_0x0128_0x0400 [0x0400 - 0x0128]; /* 0x0128 */
76
77 /* Performance Monitor */
78 u64 pm_status; /* 0x0400 */
79 u64 pm_control; /* 0x0408 */
80 u64 pm_interval; /* 0x0410 */
81 u64 pm_ctr[4]; /* 0x0418 */
82 u64 pm_start_stop; /* 0x0438 */
83 u64 pm07_control[8]; /* 0x0440 */
84
85 u8 pad_0x0480_0x0800 [0x0800 - 0x0480]; /* 0x0480 */
34 86
35 /* Thermal Sensor Registers */ 87 /* Thermal Sensor Registers */
36 u64 ts_ctsr1; /* 0x0800 */ 88 union spe_reg ts_ctsr1; /* 0x0800 */
37 u64 ts_ctsr2; /* 0x0808 */ 89 u64 ts_ctsr2; /* 0x0808 */
38 u64 ts_mtsr1; /* 0x0810 */ 90 union spe_reg ts_mtsr1; /* 0x0810 */
39 u64 ts_mtsr2; /* 0x0818 */ 91 u64 ts_mtsr2; /* 0x0818 */
40 u64 ts_itr1; /* 0x0820 */ 92 union spe_reg ts_itr1; /* 0x0820 */
41 u64 ts_itr2; /* 0x0828 */ 93 u64 ts_itr2; /* 0x0828 */
42 u64 ts_gitr; /* 0x0830 */ 94 u64 ts_gitr; /* 0x0830 */
43 u64 ts_isr; /* 0x0838 */ 95 u64 ts_isr; /* 0x0838 */
44 u64 ts_imr; /* 0x0840 */ 96 u64 ts_imr; /* 0x0840 */
45 u64 tm_cr1; /* 0x0848 */ 97 union spe_reg tm_cr1; /* 0x0848 */
46 u64 tm_cr2; /* 0x0850 */ 98 u64 tm_cr2; /* 0x0850 */
47 u64 tm_simr; /* 0x0858 */ 99 u64 tm_simr; /* 0x0858 */
48 u64 tm_tpr; /* 0x0860 */ 100 union ppe_spe_reg tm_tpr; /* 0x0860 */
49 u64 tm_str1; /* 0x0868 */ 101 union spe_reg tm_str1; /* 0x0868 */
50 u64 tm_str2; /* 0x0870 */ 102 u64 tm_str2; /* 0x0870 */
51 u64 tm_tsr; /* 0x0878 */ 103 union ppe_spe_reg tm_tsr; /* 0x0878 */
52 104
53 /* Power Management */ 105 /* Power Management */
54 u64 pm_control; /* 0x0880 */ 106 u64 pmcr; /* 0x0880 */
55#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000 107#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000
56 u64 pm_status; /* 0x0888 */ 108 u64 pmsr; /* 0x0888 */
57 109
58 /* Time Base Register */ 110 /* Time Base Register */
59 u64 tbr; /* 0x0890 */ 111 u64 tbr; /* 0x0890 */
60 112
61 u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */ 113 u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */
62 114
63 /* Fault Isolation Registers */ 115 /* Fault Isolation Registers */
64 u64 checkstop_fir; /* 0x0c00 */ 116 u64 checkstop_fir; /* 0x0c00 */
65 u64 recoverable_fir; 117 u64 recoverable_fir; /* 0x0c08 */
66 u64 spec_att_mchk_fir; 118 u64 spec_att_mchk_fir; /* 0x0c10 */
67 u64 fir_mode_reg; 119 u64 fir_mode_reg; /* 0x0c18 */
68 u64 fir_enable_mask; 120 u64 fir_enable_mask; /* 0x0c20 */
69 121
70 u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */ 122 u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */
71}; 123};
72 124
73extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); 125extern 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); 126extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu);
75 127
76/* 128/*
129 * PMU shadow registers
130 *
131 * Many of the registers in the performance monitoring unit are write-only,
132 * so we need to save a copy of what we write to those registers.
133 *
134 * The actual data counters are read/write. However, writing to the counters
135 * only takes effect if the PMU is enabled. Otherwise the value is stored in
136 * a hardware latch until the next time the PMU is enabled. So we save a copy
137 * of the counter values if we need to read them back while the PMU is
138 * disabled. The counter_value_in_latch field is a bitmap indicating which
139 * counters currently have a value waiting to be written.
140 */
141
142#define NR_PHYS_CTRS 4
143#define NR_CTRS (NR_PHYS_CTRS * 2)
144
145struct cbe_pmd_shadow_regs {
146 u32 group_control;
147 u32 debug_bus_control;
148 u32 trace_address;
149 u32 ext_tr_timer;
150 u32 pm_status;
151 u32 pm_control;
152 u32 pm_interval;
153 u32 pm_start_stop;
154 u32 pm07_control[NR_CTRS];
155
156 u32 pm_ctr[NR_PHYS_CTRS];
157 u32 counter_value_in_latch;
158};
159
160extern struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np);
161extern struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu);
162
163/*
77 * 164 *
78 * IIC unit register definitions 165 * IIC unit register definitions
79 * 166 *
@@ -102,18 +189,20 @@ struct cbe_iic_regs {
102 189
103 /* IIC interrupt registers */ 190 /* IIC interrupt registers */
104 struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ 191 struct cbe_iic_thread_regs thread[2]; /* 0x0400 */
105 u64 iic_ir; /* 0x0440 */ 192
106 u64 iic_is; /* 0x0448 */ 193 u64 iic_ir; /* 0x0440 */
194 u64 iic_is; /* 0x0448 */
195#define CBE_IIC_IS_PMI 0x2
107 196
108 u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */ 197 u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */
109 198
110 /* IOC FIR */ 199 /* IOC FIR */
111 u64 ioc_fir_reset; /* 0x0500 */ 200 u64 ioc_fir_reset; /* 0x0500 */
112 u64 ioc_fir_set; 201 u64 ioc_fir_set; /* 0x0508 */
113 u64 ioc_checkstop_enable; 202 u64 ioc_checkstop_enable; /* 0x0510 */
114 u64 ioc_fir_error_mask; 203 u64 ioc_fir_error_mask; /* 0x0518 */
115 u64 ioc_syserr_enable; 204 u64 ioc_syserr_enable; /* 0x0520 */
116 u64 ioc_fir; 205 u64 ioc_fir; /* 0x0528 */
117 206
118 u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */ 207 u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */
119}; 208};
@@ -122,6 +211,48 @@ extern 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); 211extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
123 212
124 213
214struct cbe_mic_tm_regs {
215 u8 pad_0x0000_0x0040[0x0040 - 0x0000]; /* 0x0000 */
216
217 u64 mic_ctl_cnfg2; /* 0x0040 */
218#define CBE_MIC_ENABLE_AUX_TRC 0x8000000000000000LL
219#define CBE_MIC_DISABLE_PWR_SAV_2 0x0200000000000000LL
220#define CBE_MIC_DISABLE_AUX_TRC_WRAP 0x0100000000000000LL
221#define CBE_MIC_ENABLE_AUX_TRC_INT 0x0080000000000000LL
222
223 u64 pad_0x0048; /* 0x0048 */
224
225 u64 mic_aux_trc_base; /* 0x0050 */
226 u64 mic_aux_trc_max_addr; /* 0x0058 */
227 u64 mic_aux_trc_cur_addr; /* 0x0060 */
228 u64 mic_aux_trc_grf_addr; /* 0x0068 */
229 u64 mic_aux_trc_grf_data; /* 0x0070 */
230
231 u64 pad_0x0078; /* 0x0078 */
232
233 u64 mic_ctl_cnfg_0; /* 0x0080 */
234#define CBE_MIC_DISABLE_PWR_SAV_0 0x8000000000000000LL
235
236 u64 pad_0x0088; /* 0x0088 */
237
238 u64 slow_fast_timer_0; /* 0x0090 */
239 u64 slow_next_timer_0; /* 0x0098 */
240
241 u8 pad_0x00a0_0x01c0[0x01c0 - 0x0a0]; /* 0x00a0 */
242
243 u64 mic_ctl_cnfg_1; /* 0x01c0 */
244#define CBE_MIC_DISABLE_PWR_SAV_1 0x8000000000000000LL
245 u64 pad_0x01c8; /* 0x01c8 */
246
247 u64 slow_fast_timer_1; /* 0x01d0 */
248 u64 slow_next_timer_1; /* 0x01d8 */
249
250 u8 pad_0x01e0_0x1000[0x1000 - 0x01e0]; /* 0x01e0 */
251};
252
253extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
254extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
255
125/* Init this module early */ 256/* Init this module early */
126extern void cbe_regs_init(void); 257extern void cbe_regs_init(void);
127 258
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
new file mode 100644
index 000000000000..17831a92d91e
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -0,0 +1,225 @@
1/*
2 * thermal support for the cell processor
3 *
4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5 *
6 * Author: Christian Krafft <krafft@de.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/module.h>
24#include <linux/sysdev.h>
25#include <linux/kernel.h>
26#include <linux/cpu.h>
27#include <asm/spu.h>
28#include <asm/io.h>
29#include <asm/prom.h>
30
31#include "cbe_regs.h"
32
33static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
34{
35 struct spu *spu;
36
37 spu = container_of(sysdev, struct spu, sysdev);
38
39 return cbe_get_pmd_regs(spu->devnode);
40}
41
42/* returns the value for a given spu in a given register */
43static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
44{
45 unsigned int *id;
46 union spe_reg value;
47 struct spu *spu;
48
49 /* getting the id from the reg attribute will not work on future device-tree layouts
50 * in future we should store the id to the spu struct and use it here */
51 spu = container_of(sysdev, struct spu, sysdev);
52 id = (unsigned int *)get_property(spu->devnode, "reg", NULL);
53 value.val = in_be64(&reg->val);
54
55 return value.spe[*id];
56}
57
58static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
59{
60 int value;
61 struct cbe_pmd_regs __iomem *pmd_regs;
62
63 pmd_regs = get_pmd_regs(sysdev);
64
65 value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
66 /* clear all other bits */
67 value &= 0x3F;
68 /* temp is stored in steps of 2 degrees */
69 value *= 2;
70 /* base temp is 65 degrees */
71 value += 65;
72
73 return sprintf(buf, "%d\n", (int) value);
74}
75
76static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
77{
78 struct cbe_pmd_regs __iomem *pmd_regs;
79 u64 value;
80
81 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
82 value = in_be64(&pmd_regs->ts_ctsr2);
83
84 /* access the corresponding byte */
85 value >>= pos;
86 /* clear all other bits */
87 value &= 0x3F;
88 /* temp is stored in steps of 2 degrees */
89 value *= 2;
90 /* base temp is 65 degrees */
91 value += 65;
92
93 return sprintf(buf, "%d\n", (int) value);
94}
95
96
97/* shows the temperature of the DTS on the PPE,
98 * located near the linear thermal sensor */
99static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf)
100{
101 return ppe_show_temp(sysdev, buf, 32);
102}
103
104/* shows the temperature of the second DTS on the PPE */
105static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
106{
107 return ppe_show_temp(sysdev, buf, 0);
108}
109
110static struct sysdev_attribute attr_spu_temperature = {
111 .attr = {.name = "temperature", .mode = 0400 },
112 .show = spu_show_temp,
113};
114
115static struct attribute *spu_attributes[] = {
116 &attr_spu_temperature.attr,
117};
118
119static struct attribute_group spu_attribute_group = {
120 .name = "thermal",
121 .attrs = spu_attributes,
122};
123
124static struct sysdev_attribute attr_ppe_temperature0 = {
125 .attr = {.name = "temperature0", .mode = 0400 },
126 .show = ppe_show_temp0,
127};
128
129static struct sysdev_attribute attr_ppe_temperature1 = {
130 .attr = {.name = "temperature1", .mode = 0400 },
131 .show = ppe_show_temp1,
132};
133
134static struct attribute *ppe_attributes[] = {
135 &attr_ppe_temperature0.attr,
136 &attr_ppe_temperature1.attr,
137};
138
139static struct attribute_group ppe_attribute_group = {
140 .name = "thermal",
141 .attrs = ppe_attributes,
142};
143
144/*
145 * initialize throttling with default values
146 */
147static void __init init_default_values(void)
148{
149 int cpu;
150 struct cbe_pmd_regs __iomem *pmd_regs;
151 struct sys_device *sysdev;
152 union ppe_spe_reg tpr;
153 union spe_reg str1;
154 u64 str2;
155 union spe_reg cr1;
156 u64 cr2;
157
158 /* TPR defaults */
159 /* ppe
160 * 1F - no full stop
161 * 08 - dynamic throttling starts if over 80 degrees
162 * 03 - dynamic throttling ceases if below 70 degrees */
163 tpr.ppe = 0x1F0803;
164 /* spe
165 * 10 - full stopped when over 96 degrees
166 * 08 - dynamic throttling starts if over 80 degrees
167 * 03 - dynamic throttling ceases if below 70 degrees
168 */
169 tpr.spe = 0x100803;
170
171 /* STR defaults */
172 /* str1
173 * 10 - stop 16 of 32 cycles
174 */
175 str1.val = 0x1010101010101010ull;
176 /* str2
177 * 10 - stop 16 of 32 cycles
178 */
179 str2 = 0x10;
180
181 /* CR defaults */
182 /* cr1
183 * 4 - normal operation
184 */
185 cr1.val = 0x0404040404040404ull;
186 /* cr2
187 * 4 - normal operation
188 */
189 cr2 = 0x04;
190
191 for_each_possible_cpu (cpu) {
192 pr_debug("processing cpu %d\n", cpu);
193 sysdev = get_cpu_sysdev(cpu);
194 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
195
196 out_be64(&pmd_regs->tm_str2, str2);
197 out_be64(&pmd_regs->tm_str1.val, str1.val);
198 out_be64(&pmd_regs->tm_tpr.val, tpr.val);
199 out_be64(&pmd_regs->tm_cr1.val, cr1.val);
200 out_be64(&pmd_regs->tm_cr2, cr2);
201 }
202}
203
204
205static int __init thermal_init(void)
206{
207 init_default_values();
208
209 spu_add_sysdev_attr_group(&spu_attribute_group);
210 cpu_add_sysdev_attr_group(&ppe_attribute_group);
211
212 return 0;
213}
214module_init(thermal_init);
215
216static void __exit thermal_exit(void)
217{
218 spu_remove_sysdev_attr_group(&spu_attribute_group);
219 cpu_remove_sysdev_attr_group(&ppe_attribute_group);
220}
221module_exit(thermal_exit);
222
223MODULE_LICENSE("GPL");
224MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
225
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index 9f2e4ed20a57..c68fabdc7874 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -38,32 +38,16 @@
38#include "pervasive.h" 38#include "pervasive.h"
39#include "cbe_regs.h" 39#include "cbe_regs.h"
40 40
41static DEFINE_SPINLOCK(cbe_pervasive_lock); 41static void cbe_power_save(void)
42
43static void __init cbe_enable_pause_zero(void)
44{ 42{
45 unsigned long thread_switch_control; 43 unsigned long ctrl, thread_switch_control;
46 unsigned long temp_register; 44 ctrl = mfspr(SPRN_CTRLF);
47 struct cbe_pmd_regs __iomem *pregs;
48
49 spin_lock_irq(&cbe_pervasive_lock);
50 pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
51 if (pregs == NULL)
52 goto out;
53
54 pr_debug("Power Management: CPU %d\n", smp_processor_id());
55
56 /* Enable Pause(0) control bit */
57 temp_register = in_be64(&pregs->pm_control);
58
59 out_be64(&pregs->pm_control,
60 temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
61 45
62 /* Enable DEC and EE interrupt request */ 46 /* Enable DEC and EE interrupt request */
63 thread_switch_control = mfspr(SPRN_TSC_CELL); 47 thread_switch_control = mfspr(SPRN_TSC_CELL);
64 thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST; 48 thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
65 49
66 switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) { 50 switch (ctrl & CTRL_CT) {
67 case CTRL_CT0: 51 case CTRL_CT0:
68 thread_switch_control |= TSC_CELL_DEC_ENABLE_0; 52 thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
69 break; 53 break;
@@ -75,58 +59,21 @@ static void __init cbe_enable_pause_zero(void)
75 __FUNCTION__); 59 __FUNCTION__);
76 break; 60 break;
77 } 61 }
78
79 mtspr(SPRN_TSC_CELL, thread_switch_control); 62 mtspr(SPRN_TSC_CELL, thread_switch_control);
80 63
81out: 64 /*
82 spin_unlock_irq(&cbe_pervasive_lock); 65 * go into low thread priority, medium priority will be
83} 66 * restored for us after wake-up.
84
85static void cbe_idle(void)
86{
87 unsigned long ctrl;
88
89 /* Why do we do that on every idle ? Couldn't that be done once for
90 * all or do we lose the state some way ? Also, the pm_control
91 * register setting, that can't be set once at boot ? We really want
92 * to move that away in order to implement a simple powersave
93 */ 67 */
94 cbe_enable_pause_zero(); 68 HMT_low();
95
96 while (1) {
97 if (!need_resched()) {
98 local_irq_disable();
99 while (!need_resched()) {
100 /* go into low thread priority */
101 HMT_low();
102
103 /*
104 * atomically disable thread execution
105 * and runlatch.
106 * External and Decrementer exceptions
107 * are still handled when the thread
108 * is disabled but now enter in
109 * cbe_system_reset_exception()
110 */
111 ctrl = mfspr(SPRN_CTRLF);
112 ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
113 mtspr(SPRN_CTRLT, ctrl);
114 }
115 /* restore thread prio */
116 HMT_medium();
117 local_irq_enable();
118 }
119 69
120 /* 70 /*
121 * turn runlatch on again before scheduling the 71 * atomically disable thread execution and runlatch.
122 * process we just woke up 72 * External and Decrementer exceptions are still handled when the
123 */ 73 * thread is disabled but now enter in cbe_system_reset_exception()
124 ppc64_runlatch_on(); 74 */
125 75 ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
126 preempt_enable_no_resched(); 76 mtspr(SPRN_CTRLT, ctrl);
127 schedule();
128 preempt_disable();
129 }
130} 77}
131 78
132static int cbe_system_reset_exception(struct pt_regs *regs) 79static int cbe_system_reset_exception(struct pt_regs *regs)
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(struct pt_regs *regs)
158 105
159void __init cbe_pervasive_init(void) 106void __init cbe_pervasive_init(void)
160{ 107{
108 int cpu;
161 if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) 109 if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
162 return; 110 return;
163 111
164 ppc_md.idle_loop = cbe_idle; 112 for_each_possible_cpu(cpu) {
113 struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu);
114 if (!regs)
115 continue;
116
117 /* Enable Pause(0) control bit */
118 out_be64(&regs->pmcr, in_be64(&regs->pmcr) |
119 CBE_PMD_PAUSE_ZERO_CONTROL);
120 }
121
122 ppc_md.power_save = cbe_power_save;
165 ppc_md.system_reset_exception = cbe_system_reset_exception; 123 ppc_md.system_reset_exception = cbe_system_reset_exception;
166} 124}
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c
new file mode 100644
index 000000000000..30d17ce236a7
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pmu.c
@@ -0,0 +1,328 @@
1/*
2 * Cell Broadband Engine Performance Monitor
3 *
4 * (C) Copyright IBM Corporation 2001,2006
5 *
6 * Author:
7 * David Erb (djerb@us.ibm.com)
8 * Kevin Corry (kevcorry@us.ibm.com)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#include <linux/types.h>
26#include <asm/io.h>
27#include <asm/machdep.h>
28#include <asm/reg.h>
29#include <asm/spu.h>
30
31#include "cbe_regs.h"
32#include "interrupt.h"
33#include "pmu.h"
34
35/*
36 * When writing to write-only mmio addresses, save a shadow copy. All of the
37 * registers are 32-bit, but stored in the upper-half of a 64-bit field in
38 * pmd_regs.
39 */
40
41#define WRITE_WO_MMIO(reg, x) \
42 do { \
43 u32 _x = (x); \
44 struct cbe_pmd_regs __iomem *pmd_regs; \
45 struct cbe_pmd_shadow_regs *shadow_regs; \
46 pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
47 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
48 out_be64(&(pmd_regs->reg), (((u64)_x) << 32)); \
49 shadow_regs->reg = _x; \
50 } while (0)
51
52#define READ_SHADOW_REG(val, reg) \
53 do { \
54 struct cbe_pmd_shadow_regs *shadow_regs; \
55 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
56 (val) = shadow_regs->reg; \
57 } while (0)
58
59#define READ_MMIO_UPPER32(val, reg) \
60 do { \
61 struct cbe_pmd_regs __iomem *pmd_regs; \
62 pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
63 (val) = (u32)(in_be64(&pmd_regs->reg) >> 32); \
64 } while (0)
65
66/*
67 * Physical counter registers.
68 * Each physical counter can act as one 32-bit counter or two 16-bit counters.
69 */
70
71u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
72{
73 u32 val_in_latch, val = 0;
74
75 if (phys_ctr < NR_PHYS_CTRS) {
76 READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
77
78 /* Read the latch or the actual counter, whichever is newer. */
79 if (val_in_latch & (1 << phys_ctr)) {
80 READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
81 } else {
82 READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
83 }
84 }
85
86 return val;
87}
88
89void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
90{
91 struct cbe_pmd_shadow_regs *shadow_regs;
92 u32 pm_ctrl;
93
94 if (phys_ctr < NR_PHYS_CTRS) {
95 /* Writing to a counter only writes to a hardware latch.
96 * The new value is not propagated to the actual counter
97 * until the performance monitor is enabled.
98 */
99 WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
100
101 pm_ctrl = cbe_read_pm(cpu, pm_control);
102 if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
103 /* The counters are already active, so we need to
104 * rewrite the pm_control register to "re-enable"
105 * the PMU.
106 */
107 cbe_write_pm(cpu, pm_control, pm_ctrl);
108 } else {
109 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
110 shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
111 }
112 }
113}
114
115/*
116 * "Logical" counter registers.
117 * These will read/write 16-bits or 32-bits depending on the
118 * current size of the counter. Counters 4 - 7 are always 16-bit.
119 */
120
121u32 cbe_read_ctr(u32 cpu, u32 ctr)
122{
123 u32 val;
124 u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
125
126 val = cbe_read_phys_ctr(cpu, phys_ctr);
127
128 if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
129 val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
130
131 return val;
132}
133
134void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
135{
136 u32 phys_ctr;
137 u32 phys_val;
138
139 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
140
141 if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
142 phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
143
144 if (ctr < NR_PHYS_CTRS)
145 val = (val << 16) | (phys_val & 0xffff);
146 else
147 val = (val & 0xffff) | (phys_val & 0xffff0000);
148 }
149
150 cbe_write_phys_ctr(cpu, phys_ctr, val);
151}
152
153/*
154 * Counter-control registers.
155 * Each "logical" counter has a corresponding control register.
156 */
157
158u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
159{
160 u32 pm07_control = 0;
161
162 if (ctr < NR_CTRS)
163 READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
164
165 return pm07_control;
166}
167
168void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
169{
170 if (ctr < NR_CTRS)
171 WRITE_WO_MMIO(pm07_control[ctr], val);
172}
173
174/*
175 * Other PMU control registers. Most of these are write-only.
176 */
177
178u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
179{
180 u32 val = 0;
181
182 switch (reg) {
183 case group_control:
184 READ_SHADOW_REG(val, group_control);
185 break;
186
187 case debug_bus_control:
188 READ_SHADOW_REG(val, debug_bus_control);
189 break;
190
191 case trace_address:
192 READ_MMIO_UPPER32(val, trace_address);
193 break;
194
195 case ext_tr_timer:
196 READ_SHADOW_REG(val, ext_tr_timer);
197 break;
198
199 case pm_status:
200 READ_MMIO_UPPER32(val, pm_status);
201 break;
202
203 case pm_control:
204 READ_SHADOW_REG(val, pm_control);
205 break;
206
207 case pm_interval:
208 READ_SHADOW_REG(val, pm_interval);
209 break;
210
211 case pm_start_stop:
212 READ_SHADOW_REG(val, pm_start_stop);
213 break;
214 }
215
216 return val;
217}
218
219void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
220{
221 switch (reg) {
222 case group_control:
223 WRITE_WO_MMIO(group_control, val);
224 break;
225
226 case debug_bus_control:
227 WRITE_WO_MMIO(debug_bus_control, val);
228 break;
229
230 case trace_address:
231 WRITE_WO_MMIO(trace_address, val);
232 break;
233
234 case ext_tr_timer:
235 WRITE_WO_MMIO(ext_tr_timer, val);
236 break;
237
238 case pm_status:
239 WRITE_WO_MMIO(pm_status, val);
240 break;
241
242 case pm_control:
243 WRITE_WO_MMIO(pm_control, val);
244 break;
245
246 case pm_interval:
247 WRITE_WO_MMIO(pm_interval, val);
248 break;
249
250 case pm_start_stop:
251 WRITE_WO_MMIO(pm_start_stop, val);
252 break;
253 }
254}
255
256/*
257 * Get/set the size of a physical counter to either 16 or 32 bits.
258 */
259
260u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
261{
262 u32 pm_ctrl, size = 0;
263
264 if (phys_ctr < NR_PHYS_CTRS) {
265 pm_ctrl = cbe_read_pm(cpu, pm_control);
266 size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
267 }
268
269 return size;
270}
271
272void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
273{
274 u32 pm_ctrl;
275
276 if (phys_ctr < NR_PHYS_CTRS) {
277 pm_ctrl = cbe_read_pm(cpu, pm_control);
278 switch (ctr_size) {
279 case 16:
280 pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
281 break;
282
283 case 32:
284 pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
285 break;
286 }
287 cbe_write_pm(cpu, pm_control, pm_ctrl);
288 }
289}
290
291/*
292 * Enable/disable the entire performance monitoring unit.
293 * When we enable the PMU, all pending writes to counters get committed.
294 */
295
296void cbe_enable_pm(u32 cpu)
297{
298 struct cbe_pmd_shadow_regs *shadow_regs;
299 u32 pm_ctrl;
300
301 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
302 shadow_regs->counter_value_in_latch = 0;
303
304 pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
305 cbe_write_pm(cpu, pm_control, pm_ctrl);
306}
307
308void cbe_disable_pm(u32 cpu)
309{
310 u32 pm_ctrl;
311 pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
312 cbe_write_pm(cpu, pm_control, pm_ctrl);
313}
314
315/*
316 * Reading from the trace_buffer.
317 * The trace buffer is two 64-bit registers. Reading from
318 * the second half automatically increments the trace_address.
319 */
320
321void cbe_read_trace_buffer(u32 cpu, u64 *buf)
322{
323 struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
324
325 *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
326 *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
327}
328
diff --git a/arch/powerpc/platforms/cell/pmu.h b/arch/powerpc/platforms/cell/pmu.h
new file mode 100644
index 000000000000..eb1e8e0af910
--- /dev/null
+++ b/arch/powerpc/platforms/cell/pmu.h
@@ -0,0 +1,57 @@
1/*
2 * Cell Broadband Engine Performance Monitor
3 *
4 * (C) Copyright IBM Corporation 2001,2006
5 *
6 * Author:
7 * David Erb (djerb@us.ibm.com)
8 * Kevin Corry (kevcorry@us.ibm.com)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25#ifndef __PERFMON_H__
26#define __PERFMON_H__
27
28enum pm_reg_name {
29 group_control,
30 debug_bus_control,
31 trace_address,
32 ext_tr_timer,
33 pm_status,
34 pm_control,
35 pm_interval,
36 pm_start_stop,
37};
38
39extern u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr);
40extern void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
41extern u32 cbe_read_ctr(u32 cpu, u32 ctr);
42extern void cbe_write_ctr(u32 cpu, u32 ctr, u32 val);
43
44extern u32 cbe_read_pm07_control(u32 cpu, u32 ctr);
45extern void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val);
46extern u32 cbe_read_pm (u32 cpu, enum pm_reg_name reg);
47extern void cbe_write_pm (u32 cpu, enum pm_reg_name reg, u32 val);
48
49extern u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr);
50extern void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
51
52extern void cbe_enable_pm(u32 cpu);
53extern void cbe_disable_pm(u32 cpu);
54
55extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
56
57#endif
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 7aa809d5a244..d5aeb3c6dd45 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -38,6 +38,7 @@
38#include <asm/spu.h> 38#include <asm/spu.h>
39#include <asm/spu_priv1.h> 39#include <asm/spu_priv1.h>
40#include <asm/mmu_context.h> 40#include <asm/mmu_context.h>
41#include <asm/xmon.h>
41 42
42#include "interrupt.h" 43#include "interrupt.h"
43 44
@@ -89,7 +90,30 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
89 printk("%s: invalid access during switch!\n", __func__); 90 printk("%s: invalid access during switch!\n", __func__);
90 return 1; 91 return 1;
91 } 92 }
92 if (!mm || (REGION_ID(ea) != USER_REGION_ID)) { 93 esid = (ea & ESID_MASK) | SLB_ESID_V;
94
95 switch(REGION_ID(ea)) {
96 case USER_REGION_ID:
97#ifdef CONFIG_HUGETLB_PAGE
98 if (in_hugepage_area(mm->context, ea))
99 llp = mmu_psize_defs[mmu_huge_psize].sllp;
100 else
101#endif
102 llp = mmu_psize_defs[mmu_virtual_psize].sllp;
103 vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
104 SLB_VSID_USER | llp;
105 break;
106 case VMALLOC_REGION_ID:
107 llp = mmu_psize_defs[mmu_virtual_psize].sllp;
108 vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
109 SLB_VSID_KERNEL | llp;
110 break;
111 case KERNEL_REGION_ID:
112 llp = mmu_psize_defs[mmu_linear_psize].sllp;
113 vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
114 SLB_VSID_KERNEL | llp;
115 break;
116 default:
93 /* Future: support kernel segments so that drivers 117 /* Future: support kernel segments so that drivers
94 * can use SPUs. 118 * can use SPUs.
95 */ 119 */
@@ -97,16 +121,6 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
97 return 1; 121 return 1;
98 } 122 }
99 123
100 esid = (ea & ESID_MASK) | SLB_ESID_V;
101#ifdef CONFIG_HUGETLB_PAGE
102 if (in_hugepage_area(mm->context, ea))
103 llp = mmu_psize_defs[mmu_huge_psize].sllp;
104 else
105#endif
106 llp = mmu_psize_defs[mmu_virtual_psize].sllp;
107 vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
108 SLB_VSID_USER | llp;
109
110 out_be64(&priv2->slb_index_W, spu->slb_replace); 124 out_be64(&priv2->slb_index_W, spu->slb_replace);
111 out_be64(&priv2->slb_vsid_RW, vsid); 125 out_be64(&priv2->slb_vsid_RW, vsid);
112 out_be64(&priv2->slb_esid_RW, esid); 126 out_be64(&priv2->slb_esid_RW, esid);
@@ -320,6 +334,7 @@ static void spu_free_irqs(struct spu *spu)
320} 334}
321 335
322static struct list_head spu_list[MAX_NUMNODES]; 336static struct list_head spu_list[MAX_NUMNODES];
337static LIST_HEAD(spu_full_list);
323static DEFINE_MUTEX(spu_mutex); 338static DEFINE_MUTEX(spu_mutex);
324 339
325static void spu_init_channels(struct spu *spu) 340static void spu_init_channels(struct spu *spu)
@@ -364,8 +379,7 @@ struct spu *spu_alloc_node(int node)
364 if (!list_empty(&spu_list[node])) { 379 if (!list_empty(&spu_list[node])) {
365 spu = list_entry(spu_list[node].next, struct spu, list); 380 spu = list_entry(spu_list[node].next, struct spu, list);
366 list_del_init(&spu->list); 381 list_del_init(&spu->list);
367 pr_debug("Got SPU %x %d %d\n", 382 pr_debug("Got SPU %d %d\n", spu->number, spu->node);
368 spu->isrc, spu->number, spu->node);
369 spu_init_channels(spu); 383 spu_init_channels(spu);
370 } 384 }
371 mutex_unlock(&spu_mutex); 385 mutex_unlock(&spu_mutex);
@@ -591,7 +605,6 @@ static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np
591 605
592 /* Add the node number */ 606 /* Add the node number */
593 isrc |= spu->node << IIC_IRQ_NODE_SHIFT; 607 isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
594 spu->isrc = isrc;
595 608
596 /* Now map interrupts of all 3 classes */ 609 /* Now map interrupts of all 3 classes */
597 spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); 610 spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
@@ -758,15 +771,56 @@ struct sysdev_class spu_sysdev_class = {
758 set_kset_name("spu") 771 set_kset_name("spu")
759}; 772};
760 773
761static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf) 774int spu_add_sysdev_attr(struct sysdev_attribute *attr)
762{ 775{
763 struct spu *spu = container_of(sysdev, struct spu, sysdev); 776 struct spu *spu;
764 return sprintf(buf, "%d\n", spu->isrc); 777 mutex_lock(&spu_mutex);
778
779 list_for_each_entry(spu, &spu_full_list, full_list)
780 sysdev_create_file(&spu->sysdev, attr);
765 781
782 mutex_unlock(&spu_mutex);
783 return 0;
766} 784}
767static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL); 785EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
786
787int spu_add_sysdev_attr_group(struct attribute_group *attrs)
788{
789 struct spu *spu;
790 mutex_lock(&spu_mutex);
768 791
769extern int attach_sysdev_to_node(struct sys_device *dev, int nid); 792 list_for_each_entry(spu, &spu_full_list, full_list)
793 sysfs_create_group(&spu->sysdev.kobj, attrs);
794
795 mutex_unlock(&spu_mutex);
796 return 0;
797}
798EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
799
800
801void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
802{
803 struct spu *spu;
804 mutex_lock(&spu_mutex);
805
806 list_for_each_entry(spu, &spu_full_list, full_list)
807 sysdev_remove_file(&spu->sysdev, attr);
808
809 mutex_unlock(&spu_mutex);
810}
811EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
812
813void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
814{
815 struct spu *spu;
816 mutex_lock(&spu_mutex);
817
818 list_for_each_entry(spu, &spu_full_list, full_list)
819 sysfs_remove_group(&spu->sysdev.kobj, attrs);
820
821 mutex_unlock(&spu_mutex);
822}
823EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
770 824
771static int spu_create_sysdev(struct spu *spu) 825static int spu_create_sysdev(struct spu *spu)
772{ 826{
@@ -781,8 +835,6 @@ static int spu_create_sysdev(struct spu *spu)
781 return ret; 835 return ret;
782 } 836 }
783 837
784 if (spu->isrc != 0)
785 sysdev_create_file(&spu->sysdev, &attr_isrc);
786 sysfs_add_device_to_node(&spu->sysdev, spu->nid); 838 sysfs_add_device_to_node(&spu->sysdev, spu->nid);
787 839
788 return 0; 840 return 0;
@@ -790,7 +842,6 @@ static int spu_create_sysdev(struct spu *spu)
790 842
791static void spu_destroy_sysdev(struct spu *spu) 843static void spu_destroy_sysdev(struct spu *spu)
792{ 844{
793 sysdev_remove_file(&spu->sysdev, &attr_isrc);
794 sysfs_remove_device_from_node(&spu->sysdev, spu->nid); 845 sysfs_remove_device_from_node(&spu->sysdev, spu->nid);
795 sysdev_unregister(&spu->sysdev); 846 sysdev_unregister(&spu->sysdev);
796} 847}
@@ -830,7 +881,7 @@ static int __init create_spu(struct device_node *spe)
830 if (ret) 881 if (ret)
831 goto out_unmap; 882 goto out_unmap;
832 spin_lock_init(&spu->register_lock); 883 spin_lock_init(&spu->register_lock);
833 spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1)); 884 spu_mfc_sdr_setup(spu);
834 spu_mfc_sr1_set(spu, 0x33); 885 spu_mfc_sr1_set(spu, 0x33);
835 mutex_lock(&spu_mutex); 886 mutex_lock(&spu_mutex);
836 887
@@ -844,10 +895,13 @@ static int __init create_spu(struct device_node *spe)
844 goto out_free_irqs; 895 goto out_free_irqs;
845 896
846 list_add(&spu->list, &spu_list[spu->node]); 897 list_add(&spu->list, &spu_list[spu->node]);
898 list_add(&spu->full_list, &spu_full_list);
899 spu->devnode = of_node_get(spe);
900
847 mutex_unlock(&spu_mutex); 901 mutex_unlock(&spu_mutex);
848 902
849 pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n", 903 pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
850 spu->name, spu->isrc, spu->local_store, 904 spu->name, spu->local_store,
851 spu->problem, spu->priv1, spu->priv2, spu->number); 905 spu->problem, spu->priv1, spu->priv2, spu->number);
852 goto out; 906 goto out;
853 907
@@ -866,6 +920,9 @@ out:
866static void destroy_spu(struct spu *spu) 920static void destroy_spu(struct spu *spu)
867{ 921{
868 list_del_init(&spu->list); 922 list_del_init(&spu->list);
923 list_del_init(&spu->full_list);
924
925 of_node_put(spu->devnode);
869 926
870 spu_destroy_sysdev(spu); 927 spu_destroy_sysdev(spu);
871 spu_free_irqs(spu); 928 spu_free_irqs(spu);
@@ -912,6 +969,9 @@ static int __init init_spu_base(void)
912 break; 969 break;
913 } 970 }
914 } 971 }
972
973 xmon_register_spus(&spu_full_list);
974
915 return ret; 975 return ret;
916} 976}
917module_init(init_spu_base); 977module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
index 71b69f0a1a48..90011f9aab3f 100644
--- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -84,9 +84,9 @@ static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
84 out_be64(&spu->priv1->mfc_dsisr_RW, dsisr); 84 out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
85} 85}
86 86
87static void mfc_sdr_set(struct spu *spu, u64 sdr) 87static void mfc_sdr_setup(struct spu *spu)
88{ 88{
89 out_be64(&spu->priv1->mfc_sdr_RW, sdr); 89 out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
90} 90}
91 91
92static void mfc_sr1_set(struct spu *spu, u64 sr1) 92static void mfc_sr1_set(struct spu *spu, u64 sr1)
@@ -146,7 +146,7 @@ const struct spu_priv1_ops spu_priv1_mmio_ops =
146 .mfc_dar_get = mfc_dar_get, 146 .mfc_dar_get = mfc_dar_get,
147 .mfc_dsisr_get = mfc_dsisr_get, 147 .mfc_dsisr_get = mfc_dsisr_get,
148 .mfc_dsisr_set = mfc_dsisr_set, 148 .mfc_dsisr_set = mfc_dsisr_set,
149 .mfc_sdr_set = mfc_sdr_set, 149 .mfc_sdr_setup = mfc_sdr_setup,
150 .mfc_sr1_set = mfc_sr1_set, 150 .mfc_sr1_set = mfc_sr1_set,
151 .mfc_sr1_get = mfc_sr1_get, 151 .mfc_sr1_get = mfc_sr1_get,
152 .mfc_tclass_id_set = mfc_tclass_id_set, 152 .mfc_tclass_id_set = mfc_tclass_id_set,
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 034cf6af53a2..48eb050bcf4b 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -120,6 +120,33 @@ void spu_unmap_mappings(struct spu_context *ctx)
120 unmap_mapping_range(ctx->signal2, 0, 0x4000, 1); 120 unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
121} 121}
122 122
123int spu_acquire_exclusive(struct spu_context *ctx)
124{
125 int ret = 0;
126
127 down_write(&ctx->state_sema);
128 /* ctx is about to be freed, can't acquire any more */
129 if (!ctx->owner) {
130 ret = -EINVAL;
131 goto out;
132 }
133
134 if (ctx->state == SPU_STATE_SAVED) {
135 ret = spu_activate(ctx, 0);
136 if (ret)
137 goto out;
138 ctx->state = SPU_STATE_RUNNABLE;
139 } else {
140 /* We need to exclude userspace access to the context. */
141 spu_unmap_mappings(ctx);
142 }
143
144out:
145 if (ret)
146 up_write(&ctx->state_sema);
147 return ret;
148}
149
123int spu_acquire_runnable(struct spu_context *ctx) 150int spu_acquire_runnable(struct spu_context *ctx)
124{ 151{
125 int ret = 0; 152 int ret = 0;
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 533e2723e184..0ea2361865a2 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -1343,6 +1343,37 @@ static struct file_operations spufs_mfc_fops = {
1343 .mmap = spufs_mfc_mmap, 1343 .mmap = spufs_mfc_mmap,
1344}; 1344};
1345 1345
1346
1347static int spufs_recycle_open(struct inode *inode, struct file *file)
1348{
1349 file->private_data = SPUFS_I(inode)->i_ctx;
1350 return nonseekable_open(inode, file);
1351}
1352
1353static ssize_t spufs_recycle_write(struct file *file,
1354 const char __user *buffer, size_t size, loff_t *pos)
1355{
1356 struct spu_context *ctx = file->private_data;
1357 int ret;
1358
1359 if (!(ctx->flags & SPU_CREATE_ISOLATE))
1360 return -EINVAL;
1361
1362 if (size < 1)
1363 return -EINVAL;
1364
1365 ret = spu_recycle_isolated(ctx);
1366
1367 if (ret)
1368 return ret;
1369 return size;
1370}
1371
1372static struct file_operations spufs_recycle_fops = {
1373 .open = spufs_recycle_open,
1374 .write = spufs_recycle_write,
1375};
1376
1346static void spufs_npc_set(void *data, u64 val) 1377static void spufs_npc_set(void *data, u64 val)
1347{ 1378{
1348 struct spu_context *ctx = data; 1379 struct spu_context *ctx = data;
@@ -1531,3 +1562,26 @@ struct tree_descr spufs_dir_contents[] = {
1531 { "object-id", &spufs_object_id_ops, 0666, }, 1562 { "object-id", &spufs_object_id_ops, 0666, },
1532 {}, 1563 {},
1533}; 1564};
1565
1566struct tree_descr spufs_dir_nosched_contents[] = {
1567 { "mem", &spufs_mem_fops, 0666, },
1568 { "mbox", &spufs_mbox_fops, 0444, },
1569 { "ibox", &spufs_ibox_fops, 0444, },
1570 { "wbox", &spufs_wbox_fops, 0222, },
1571 { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
1572 { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
1573 { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
1574 { "signal1", &spufs_signal1_fops, 0666, },
1575 { "signal2", &spufs_signal2_fops, 0666, },
1576 { "signal1_type", &spufs_signal1_type, 0666, },
1577 { "signal2_type", &spufs_signal2_type, 0666, },
1578 { "mss", &spufs_mss_fops, 0666, },
1579 { "mfc", &spufs_mfc_fops, 0666, },
1580 { "cntl", &spufs_cntl_fops, 0666, },
1581 { "npc", &spufs_npc_ops, 0666, },
1582 { "psmap", &spufs_psmap_fops, 0666, },
1583 { "phys-id", &spufs_id_ops, 0666, },
1584 { "object-id", &spufs_object_id_ops, 0666, },
1585 { "recycle", &spufs_recycle_fops, 0222, },
1586 {},
1587};
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index d805ffed892d..59c87f12da5a 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -219,8 +219,11 @@ static char *spu_hw_get_ls(struct spu_context *ctx)
219 219
220static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val) 220static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
221{ 221{
222 eieio(); 222 spin_lock_irq(&ctx->spu->register_lock);
223 if (val & SPU_RUNCNTL_ISOLATE)
224 out_be64(&ctx->spu->priv2->spu_privcntl_RW, 4LL);
223 out_be32(&ctx->spu->problem->spu_runcntl_RW, val); 225 out_be32(&ctx->spu->problem->spu_runcntl_RW, val);
226 spin_unlock_irq(&ctx->spu->register_lock);
224} 227}
225 228
226static void spu_hw_runcntl_stop(struct spu_context *ctx) 229static void spu_hw_runcntl_stop(struct spu_context *ctx)
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 427d00a4f6a0..9e457be140ef 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -33,6 +33,8 @@
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/parser.h> 34#include <linux/parser.h>
35 35
36#include <asm/prom.h>
37#include <asm/spu_priv1.h>
36#include <asm/io.h> 38#include <asm/io.h>
37#include <asm/semaphore.h> 39#include <asm/semaphore.h>
38#include <asm/spu.h> 40#include <asm/spu.h>
@@ -41,6 +43,7 @@
41#include "spufs.h" 43#include "spufs.h"
42 44
43static kmem_cache_t *spufs_inode_cache; 45static kmem_cache_t *spufs_inode_cache;
46static char *isolated_loader;
44 47
45static struct inode * 48static struct inode *
46spufs_alloc_inode(struct super_block *sb) 49spufs_alloc_inode(struct super_block *sb)
@@ -232,6 +235,95 @@ struct file_operations spufs_context_fops = {
232 .fsync = simple_sync_file, 235 .fsync = simple_sync_file,
233}; 236};
234 237
238static int spu_setup_isolated(struct spu_context *ctx)
239{
240 int ret;
241 u64 __iomem *mfc_cntl;
242 u64 sr1;
243 u32 status;
244 unsigned long timeout;
245 const u32 status_loading = SPU_STATUS_RUNNING
246 | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
247
248 if (!isolated_loader)
249 return -ENODEV;
250
251 if ((ret = spu_acquire_exclusive(ctx)) != 0)
252 return ret;
253
254 mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
255
256 /* purge the MFC DMA queue to ensure no spurious accesses before we
257 * enter kernel mode */
258 timeout = jiffies + HZ;
259 out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST);
260 while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK)
261 != MFC_CNTL_PURGE_DMA_COMPLETE) {
262 if (time_after(jiffies, timeout)) {
263 printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
264 __FUNCTION__);
265 ret = -EIO;
266 goto out_unlock;
267 }
268 cond_resched();
269 }
270
271 /* put the SPE in kernel mode to allow access to the loader */
272 sr1 = spu_mfc_sr1_get(ctx->spu);
273 sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
274 spu_mfc_sr1_set(ctx->spu, sr1);
275
276 /* start the loader */
277 ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32);
278 ctx->ops->signal2_write(ctx,
279 (unsigned long)isolated_loader & 0xffffffff);
280
281 ctx->ops->runcntl_write(ctx,
282 SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
283
284 ret = 0;
285 timeout = jiffies + HZ;
286 while (((status = ctx->ops->status_read(ctx)) & status_loading) ==
287 status_loading) {
288 if (time_after(jiffies, timeout)) {
289 printk(KERN_ERR "%s: timeout waiting for loader\n",
290 __FUNCTION__);
291 ret = -EIO;
292 goto out_drop_priv;
293 }
294 cond_resched();
295 }
296
297 if (!(status & SPU_STATUS_RUNNING)) {
298 /* If isolated LOAD has failed: run SPU, we will get a stop-and
299 * signal later. */
300 pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
301 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
302 ret = -EACCES;
303
304 } else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
305 /* This isn't allowed by the CBEA, but check anyway */
306 pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
307 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
308 ret = -EINVAL;
309 }
310
311out_drop_priv:
312 /* Finished accessing the loader. Drop kernel mode */
313 sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
314 spu_mfc_sr1_set(ctx->spu, sr1);
315
316out_unlock:
317 spu_release_exclusive(ctx);
318 return ret;
319}
320
321int spu_recycle_isolated(struct spu_context *ctx)
322{
323 ctx->ops->runcntl_stop(ctx);
324 return spu_setup_isolated(ctx);
325}
326
235static int 327static int
236spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, 328spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
237 int mode) 329 int mode)
@@ -255,10 +347,14 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
255 goto out_iput; 347 goto out_iput;
256 348
257 ctx->flags = flags; 349 ctx->flags = flags;
258
259 inode->i_op = &spufs_dir_inode_operations; 350 inode->i_op = &spufs_dir_inode_operations;
260 inode->i_fop = &simple_dir_operations; 351 inode->i_fop = &simple_dir_operations;
261 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx); 352 if (flags & SPU_CREATE_NOSCHED)
353 ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
354 mode, ctx);
355 else
356 ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
357
262 if (ret) 358 if (ret)
263 goto out_free_ctx; 359 goto out_free_ctx;
264 360
@@ -307,6 +403,16 @@ static int spufs_create_context(struct inode *inode,
307{ 403{
308 int ret; 404 int ret;
309 405
406 ret = -EPERM;
407 if ((flags & SPU_CREATE_NOSCHED) &&
408 !capable(CAP_SYS_NICE))
409 goto out_unlock;
410
411 ret = -EINVAL;
412 if ((flags & (SPU_CREATE_NOSCHED | SPU_CREATE_ISOLATE))
413 == SPU_CREATE_ISOLATE)
414 goto out_unlock;
415
310 ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); 416 ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
311 if (ret) 417 if (ret)
312 goto out_unlock; 418 goto out_unlock;
@@ -326,6 +432,13 @@ static int spufs_create_context(struct inode *inode,
326out_unlock: 432out_unlock:
327 mutex_unlock(&inode->i_mutex); 433 mutex_unlock(&inode->i_mutex);
328out: 434out:
435 if (ret >= 0 && (flags & SPU_CREATE_ISOLATE)) {
436 int setup_err = spu_setup_isolated(
437 SPUFS_I(dentry->d_inode)->i_ctx);
438 if (setup_err)
439 ret = setup_err;
440 }
441
329 dput(dentry); 442 dput(dentry);
330 return ret; 443 return ret;
331} 444}
@@ -540,6 +653,30 @@ spufs_parse_options(char *options, struct inode *root)
540 return 1; 653 return 1;
541} 654}
542 655
656static void
657spufs_init_isolated_loader(void)
658{
659 struct device_node *dn;
660 const char *loader;
661 int size;
662
663 dn = of_find_node_by_path("/spu-isolation");
664 if (!dn)
665 return;
666
667 loader = get_property(dn, "loader", &size);
668 if (!loader)
669 return;
670
671 /* kmalloc should align on a 16 byte boundary..* */
672 isolated_loader = kmalloc(size, GFP_KERNEL);
673 if (!isolated_loader)
674 return;
675
676 memcpy(isolated_loader, loader, size);
677 printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
678}
679
543static int 680static int
544spufs_create_root(struct super_block *sb, void *data) 681spufs_create_root(struct super_block *sb, void *data)
545{ 682{
@@ -625,6 +762,8 @@ static int __init spufs_init(void)
625 ret = register_spu_syscalls(&spufs_calls); 762 ret = register_spu_syscalls(&spufs_calls);
626 if (ret) 763 if (ret)
627 goto out_fs; 764 goto out_fs;
765
766 spufs_init_isolated_loader();
628 return 0; 767 return 0;
629out_fs: 768out_fs:
630 unregister_filesystem(&spufs_type); 769 unregister_filesystem(&spufs_type);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 63df8cf4ba16..a4a0080c2233 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -1,3 +1,5 @@
1#define DEBUG
2
1#include <linux/wait.h> 3#include <linux/wait.h>
2#include <linux/ptrace.h> 4#include <linux/ptrace.h>
3 5
@@ -51,11 +53,17 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
51static inline int spu_run_init(struct spu_context *ctx, u32 * npc) 53static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
52{ 54{
53 int ret; 55 int ret;
56 unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
54 57
55 if ((ret = spu_acquire_runnable(ctx)) != 0) 58 if ((ret = spu_acquire_runnable(ctx)) != 0)
56 return ret; 59 return ret;
57 ctx->ops->npc_write(ctx, *npc); 60
58 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 61 /* if we're in isolated mode, we would have started the SPU
62 * earlier, so don't do it again now. */
63 if (!(ctx->flags & SPU_CREATE_ISOLATE)) {
64 ctx->ops->npc_write(ctx, *npc);
65 ctx->ops->runcntl_write(ctx, runcntl);
66 }
59 return 0; 67 return 0;
60} 68}
61 69
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index a0f55ca2d488..f438f0b8525d 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -135,6 +135,7 @@ struct spufs_inode_info {
135 container_of(inode, struct spufs_inode_info, vfs_inode) 135 container_of(inode, struct spufs_inode_info, vfs_inode)
136 136
137extern struct tree_descr spufs_dir_contents[]; 137extern struct tree_descr spufs_dir_contents[];
138extern struct tree_descr spufs_dir_nosched_contents[];
138 139
139/* system call implementation */ 140/* system call implementation */
140long spufs_run_spu(struct file *file, 141long spufs_run_spu(struct file *file,
@@ -162,6 +163,12 @@ void spu_acquire(struct spu_context *ctx);
162void spu_release(struct spu_context *ctx); 163void spu_release(struct spu_context *ctx);
163int spu_acquire_runnable(struct spu_context *ctx); 164int spu_acquire_runnable(struct spu_context *ctx);
164void spu_acquire_saved(struct spu_context *ctx); 165void spu_acquire_saved(struct spu_context *ctx);
166int spu_acquire_exclusive(struct spu_context *ctx);
167
168static inline void spu_release_exclusive(struct spu_context *ctx)
169{
170 up_write(&ctx->state_sema);
171}
165 172
166int spu_activate(struct spu_context *ctx, u64 flags); 173int spu_activate(struct spu_context *ctx, u64 flags);
167void spu_deactivate(struct spu_context *ctx); 174void spu_deactivate(struct spu_context *ctx);
@@ -169,6 +176,7 @@ void spu_yield(struct spu_context *ctx);
169int __init spu_sched_init(void); 176int __init spu_sched_init(void);
170void __exit spu_sched_exit(void); 177void __exit spu_sched_exit(void);
171 178
179int spu_recycle_isolated(struct spu_context *ctx);
172/* 180/*
173 * spufs_wait 181 * spufs_wait
174 * Same as wait_event_interruptible(), except that here 182 * Same as wait_event_interruptible(), except that here
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 0f782ca662ba..c08981ff7fc6 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -102,7 +102,7 @@ static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
102 * saved at this time. 102 * saved at this time.
103 */ 103 */
104 isolate_state = SPU_STATUS_ISOLATED_STATE | 104 isolate_state = SPU_STATUS_ISOLATED_STATE |
105 SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS; 105 SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS;
106 return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0; 106 return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
107} 107}
108 108
@@ -1046,12 +1046,12 @@ static inline int suspend_spe(struct spu_state *csa, struct spu *spu)
1046 */ 1046 */
1047 if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) { 1047 if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
1048 if (in_be32(&prob->spu_status_R) & 1048 if (in_be32(&prob->spu_status_R) &
1049 SPU_STATUS_ISOLATED_EXIT_STAUTUS) { 1049 SPU_STATUS_ISOLATED_EXIT_STATUS) {
1050 POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & 1050 POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
1051 SPU_STATUS_RUNNING); 1051 SPU_STATUS_RUNNING);
1052 } 1052 }
1053 if ((in_be32(&prob->spu_status_R) & 1053 if ((in_be32(&prob->spu_status_R) &
1054 SPU_STATUS_ISOLATED_LOAD_STAUTUS) 1054 SPU_STATUS_ISOLATED_LOAD_STATUS)
1055 || (in_be32(&prob->spu_status_R) & 1055 || (in_be32(&prob->spu_status_R) &
1056 SPU_STATUS_ISOLATED_STATE)) { 1056 SPU_STATUS_ISOLATED_STATE)) {
1057 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP); 1057 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
@@ -1085,7 +1085,7 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
1085 */ 1085 */
1086 if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) { 1086 if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
1087 if (in_be32(&prob->spu_status_R) & 1087 if (in_be32(&prob->spu_status_R) &
1088 SPU_STATUS_ISOLATED_EXIT_STAUTUS) { 1088 SPU_STATUS_ISOLATED_EXIT_STATUS) {
1089 spu_mfc_sr1_set(spu, 1089 spu_mfc_sr1_set(spu,
1090 MFC_STATE1_MASTER_RUN_CONTROL_MASK); 1090 MFC_STATE1_MASTER_RUN_CONTROL_MASK);
1091 eieio(); 1091 eieio();
@@ -1095,7 +1095,7 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
1095 SPU_STATUS_RUNNING); 1095 SPU_STATUS_RUNNING);
1096 } 1096 }
1097 if ((in_be32(&prob->spu_status_R) & 1097 if ((in_be32(&prob->spu_status_R) &
1098 SPU_STATUS_ISOLATED_LOAD_STAUTUS) 1098 SPU_STATUS_ISOLATED_LOAD_STATUS)
1099 || (in_be32(&prob->spu_status_R) & 1099 || (in_be32(&prob->spu_status_R) &
1100 SPU_STATUS_ISOLATED_STATE)) { 1100 SPU_STATUS_ISOLATED_STATE)) {
1101 spu_mfc_sr1_set(spu, 1101 spu_mfc_sr1_set(spu,
@@ -1916,6 +1916,51 @@ static void save_lscsa(struct spu_state *prev, struct spu *spu)
1916 wait_spu_stopped(prev, spu); /* Step 57. */ 1916 wait_spu_stopped(prev, spu); /* Step 57. */
1917} 1917}
1918 1918
1919static void force_spu_isolate_exit(struct spu *spu)
1920{
1921 struct spu_problem __iomem *prob = spu->problem;
1922 struct spu_priv2 __iomem *priv2 = spu->priv2;
1923
1924 /* Stop SPE execution and wait for completion. */
1925 out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
1926 iobarrier_rw();
1927 POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING);
1928
1929 /* Restart SPE master runcntl. */
1930 spu_mfc_sr1_set(spu, MFC_STATE1_MASTER_RUN_CONTROL_MASK);
1931 iobarrier_w();
1932
1933 /* Initiate isolate exit request and wait for completion. */
1934 out_be64(&priv2->spu_privcntl_RW, 4LL);
1935 iobarrier_w();
1936 out_be32(&prob->spu_runcntl_RW, 2);
1937 iobarrier_rw();
1938 POLL_WHILE_FALSE((in_be32(&prob->spu_status_R)
1939 & SPU_STATUS_STOPPED_BY_STOP));
1940
1941 /* Reset load request to normal. */
1942 out_be64(&priv2->spu_privcntl_RW, SPU_PRIVCNT_LOAD_REQUEST_NORMAL);
1943 iobarrier_w();
1944}
1945
1946/**
1947 * stop_spu_isolate
1948 * Check SPU run-control state and force isolated
1949 * exit function as necessary.
1950 */
1951static void stop_spu_isolate(struct spu *spu)
1952{
1953 struct spu_problem __iomem *prob = spu->problem;
1954
1955 if (in_be32(&prob->spu_status_R) & SPU_STATUS_ISOLATED_STATE) {
1956 /* The SPU is in isolated state; the only way
1957 * to get it out is to perform an isolated
1958 * exit (clean) operation.
1959 */
1960 force_spu_isolate_exit(spu);
1961 }
1962}
1963
1919static void harvest(struct spu_state *prev, struct spu *spu) 1964static void harvest(struct spu_state *prev, struct spu *spu)
1920{ 1965{
1921 /* 1966 /*
@@ -1928,6 +1973,7 @@ static void harvest(struct spu_state *prev, struct spu *spu)
1928 inhibit_user_access(prev, spu); /* Step 3. */ 1973 inhibit_user_access(prev, spu); /* Step 3. */
1929 terminate_spu_app(prev, spu); /* Step 4. */ 1974 terminate_spu_app(prev, spu); /* Step 4. */
1930 set_switch_pending(prev, spu); /* Step 5. */ 1975 set_switch_pending(prev, spu); /* Step 5. */
1976 stop_spu_isolate(spu); /* NEW. */
1931 remove_other_spu_access(prev, spu); /* Step 6. */ 1977 remove_other_spu_access(prev, spu); /* Step 6. */
1932 suspend_mfc(prev, spu); /* Step 7. */ 1978 suspend_mfc(prev, spu); /* Step 7. */
1933 wait_suspend_mfc_complete(prev, spu); /* Step 8. */ 1979 wait_suspend_mfc_complete(prev, spu); /* Step 8. */
@@ -2096,11 +2142,11 @@ int spu_save(struct spu_state *prev, struct spu *spu)
2096 acquire_spu_lock(spu); /* Step 1. */ 2142 acquire_spu_lock(spu); /* Step 1. */
2097 rc = __do_spu_save(prev, spu); /* Steps 2-53. */ 2143 rc = __do_spu_save(prev, spu); /* Steps 2-53. */
2098 release_spu_lock(spu); 2144 release_spu_lock(spu);
2099 if (rc) { 2145 if (rc != 0 && rc != 2 && rc != 6) {
2100 panic("%s failed on SPU[%d], rc=%d.\n", 2146 panic("%s failed on SPU[%d], rc=%d.\n",
2101 __func__, spu->number, rc); 2147 __func__, spu->number, rc);
2102 } 2148 }
2103 return rc; 2149 return 0;
2104} 2150}
2105EXPORT_SYMBOL_GPL(spu_save); 2151EXPORT_SYMBOL_GPL(spu_save);
2106 2152
@@ -2165,9 +2211,6 @@ static void init_priv1(struct spu_state *csa)
2165 MFC_STATE1_PROBLEM_STATE_MASK | 2211 MFC_STATE1_PROBLEM_STATE_MASK |
2166 MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK; 2212 MFC_STATE1_RELOCATE_MASK | MFC_STATE1_BUS_TLBIE_MASK;
2167 2213
2168 /* Set storage description. */
2169 csa->priv1.mfc_sdr_RW = mfspr(SPRN_SDR1);
2170
2171 /* Enable OS-specific set of interrupts. */ 2214 /* Enable OS-specific set of interrupts. */
2172 csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR | 2215 csa->priv1.int_mask_class0_RW = CLASS0_ENABLE_DMA_ALIGNMENT_INTR |
2173 CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR | 2216 CLASS0_ENABLE_INVALID_DMA_COMMAND_INTR |
diff --git a/arch/powerpc/platforms/efika/Makefile b/arch/powerpc/platforms/efika/Makefile
new file mode 100644
index 000000000000..17b2a781fbae
--- /dev/null
+++ b/arch/powerpc/platforms/efika/Makefile
@@ -0,0 +1 @@
obj-y += setup.o mpc52xx.o pci.o
diff --git a/arch/powerpc/platforms/efika/efika.h b/arch/powerpc/platforms/efika/efika.h
new file mode 100644
index 000000000000..2f060fd097d7
--- /dev/null
+++ b/arch/powerpc/platforms/efika/efika.h
@@ -0,0 +1,19 @@
1/*
2 * Efika 5K2 platform setup - Header file
3 *
4 * Copyright (C) 2006 bplan GmbH
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 *
10 */
11
12#ifndef __ARCH_POWERPC_EFIKA__
13#define __ARCH_POWERPC_EFIKA__
14
15#define EFIKA_PLATFORM_NAME "Efika"
16
17extern void __init efika_pcisetup(void);
18
19#endif
diff --git a/arch/powerpc/platforms/efika/pci.c b/arch/powerpc/platforms/efika/pci.c
new file mode 100644
index 000000000000..62e05b2a9227
--- /dev/null
+++ b/arch/powerpc/platforms/efika/pci.c
@@ -0,0 +1,119 @@
1
2#include <linux/kernel.h>
3#include <linux/pci.h>
4#include <linux/string.h>
5#include <linux/init.h>
6
7#include <asm/io.h>
8#include <asm/irq.h>
9#include <asm/prom.h>
10#include <asm/machdep.h>
11#include <asm/sections.h>
12#include <asm/pci-bridge.h>
13#include <asm/rtas.h>
14
15#include "efika.h"
16
17#ifdef CONFIG_PCI
18/*
19 * Access functions for PCI config space using RTAS calls.
20 */
21static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
22 int len, u32 * val)
23{
24 struct pci_controller *hose = bus->sysdata;
25 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
26 | (((bus->number - hose->first_busno) & 0xff) << 16)
27 | (hose->index << 24);
28 int ret = -1;
29 int rval;
30
31 rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
32 *val = ret;
33 return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
34}
35
36static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
37 int offset, int len, u32 val)
38{
39 struct pci_controller *hose = bus->sysdata;
40 unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
41 | (((bus->number - hose->first_busno) & 0xff) << 16)
42 | (hose->index << 24);
43 int rval;
44
45 rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
46 addr, len, val);
47 return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
48}
49
50static struct pci_ops rtas_pci_ops = {
51 rtas_read_config,
52 rtas_write_config
53};
54
55void __init efika_pcisetup(void)
56{
57 const int *bus_range;
58 int len;
59 struct pci_controller *hose;
60 struct device_node *root;
61 struct device_node *pcictrl;
62
63 root = of_find_node_by_path("/");
64 if (root == NULL) {
65 printk(KERN_WARNING EFIKA_PLATFORM_NAME
66 ": Unable to find the root node\n");
67 return;
68 }
69
70 for (pcictrl = NULL;;) {
71 pcictrl = of_get_next_child(root, pcictrl);
72 if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0))
73 break;
74 }
75
76 of_node_put(root);
77
78 if (pcictrl == NULL) {
79 printk(KERN_WARNING EFIKA_PLATFORM_NAME
80 ": Unable to find the PCI bridge node\n");
81 return;
82 }
83
84 bus_range = get_property(pcictrl, "bus-range", &len);
85 if (bus_range == NULL || len < 2 * sizeof(int)) {
86 printk(KERN_WARNING EFIKA_PLATFORM_NAME
87 ": Can't get bus-range for %s\n", pcictrl->full_name);
88 return;
89 }
90
91 if (bus_range[1] == bus_range[0])
92 printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d",
93 bus_range[0]);
94 else
95 printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d",
96 bus_range[0], bus_range[1]);
97 printk(" controlled by %s\n", pcictrl->full_name);
98 printk("\n");
99
100 hose = pcibios_alloc_controller();
101 if (!hose) {
102 printk(KERN_WARNING EFIKA_PLATFORM_NAME
103 ": Can't allocate PCI controller structure for %s\n",
104 pcictrl->full_name);
105 return;
106 }
107
108 hose->arch_data = of_node_get(pcictrl);
109 hose->first_busno = bus_range[0];
110 hose->last_busno = bus_range[1];
111 hose->ops = &rtas_pci_ops;
112
113 pci_process_bridge_OF_ranges(hose, pcictrl, 0);
114}
115
116#else
117void __init efika_pcisetup(void)
118{}
119#endif
diff --git a/arch/powerpc/platforms/efika/setup.c b/arch/powerpc/platforms/efika/setup.c
new file mode 100644
index 000000000000..3bc1b5fe0cea
--- /dev/null
+++ b/arch/powerpc/platforms/efika/setup.c
@@ -0,0 +1,149 @@
1/*
2 *
3 * Efika 5K2 platform setup
4 * Some code really inspired from the lite5200b platform.
5 *
6 * Copyright (C) 2006 bplan GmbH
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 *
12 */
13
14#include <linux/errno.h>
15#include <linux/kernel.h>
16#include <linux/slab.h>
17#include <linux/reboot.h>
18#include <linux/init.h>
19#include <linux/utsrelease.h>
20#include <linux/seq_file.h>
21#include <linux/root_dev.h>
22#include <linux/initrd.h>
23#include <linux/timer.h>
24#include <linux/pci.h>
25
26#include <asm/pgtable.h>
27#include <asm/prom.h>
28#include <asm/time.h>
29#include <asm/machdep.h>
30#include <asm/rtas.h>
31#include <asm/of_device.h>
32#include <asm/mpc52xx.h>
33
34#include "efika.h"
35
36static void efika_show_cpuinfo(struct seq_file *m)
37{
38 struct device_node *root;
39 const char *revision = NULL;
40 const char *codegendescription = NULL;
41 const char *codegenvendor = NULL;
42
43 root = of_find_node_by_path("/");
44 if (root) {
45 revision = get_property(root, "revision", NULL);
46 codegendescription =
47 get_property(root, "CODEGEN,description", NULL);
48 codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
49
50 of_node_put(root);
51 }
52
53 if (codegendescription)
54 seq_printf(m, "machine\t\t: %s\n", codegendescription);
55 else
56 seq_printf(m, "machine\t\t: Efika\n");
57
58 if (revision)
59 seq_printf(m, "revision\t: %s\n", revision);
60
61 if (codegenvendor)
62 seq_printf(m, "vendor\t\t: %s\n", codegenvendor);
63
64 of_node_put(root);
65}
66
67static void __init efika_setup_arch(void)
68{
69 rtas_initialize();
70
71#ifdef CONFIG_BLK_DEV_INITRD
72 initrd_below_start_ok = 1;
73
74 if (initrd_start)
75 ROOT_DEV = Root_RAM0;
76 else
77#endif
78 ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */
79
80 efika_pcisetup();
81
82 if (ppc_md.progress)
83 ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0);
84}
85
86static void __init efika_init(void)
87{
88 struct device_node *np;
89 struct device_node *cnp = NULL;
90 const u32 *base;
91
92 /* Find every child of the SOC node and add it to of_platform */
93 np = of_find_node_by_name(NULL, "builtin");
94 if (np) {
95 char name[BUS_ID_SIZE];
96 while ((cnp = of_get_next_child(np, cnp))) {
97 strcpy(name, cnp->name);
98
99 base = get_property(cnp, "reg", NULL);
100 if (base == NULL)
101 continue;
102
103 snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base);
104 of_platform_device_create(cnp, name, NULL);
105
106 printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name);
107 }
108 }
109
110 if (ppc_md.progress)
111 ppc_md.progress(" Have fun with your Efika! ", 0x7777);
112}
113
114static int __init efika_probe(void)
115{
116 char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
117 "model", NULL);
118
119 if (model == NULL)
120 return 0;
121 if (strcmp(model, "EFIKA5K2"))
122 return 0;
123
124 ISA_DMA_THRESHOLD = ~0L;
125 DMA_MODE_READ = 0x44;
126 DMA_MODE_WRITE = 0x48;
127
128 return 1;
129}
130
131define_machine(efika)
132{
133 .name = EFIKA_PLATFORM_NAME,
134 .probe = efika_probe,
135 .setup_arch = efika_setup_arch,
136 .init = efika_init,
137 .show_cpuinfo = efika_show_cpuinfo,
138 .init_IRQ = mpc52xx_init_irq,
139 .get_irq = mpc52xx_get_irq,
140 .restart = rtas_restart,
141 .power_off = rtas_power_off,
142 .halt = rtas_halt,
143 .set_rtc_time = rtas_set_rtc_time,
144 .get_rtc_time = rtas_get_rtc_time,
145 .progress = rtas_progress,
146 .get_boot_time = rtas_get_boot_time,
147 .calibrate_decr = generic_calibrate_decr,
148 .phys_mem_access_prot = pci_phys_mem_access_prot,
149};
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index e305deee7f44..9e8a334a518a 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -41,6 +41,7 @@
41#include "call_pci.h" 41#include "call_pci.h"
42#include "pci.h" 42#include "pci.h"
43#include "it_exp_vpd_panel.h" 43#include "it_exp_vpd_panel.h"
44#include "naca.h"
44 45
45#ifdef DEBUG 46#ifdef DEBUG
46#define DBG(fmt...) udbg_printf(fmt) 47#define DBG(fmt...) udbg_printf(fmt)
@@ -205,13 +206,11 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
205 dt_prop(dt, name, &data, sizeof(u32)); 206 dt_prop(dt, name, &data, sizeof(u32));
206} 207}
207 208
208#ifdef notyet
209static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name, 209static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
210 u64 data) 210 u64 data)
211{ 211{
212 dt_prop(dt, name, &data, sizeof(u64)); 212 dt_prop(dt, name, &data, sizeof(u64));
213} 213}
214#endif
215 214
216static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, 215static void __init dt_prop_u64_list(struct iseries_flat_dt *dt,
217 const char *name, u64 *data, int n) 216 const char *name, u64 *data, int n)
@@ -306,6 +305,17 @@ static void __init dt_model(struct iseries_flat_dt *dt)
306 dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex()); 305 dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex());
307} 306}
308 307
308static void __init dt_initrd(struct iseries_flat_dt *dt)
309{
310#ifdef CONFIG_BLK_DEV_INITRD
311 if (naca.xRamDisk) {
312 dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk);
313 dt_prop_u64(dt, "linux,initrd-end",
314 (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE);
315 }
316#endif
317}
318
309static void __init dt_do_vdevice(struct iseries_flat_dt *dt, 319static void __init dt_do_vdevice(struct iseries_flat_dt *dt,
310 const char *name, u32 reg, int unit, 320 const char *name, u32 reg, int unit,
311 const char *type, const char *compat, int end) 321 const char *type, const char *compat, int end)
@@ -641,6 +651,7 @@ void * __init build_flat_dt(unsigned long phys_mem_size)
641 /* /chosen */ 651 /* /chosen */
642 dt_start_node(iseries_dt, "chosen"); 652 dt_start_node(iseries_dt, "chosen");
643 dt_prop_str(iseries_dt, "bootargs", cmd_line); 653 dt_prop_str(iseries_dt, "bootargs", cmd_line);
654 dt_initrd(iseries_dt);
644 dt_end_node(iseries_dt); 655 dt_end_node(iseries_dt);
645 656
646 dt_cpus(iseries_dt); 657 dt_cpus(iseries_dt);
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c
index a2200842f4e5..2430848b98e7 100644
--- a/arch/powerpc/platforms/iseries/ksyms.c
+++ b/arch/powerpc/platforms/iseries/ksyms.c
@@ -19,9 +19,3 @@ EXPORT_SYMBOL(HvCall4);
19EXPORT_SYMBOL(HvCall5); 19EXPORT_SYMBOL(HvCall5);
20EXPORT_SYMBOL(HvCall6); 20EXPORT_SYMBOL(HvCall6);
21EXPORT_SYMBOL(HvCall7); 21EXPORT_SYMBOL(HvCall7);
22
23#ifdef CONFIG_SMP
24EXPORT_SYMBOL(local_get_flags);
25EXPORT_SYMBOL(local_irq_disable);
26EXPORT_SYMBOL(local_irq_restore);
27#endif
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
index 7641fc7e550a..2c6ff0fdac98 100644
--- a/arch/powerpc/platforms/iseries/misc.S
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -19,39 +19,8 @@
19 19
20 .text 20 .text
21 21
22/* unsigned long local_save_flags(void) */ 22/* Handle pending interrupts in interrupt context */
23_GLOBAL(local_get_flags) 23_GLOBAL(iseries_handle_interrupts)
24 lbz r3,PACAPROCENABLED(r13)
25 blr
26
27/* unsigned long local_irq_disable(void) */
28_GLOBAL(local_irq_disable)
29 lbz r3,PACAPROCENABLED(r13)
30 li r4,0
31 stb r4,PACAPROCENABLED(r13)
32 blr /* Done */
33
34/* void local_irq_restore(unsigned long flags) */
35_GLOBAL(local_irq_restore)
36 lbz r5,PACAPROCENABLED(r13)
37 /* Check if things are setup the way we want _already_. */
38 cmpw 0,r3,r5
39 beqlr
40 /* are we enabling interrupts? */
41 cmpdi 0,r3,0
42 stb r3,PACAPROCENABLED(r13)
43 beqlr
44 /* Check pending interrupts */
45 /* A decrementer, IPI or PMC interrupt may have occurred
46 * while we were in the hypervisor (which enables) */
47 ld r4,PACALPPACAPTR(r13)
48 ld r4,LPPACAANYINT(r4)
49 cmpdi r4,0
50 beqlr
51
52 /*
53 * Handle pending interrupts in interrupt context
54 */
55 li r0,0x5555 24 li r0,0x5555
56 sc 25 sc
57 blr 26 blr
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 6f73469fd3b0..cd8965ec9ddb 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -21,7 +21,6 @@
21#include <linux/smp.h> 21#include <linux/smp.h>
22#include <linux/param.h> 22#include <linux/param.h>
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/initrd.h>
25#include <linux/seq_file.h> 24#include <linux/seq_file.h>
26#include <linux/kdev_t.h> 25#include <linux/kdev_t.h>
27#include <linux/major.h> 26#include <linux/major.h>
@@ -80,8 +79,6 @@ extern void iSeries_pci_final_fixup(void);
80static void iSeries_pci_final_fixup(void) { } 79static void iSeries_pci_final_fixup(void) { }
81#endif 80#endif
82 81
83extern int rd_size; /* Defined in drivers/block/rd.c */
84
85extern unsigned long iSeries_recal_tb; 82extern unsigned long iSeries_recal_tb;
86extern unsigned long iSeries_recal_titan; 83extern unsigned long iSeries_recal_titan;
87 84
@@ -295,24 +292,6 @@ static void __init iSeries_init_early(void)
295{ 292{
296 DBG(" -> iSeries_init_early()\n"); 293 DBG(" -> iSeries_init_early()\n");
297 294
298#if defined(CONFIG_BLK_DEV_INITRD)
299 /*
300 * If the init RAM disk has been configured and there is
301 * a non-zero starting address for it, set it up
302 */
303 if (naca.xRamDisk) {
304 initrd_start = (unsigned long)__va(naca.xRamDisk);
305 initrd_end = initrd_start + naca.xRamDiskSize * HW_PAGE_SIZE;
306 initrd_below_start_ok = 1; // ramdisk in kernel space
307 ROOT_DEV = Root_RAM0;
308 if (((rd_size * 1024) / HW_PAGE_SIZE) < naca.xRamDiskSize)
309 rd_size = (naca.xRamDiskSize * HW_PAGE_SIZE) / 1024;
310 } else
311#endif /* CONFIG_BLK_DEV_INITRD */
312 {
313 /* ROOT_DEV = MKDEV(VIODASD_MAJOR, 1); */
314 }
315
316 iSeries_recal_tb = get_tb(); 295 iSeries_recal_tb = get_tb();
317 iSeries_recal_titan = HvCallXm_loadTod(); 296 iSeries_recal_titan = HvCallXm_loadTod();
318 297
@@ -331,17 +310,6 @@ static void __init iSeries_init_early(void)
331 310
332 mf_init(); 311 mf_init();
333 312
334 /* If we were passed an initrd, set the ROOT_DEV properly if the values
335 * look sensible. If not, clear initrd reference.
336 */
337#ifdef CONFIG_BLK_DEV_INITRD
338 if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
339 initrd_end > initrd_start)
340 ROOT_DEV = Root_RAM0;
341 else
342 initrd_start = initrd_end = 0;
343#endif /* CONFIG_BLK_DEV_INITRD */
344
345 DBG(" <- iSeries_init_early()\n"); 313 DBG(" <- iSeries_init_early()\n");
346} 314}
347 315
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index e49621be6640..c29a6a064d22 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -486,10 +486,6 @@ static long heathrow_sound_enable(struct device_node *node, long param,
486 486
487static u32 save_fcr[6]; 487static u32 save_fcr[6];
488static u32 save_mbcr; 488static u32 save_mbcr;
489static u32 save_gpio_levels[2];
490static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
491static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
492static u32 save_unin_clock_ctl;
493static struct dbdma_regs save_dbdma[13]; 489static struct dbdma_regs save_dbdma[13];
494static struct dbdma_regs save_alt_dbdma[13]; 490static struct dbdma_regs save_alt_dbdma[13];
495 491
@@ -1548,6 +1544,10 @@ void g5_phy_disable_cpu1(void)
1548 1544
1549 1545
1550#ifdef CONFIG_PM 1546#ifdef CONFIG_PM
1547static u32 save_gpio_levels[2];
1548static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
1549static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
1550static u32 save_unin_clock_ctl;
1551 1551
1552static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode) 1552static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)
1553{ 1553{
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 824a618396ab..cb1c342061e2 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -361,7 +361,7 @@ char *bootdevice;
361void *boot_host; 361void *boot_host;
362int boot_target; 362int boot_target;
363int boot_part; 363int boot_part;
364extern dev_t boot_dev; 364static dev_t boot_dev;
365 365
366#ifdef CONFIG_SCSI 366#ifdef CONFIG_SCSI
367void __init note_scsi_host(struct device_node *node, void *host) 367void __init note_scsi_host(struct device_node *node, void *host)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 1820a0b0a8c6..721436db3ef0 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -282,7 +282,7 @@ void vpa_init(int cpu)
282 } 282 }
283} 283}
284 284
285long pSeries_lpar_hpte_insert(unsigned long hpte_group, 285static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
286 unsigned long va, unsigned long pa, 286 unsigned long va, unsigned long pa,
287 unsigned long rflags, unsigned long vflags, 287 unsigned long rflags, unsigned long vflags,
288 int psize) 288 int psize)
@@ -506,7 +506,7 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
506 * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie 506 * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
507 * lock. 507 * lock.
508 */ 508 */
509void pSeries_lpar_flush_hash_range(unsigned long number, int local) 509static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
510{ 510{
511 int i; 511 int i;
512 unsigned long flags = 0; 512 unsigned long flags = 0;