diff options
108 files changed, 5152 insertions, 1575 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 116d7d3683ed..96316c866107 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -386,6 +386,14 @@ config PPC_CHRP | |||
386 | select PPC_UDBG_16550 | 386 | select PPC_UDBG_16550 |
387 | default y | 387 | default y |
388 | 388 | ||
389 | config PPC_EFIKA | ||
390 | bool "bPlan Efika 5k2. MPC5200B based computer" | ||
391 | depends on PPC_MULTIPLATFORM && PPC32 | ||
392 | select PPC_RTAS | ||
393 | select RTAS_PROC | ||
394 | select PPC_MPC52xx | ||
395 | default y | ||
396 | |||
389 | config PPC_PMAC | 397 | config PPC_PMAC |
390 | bool "Apple PowerMac based machines" | 398 | bool "Apple PowerMac based machines" |
391 | depends on PPC_MULTIPLATFORM | 399 | depends on PPC_MULTIPLATFORM |
@@ -594,12 +602,6 @@ config TAU_AVERAGE | |||
594 | 602 | ||
595 | If in doubt, say N here. | 603 | If in doubt, say N here. |
596 | 604 | ||
597 | config PPC_TODC | ||
598 | depends on EMBEDDED6xx | ||
599 | bool "Generic Time-of-day Clock (TODC) support" | ||
600 | ---help--- | ||
601 | This adds support for many TODC/RTC chips. | ||
602 | |||
603 | endmenu | 605 | endmenu |
604 | 606 | ||
605 | source arch/powerpc/platforms/embedded6xx/Kconfig | 607 | source arch/powerpc/platforms/embedded6xx/Kconfig |
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index 45c9ad23526e..590e72f06d5e 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore | |||
@@ -1,20 +1,27 @@ | |||
1 | addnote | 1 | addnote |
2 | empty.c | ||
3 | hack-coff | ||
2 | infblock.c | 4 | infblock.c |
3 | infblock.h | 5 | infblock.h |
4 | infcodes.c | 6 | infcodes.c |
5 | infcodes.h | 7 | infcodes.h |
6 | inffast.c | 8 | inffast.c |
7 | inffast.h | 9 | inffast.h |
10 | inffixed.h | ||
8 | inflate.c | 11 | inflate.c |
12 | inflate.h | ||
9 | inftrees.c | 13 | inftrees.c |
10 | inftrees.h | 14 | inftrees.h |
11 | infutil.c | 15 | infutil.c |
12 | infutil.h | 16 | infutil.h |
13 | kernel-vmlinux.strip.c | 17 | kernel-vmlinux.strip.c |
14 | kernel-vmlinux.strip.gz | 18 | kernel-vmlinux.strip.gz |
19 | mktree | ||
15 | uImage | 20 | uImage |
16 | zImage | 21 | zImage |
17 | zImage.vmode | 22 | zImage.vmode |
23 | zImage.coff.lds | ||
24 | zImage.lds | ||
18 | zconf.h | 25 | zconf.h |
19 | zlib.h | 26 | zlib.h |
20 | zutil.h | 27 | zutil.h |
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 4b2be611f77f..4a6f0f054b72 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile | |||
@@ -40,7 +40,8 @@ zliblinuxheader := zlib.h zconf.h zutil.h | |||
40 | $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \ | 40 | $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \ |
41 | $(addprefix $(obj)/,$(zlibheader)) | 41 | $(addprefix $(obj)/,$(zlibheader)) |
42 | 42 | ||
43 | src-wlib := string.S stdio.c main.c div64.S $(zlib) | 43 | src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \ |
44 | ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib) | ||
44 | src-plat := of.c | 45 | src-plat := of.c |
45 | src-boot := crt0.S $(src-wlib) $(src-plat) empty.c | 46 | src-boot := crt0.S $(src-wlib) $(src-plat) empty.c |
46 | 47 | ||
@@ -74,7 +75,7 @@ $(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S | |||
74 | @cp $< $@ | 75 | @cp $< $@ |
75 | 76 | ||
76 | clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \ | 77 | clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \ |
77 | $(obj)/empty.c | 78 | empty.c zImage zImage.coff.lds zImage.lds zImage.sandpoint |
78 | 79 | ||
79 | quiet_cmd_bootcc = BOOTCC $@ | 80 | quiet_cmd_bootcc = BOOTCC $@ |
80 | cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< | 81 | cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $< |
@@ -93,13 +94,13 @@ $(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S | |||
93 | $(obj)/wrapper.a: $(obj-wlib) | 94 | $(obj)/wrapper.a: $(obj-wlib) |
94 | $(call cmd,bootar) | 95 | $(call cmd,bootar) |
95 | 96 | ||
96 | hostprogs-y := addnote addRamDisk hack-coff | 97 | hostprogs-y := addnote addRamDisk hack-coff mktree |
97 | 98 | ||
98 | extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ | 99 | extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ |
99 | $(obj)/zImage.lds $(obj)/zImage.coff.lds | 100 | $(obj)/zImage.lds $(obj)/zImage.coff.lds |
100 | 101 | ||
101 | wrapper :=$(srctree)/$(src)/wrapper | 102 | wrapper :=$(srctree)/$(src)/wrapper |
102 | wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff) | 103 | wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) |
103 | 104 | ||
104 | ############# | 105 | ############# |
105 | # Bits for building various flavours of zImage | 106 | # Bits for building various flavours of zImage |
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c new file mode 100644 index 000000000000..c76c194715b2 --- /dev/null +++ b/arch/powerpc/boot/flatdevtree.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License as published by | ||
4 | * the Free Software Foundation; either version 2 of the License, or | ||
5 | * (at your option) any later version. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
15 | * | ||
16 | * Copyright Pantelis Antoniou 2006 | ||
17 | * Copyright (C) IBM Corporation 2006 | ||
18 | * | ||
19 | * Authors: Pantelis Antoniou <pantelis@embeddedalley.com> | ||
20 | * Hollis Blanchard <hollisb@us.ibm.com> | ||
21 | * Mark A. Greer <mgreer@mvista.com> | ||
22 | * Paul Mackerras <paulus@samba.org> | ||
23 | */ | ||
24 | |||
25 | #include <string.h> | ||
26 | #include <stddef.h> | ||
27 | #include "flatdevtree.h" | ||
28 | #include "flatdevtree_env.h" | ||
29 | |||
30 | #define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1)) | ||
31 | |||
32 | /* Routines for keeping node ptrs returned by ft_find_device current */ | ||
33 | /* First entry not used b/c it would return 0 and be taken as NULL/error */ | ||
34 | static void *ft_node_add(struct ft_cxt *cxt, char *node) | ||
35 | { | ||
36 | unsigned int i; | ||
37 | |||
38 | for (i = 1; i < cxt->nodes_used; i++) /* already there? */ | ||
39 | if (cxt->node_tbl[i] == node) | ||
40 | return (void *)i; | ||
41 | |||
42 | if (cxt->nodes_used < cxt->node_max) { | ||
43 | cxt->node_tbl[cxt->nodes_used] = node; | ||
44 | return (void *)cxt->nodes_used++; | ||
45 | } | ||
46 | |||
47 | return NULL; | ||
48 | } | ||
49 | |||
50 | static char *ft_node_ph2node(struct ft_cxt *cxt, const void *phandle) | ||
51 | { | ||
52 | unsigned int i = (unsigned int)phandle; | ||
53 | |||
54 | if (i < cxt->nodes_used) | ||
55 | return cxt->node_tbl[i]; | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | static void ft_node_update_before(struct ft_cxt *cxt, char *addr, int shift) | ||
60 | { | ||
61 | unsigned int i; | ||
62 | |||
63 | if (shift == 0) | ||
64 | return; | ||
65 | |||
66 | for (i = 1; i < cxt->nodes_used; i++) | ||
67 | if (cxt->node_tbl[i] < addr) | ||
68 | cxt->node_tbl[i] += shift; | ||
69 | } | ||
70 | |||
71 | static void ft_node_update_after(struct ft_cxt *cxt, char *addr, int shift) | ||
72 | { | ||
73 | unsigned int i; | ||
74 | |||
75 | if (shift == 0) | ||
76 | return; | ||
77 | |||
78 | for (i = 1; i < cxt->nodes_used; i++) | ||
79 | if (cxt->node_tbl[i] >= addr) | ||
80 | cxt->node_tbl[i] += shift; | ||
81 | } | ||
82 | |||
83 | /* Struct used to return info from ft_next() */ | ||
84 | struct ft_atom { | ||
85 | u32 tag; | ||
86 | const char *name; | ||
87 | void *data; | ||
88 | u32 size; | ||
89 | }; | ||
90 | |||
91 | /* Set ptrs to current one's info; return addr of next one */ | ||
92 | static char *ft_next(struct ft_cxt *cxt, char *p, struct ft_atom *ret) | ||
93 | { | ||
94 | u32 sz; | ||
95 | |||
96 | if (p >= cxt->rgn[FT_STRUCT].start + cxt->rgn[FT_STRUCT].size) | ||
97 | return NULL; | ||
98 | |||
99 | ret->tag = be32_to_cpu(*(u32 *) p); | ||
100 | p += 4; | ||
101 | |||
102 | switch (ret->tag) { /* Tag */ | ||
103 | case OF_DT_BEGIN_NODE: | ||
104 | ret->name = p; | ||
105 | ret->data = (void *)(p - 4); /* start of node */ | ||
106 | p += _ALIGN(strlen(p) + 1, 4); | ||
107 | break; | ||
108 | case OF_DT_PROP: | ||
109 | ret->size = sz = be32_to_cpu(*(u32 *) p); | ||
110 | ret->name = cxt->str_anchor + be32_to_cpu(*(u32 *) (p + 4)); | ||
111 | ret->data = (void *)(p + 8); | ||
112 | p += 8 + _ALIGN(sz, 4); | ||
113 | break; | ||
114 | case OF_DT_END_NODE: | ||
115 | case OF_DT_NOP: | ||
116 | break; | ||
117 | case OF_DT_END: | ||
118 | default: | ||
119 | p = NULL; | ||
120 | break; | ||
121 | } | ||
122 | |||
123 | return p; | ||
124 | } | ||
125 | |||
126 | #define HDR_SIZE _ALIGN(sizeof(struct boot_param_header), 8) | ||
127 | #define EXPAND_INCR 1024 /* alloc this much extra when expanding */ | ||
128 | |||
129 | /* See if the regions are in the standard order and non-overlapping */ | ||
130 | static int ft_ordered(struct ft_cxt *cxt) | ||
131 | { | ||
132 | char *p = (char *)cxt->bph + HDR_SIZE; | ||
133 | enum ft_rgn_id r; | ||
134 | |||
135 | for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) { | ||
136 | if (p > cxt->rgn[r].start) | ||
137 | return 0; | ||
138 | p = cxt->rgn[r].start + cxt->rgn[r].size; | ||
139 | } | ||
140 | return p <= (char *)cxt->bph + cxt->max_size; | ||
141 | } | ||
142 | |||
143 | /* Copy the tree to a newly-allocated region and put things in order */ | ||
144 | static int ft_reorder(struct ft_cxt *cxt, int nextra) | ||
145 | { | ||
146 | unsigned long tot; | ||
147 | enum ft_rgn_id r; | ||
148 | char *p, *pend; | ||
149 | int stroff; | ||
150 | |||
151 | tot = HDR_SIZE + EXPAND_INCR; | ||
152 | for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) | ||
153 | tot += cxt->rgn[r].size; | ||
154 | if (nextra > 0) | ||
155 | tot += nextra; | ||
156 | tot = _ALIGN(tot, 8); | ||
157 | |||
158 | if (!cxt->realloc) | ||
159 | return 0; | ||
160 | p = cxt->realloc(NULL, tot); | ||
161 | if (!p) | ||
162 | return 0; | ||
163 | |||
164 | memcpy(p, cxt->bph, sizeof(struct boot_param_header)); | ||
165 | /* offsets get fixed up later */ | ||
166 | |||
167 | cxt->bph = (struct boot_param_header *)p; | ||
168 | cxt->max_size = tot; | ||
169 | pend = p + tot; | ||
170 | p += HDR_SIZE; | ||
171 | |||
172 | memcpy(p, cxt->rgn[FT_RSVMAP].start, cxt->rgn[FT_RSVMAP].size); | ||
173 | cxt->rgn[FT_RSVMAP].start = p; | ||
174 | p += cxt->rgn[FT_RSVMAP].size; | ||
175 | |||
176 | memcpy(p, cxt->rgn[FT_STRUCT].start, cxt->rgn[FT_STRUCT].size); | ||
177 | ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, | ||
178 | p - cxt->rgn[FT_STRUCT].start); | ||
179 | cxt->p += p - cxt->rgn[FT_STRUCT].start; | ||
180 | cxt->rgn[FT_STRUCT].start = p; | ||
181 | |||
182 | p = pend - cxt->rgn[FT_STRINGS].size; | ||
183 | memcpy(p, cxt->rgn[FT_STRINGS].start, cxt->rgn[FT_STRINGS].size); | ||
184 | stroff = cxt->str_anchor - cxt->rgn[FT_STRINGS].start; | ||
185 | cxt->rgn[FT_STRINGS].start = p; | ||
186 | cxt->str_anchor = p + stroff; | ||
187 | |||
188 | cxt->isordered = 1; | ||
189 | return 1; | ||
190 | } | ||
191 | |||
192 | static inline char *prev_end(struct ft_cxt *cxt, enum ft_rgn_id r) | ||
193 | { | ||
194 | if (r > FT_RSVMAP) | ||
195 | return cxt->rgn[r - 1].start + cxt->rgn[r - 1].size; | ||
196 | return (char *)cxt->bph + HDR_SIZE; | ||
197 | } | ||
198 | |||
199 | static inline char *next_start(struct ft_cxt *cxt, enum ft_rgn_id r) | ||
200 | { | ||
201 | if (r < FT_STRINGS) | ||
202 | return cxt->rgn[r + 1].start; | ||
203 | return (char *)cxt->bph + cxt->max_size; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * See if we can expand region rgn by nextra bytes by using up | ||
208 | * free space after or before the region. | ||
209 | */ | ||
210 | static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, | ||
211 | int nextra) | ||
212 | { | ||
213 | char *p = *pp; | ||
214 | char *rgn_start, *rgn_end; | ||
215 | |||
216 | rgn_start = cxt->rgn[rgn].start; | ||
217 | rgn_end = rgn_start + cxt->rgn[rgn].size; | ||
218 | if (nextra <= 0 || rgn_end + nextra <= next_start(cxt, rgn)) { | ||
219 | /* move following stuff */ | ||
220 | if (p < rgn_end) { | ||
221 | if (nextra < 0) | ||
222 | memmove(p, p - nextra, rgn_end - p + nextra); | ||
223 | else | ||
224 | memmove(p + nextra, p, rgn_end - p); | ||
225 | if (rgn == FT_STRUCT) | ||
226 | ft_node_update_after(cxt, p, nextra); | ||
227 | } | ||
228 | cxt->rgn[rgn].size += nextra; | ||
229 | if (rgn == FT_STRINGS) | ||
230 | /* assumes strings only added at beginning */ | ||
231 | cxt->str_anchor += nextra; | ||
232 | return 1; | ||
233 | } | ||
234 | if (prev_end(cxt, rgn) <= rgn_start - nextra) { | ||
235 | /* move preceding stuff */ | ||
236 | if (p > rgn_start) { | ||
237 | memmove(rgn_start - nextra, rgn_start, p - rgn_start); | ||
238 | if (rgn == FT_STRUCT) | ||
239 | ft_node_update_before(cxt, p, -nextra); | ||
240 | } | ||
241 | *p -= nextra; | ||
242 | cxt->rgn[rgn].start -= nextra; | ||
243 | cxt->rgn[rgn].size += nextra; | ||
244 | return 1; | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn, | ||
250 | int nextra) | ||
251 | { | ||
252 | unsigned long size, ssize, tot; | ||
253 | char *str, *next; | ||
254 | enum ft_rgn_id r; | ||
255 | |||
256 | if (!cxt->isordered && !ft_reorder(cxt, nextra)) | ||
257 | return 0; | ||
258 | if (ft_shuffle(cxt, pp, rgn, nextra)) | ||
259 | return 1; | ||
260 | |||
261 | /* See if there is space after the strings section */ | ||
262 | ssize = cxt->rgn[FT_STRINGS].size; | ||
263 | if (cxt->rgn[FT_STRINGS].start + ssize | ||
264 | < (char *)cxt->bph + cxt->max_size) { | ||
265 | /* move strings up as far as possible */ | ||
266 | str = (char *)cxt->bph + cxt->max_size - ssize; | ||
267 | cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start; | ||
268 | memmove(str, cxt->rgn[FT_STRINGS].start, ssize); | ||
269 | cxt->rgn[FT_STRINGS].start = str; | ||
270 | /* enough space now? */ | ||
271 | if (rgn >= FT_STRUCT && ft_shuffle(cxt, pp, rgn, nextra)) | ||
272 | return 1; | ||
273 | } | ||
274 | |||
275 | /* how much total free space is there following this region? */ | ||
276 | tot = 0; | ||
277 | for (r = rgn; r < FT_STRINGS; ++r) { | ||
278 | char *r_end = cxt->rgn[r].start + cxt->rgn[r].size; | ||
279 | tot += next_start(cxt, rgn) - r_end; | ||
280 | } | ||
281 | |||
282 | /* cast is to shut gcc up; we know nextra >= 0 */ | ||
283 | if (tot < (unsigned int)nextra) { | ||
284 | /* have to reallocate */ | ||
285 | char *newp, *new_start; | ||
286 | int shift; | ||
287 | |||
288 | if (!cxt->realloc) | ||
289 | return 0; | ||
290 | size = _ALIGN(cxt->max_size + (nextra - tot) + EXPAND_INCR, 8); | ||
291 | newp = cxt->realloc(cxt->bph, size); | ||
292 | if (!newp) | ||
293 | return 0; | ||
294 | cxt->max_size = size; | ||
295 | shift = newp - (char *)cxt->bph; | ||
296 | |||
297 | if (shift) { /* realloc can return same addr */ | ||
298 | cxt->bph = (struct boot_param_header *)newp; | ||
299 | ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, | ||
300 | shift); | ||
301 | for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) { | ||
302 | new_start = cxt->rgn[r].start + shift; | ||
303 | cxt->rgn[r].start = new_start; | ||
304 | } | ||
305 | *pp += shift; | ||
306 | cxt->str_anchor += shift; | ||
307 | } | ||
308 | |||
309 | /* move strings up to the end */ | ||
310 | str = newp + size - ssize; | ||
311 | cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start; | ||
312 | memmove(str, cxt->rgn[FT_STRINGS].start, ssize); | ||
313 | cxt->rgn[FT_STRINGS].start = str; | ||
314 | |||
315 | if (ft_shuffle(cxt, pp, rgn, nextra)) | ||
316 | return 1; | ||
317 | } | ||
318 | |||
319 | /* must be FT_RSVMAP and we need to move FT_STRUCT up */ | ||
320 | if (rgn == FT_RSVMAP) { | ||
321 | next = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size | ||
322 | + nextra; | ||
323 | ssize = cxt->rgn[FT_STRUCT].size; | ||
324 | if (next + ssize >= cxt->rgn[FT_STRINGS].start) | ||
325 | return 0; /* "can't happen" */ | ||
326 | memmove(next, cxt->rgn[FT_STRUCT].start, ssize); | ||
327 | ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, nextra); | ||
328 | cxt->rgn[FT_STRUCT].start = next; | ||
329 | |||
330 | if (ft_shuffle(cxt, pp, rgn, nextra)) | ||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | return 0; /* "can't happen" */ | ||
335 | } | ||
336 | |||
337 | static void ft_put_word(struct ft_cxt *cxt, u32 v) | ||
338 | { | ||
339 | *(u32 *) cxt->p = cpu_to_be32(v); | ||
340 | cxt->p += 4; | ||
341 | } | ||
342 | |||
343 | static void ft_put_bin(struct ft_cxt *cxt, const void *data, unsigned int sz) | ||
344 | { | ||
345 | unsigned long sza = _ALIGN(sz, 4); | ||
346 | |||
347 | /* zero out the alignment gap if necessary */ | ||
348 | if (sz < sza) | ||
349 | *(u32 *) (cxt->p + sza - 4) = 0; | ||
350 | |||
351 | /* copy in the data */ | ||
352 | memcpy(cxt->p, data, sz); | ||
353 | |||
354 | cxt->p += sza; | ||
355 | } | ||
356 | |||
357 | int ft_begin_node(struct ft_cxt *cxt, const char *name) | ||
358 | { | ||
359 | unsigned long nlen = strlen(name) + 1; | ||
360 | unsigned long len = 8 + _ALIGN(nlen, 4); | ||
361 | |||
362 | if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len)) | ||
363 | return -1; | ||
364 | ft_put_word(cxt, OF_DT_BEGIN_NODE); | ||
365 | ft_put_bin(cxt, name, strlen(name) + 1); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | void ft_end_node(struct ft_cxt *cxt) | ||
370 | { | ||
371 | ft_put_word(cxt, OF_DT_END_NODE); | ||
372 | } | ||
373 | |||
374 | void ft_nop(struct ft_cxt *cxt) | ||
375 | { | ||
376 | if (ft_make_space(cxt, &cxt->p, FT_STRUCT, 4)) | ||
377 | ft_put_word(cxt, OF_DT_NOP); | ||
378 | } | ||
379 | |||
380 | #define NO_STRING 0x7fffffff | ||
381 | |||
382 | static int lookup_string(struct ft_cxt *cxt, const char *name) | ||
383 | { | ||
384 | char *p, *end; | ||
385 | |||
386 | p = cxt->rgn[FT_STRINGS].start; | ||
387 | end = p + cxt->rgn[FT_STRINGS].size; | ||
388 | while (p < end) { | ||
389 | if (strcmp(p, (char *)name) == 0) | ||
390 | return p - cxt->str_anchor; | ||
391 | p += strlen(p) + 1; | ||
392 | } | ||
393 | |||
394 | return NO_STRING; | ||
395 | } | ||
396 | |||
397 | /* lookup string and insert if not found */ | ||
398 | static int map_string(struct ft_cxt *cxt, const char *name) | ||
399 | { | ||
400 | int off; | ||
401 | char *p; | ||
402 | |||
403 | off = lookup_string(cxt, name); | ||
404 | if (off != NO_STRING) | ||
405 | return off; | ||
406 | p = cxt->rgn[FT_STRINGS].start; | ||
407 | if (!ft_make_space(cxt, &p, FT_STRINGS, strlen(name) + 1)) | ||
408 | return NO_STRING; | ||
409 | strcpy(p, name); | ||
410 | return p - cxt->str_anchor; | ||
411 | } | ||
412 | |||
413 | int ft_prop(struct ft_cxt *cxt, const char *name, const void *data, | ||
414 | unsigned int sz) | ||
415 | { | ||
416 | int off, len; | ||
417 | |||
418 | off = lookup_string(cxt, name); | ||
419 | if (off == NO_STRING) | ||
420 | return -1; | ||
421 | |||
422 | len = 12 + _ALIGN(sz, 4); | ||
423 | if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len)) | ||
424 | return -1; | ||
425 | |||
426 | ft_put_word(cxt, OF_DT_PROP); | ||
427 | ft_put_word(cxt, sz); | ||
428 | ft_put_word(cxt, off); | ||
429 | ft_put_bin(cxt, data, sz); | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) | ||
434 | { | ||
435 | return ft_prop(cxt, name, str, strlen(str) + 1); | ||
436 | } | ||
437 | |||
438 | int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val) | ||
439 | { | ||
440 | u32 v = cpu_to_be32((u32) val); | ||
441 | |||
442 | return ft_prop(cxt, name, &v, 4); | ||
443 | } | ||
444 | |||
445 | /* Calculate the size of the reserved map */ | ||
446 | static unsigned long rsvmap_size(struct ft_cxt *cxt) | ||
447 | { | ||
448 | struct ft_reserve *res; | ||
449 | |||
450 | res = (struct ft_reserve *)cxt->rgn[FT_RSVMAP].start; | ||
451 | while (res->start || res->len) | ||
452 | ++res; | ||
453 | return (char *)(res + 1) - cxt->rgn[FT_RSVMAP].start; | ||
454 | } | ||
455 | |||
456 | /* Calculate the size of the struct region by stepping through it */ | ||
457 | static unsigned long struct_size(struct ft_cxt *cxt) | ||
458 | { | ||
459 | char *p = cxt->rgn[FT_STRUCT].start; | ||
460 | char *next; | ||
461 | struct ft_atom atom; | ||
462 | |||
463 | /* make check in ft_next happy */ | ||
464 | if (cxt->rgn[FT_STRUCT].size == 0) | ||
465 | cxt->rgn[FT_STRUCT].size = 0xfffffffful - (unsigned long)p; | ||
466 | |||
467 | while ((next = ft_next(cxt, p, &atom)) != NULL) | ||
468 | p = next; | ||
469 | return p + 4 - cxt->rgn[FT_STRUCT].start; | ||
470 | } | ||
471 | |||
472 | /* add `adj' on to all string offset values in the struct area */ | ||
473 | static void adjust_string_offsets(struct ft_cxt *cxt, int adj) | ||
474 | { | ||
475 | char *p = cxt->rgn[FT_STRUCT].start; | ||
476 | char *next; | ||
477 | struct ft_atom atom; | ||
478 | int off; | ||
479 | |||
480 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | ||
481 | if (atom.tag == OF_DT_PROP) { | ||
482 | off = be32_to_cpu(*(u32 *) (p + 8)); | ||
483 | *(u32 *) (p + 8) = cpu_to_be32(off + adj); | ||
484 | } | ||
485 | p = next; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /* start construction of the flat OF tree from scratch */ | ||
490 | void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size, | ||
491 | void *(*realloc_fn) (void *, unsigned long)) | ||
492 | { | ||
493 | struct boot_param_header *bph = blob; | ||
494 | char *p; | ||
495 | struct ft_reserve *pres; | ||
496 | |||
497 | /* clear the cxt */ | ||
498 | memset(cxt, 0, sizeof(*cxt)); | ||
499 | |||
500 | cxt->bph = bph; | ||
501 | cxt->max_size = max_size; | ||
502 | cxt->realloc = realloc_fn; | ||
503 | cxt->isordered = 1; | ||
504 | |||
505 | /* zero everything in the header area */ | ||
506 | memset(bph, 0, sizeof(*bph)); | ||
507 | |||
508 | bph->magic = cpu_to_be32(OF_DT_HEADER); | ||
509 | bph->version = cpu_to_be32(0x10); | ||
510 | bph->last_comp_version = cpu_to_be32(0x10); | ||
511 | |||
512 | /* start pointers */ | ||
513 | cxt->rgn[FT_RSVMAP].start = p = blob + HDR_SIZE; | ||
514 | cxt->rgn[FT_RSVMAP].size = sizeof(struct ft_reserve); | ||
515 | pres = (struct ft_reserve *)p; | ||
516 | cxt->rgn[FT_STRUCT].start = p += sizeof(struct ft_reserve); | ||
517 | cxt->rgn[FT_STRUCT].size = 4; | ||
518 | cxt->rgn[FT_STRINGS].start = blob + max_size; | ||
519 | cxt->rgn[FT_STRINGS].size = 0; | ||
520 | |||
521 | /* init rsvmap and struct */ | ||
522 | pres->start = 0; | ||
523 | pres->len = 0; | ||
524 | *(u32 *) p = cpu_to_be32(OF_DT_END); | ||
525 | |||
526 | cxt->str_anchor = blob; | ||
527 | } | ||
528 | |||
529 | /* open up an existing blob to be examined or modified */ | ||
530 | int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size, | ||
531 | unsigned int max_find_device, | ||
532 | void *(*realloc_fn) (void *, unsigned long)) | ||
533 | { | ||
534 | struct boot_param_header *bph = blob; | ||
535 | |||
536 | /* can't cope with version < 16 */ | ||
537 | if (be32_to_cpu(bph->version) < 16) | ||
538 | return -1; | ||
539 | |||
540 | /* clear the cxt */ | ||
541 | memset(cxt, 0, sizeof(*cxt)); | ||
542 | |||
543 | /* alloc node_tbl to track node ptrs returned by ft_find_device */ | ||
544 | ++max_find_device; | ||
545 | cxt->node_tbl = realloc_fn(NULL, max_find_device * sizeof(char *)); | ||
546 | if (!cxt->node_tbl) | ||
547 | return -1; | ||
548 | memset(cxt->node_tbl, 0, max_find_device * sizeof(char *)); | ||
549 | cxt->node_max = max_find_device; | ||
550 | cxt->nodes_used = 1; /* don't use idx 0 b/c looks like NULL */ | ||
551 | |||
552 | cxt->bph = bph; | ||
553 | cxt->max_size = max_size; | ||
554 | cxt->realloc = realloc_fn; | ||
555 | |||
556 | cxt->rgn[FT_RSVMAP].start = blob + be32_to_cpu(bph->off_mem_rsvmap); | ||
557 | cxt->rgn[FT_RSVMAP].size = rsvmap_size(cxt); | ||
558 | cxt->rgn[FT_STRUCT].start = blob + be32_to_cpu(bph->off_dt_struct); | ||
559 | cxt->rgn[FT_STRUCT].size = struct_size(cxt); | ||
560 | cxt->rgn[FT_STRINGS].start = blob + be32_to_cpu(bph->off_dt_strings); | ||
561 | cxt->rgn[FT_STRINGS].size = be32_to_cpu(bph->dt_strings_size); | ||
562 | /* Leave as '0' to force first ft_make_space call to do a ft_reorder | ||
563 | * and move dt to an area allocated by realloc. | ||
564 | cxt->isordered = ft_ordered(cxt); | ||
565 | */ | ||
566 | |||
567 | cxt->p = cxt->rgn[FT_STRUCT].start; | ||
568 | cxt->str_anchor = cxt->rgn[FT_STRINGS].start; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /* add a reserver physical area to the rsvmap */ | ||
574 | int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size) | ||
575 | { | ||
576 | char *p; | ||
577 | struct ft_reserve *pres; | ||
578 | |||
579 | p = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size | ||
580 | - sizeof(struct ft_reserve); | ||
581 | if (!ft_make_space(cxt, &p, FT_RSVMAP, sizeof(struct ft_reserve))) | ||
582 | return -1; | ||
583 | |||
584 | pres = (struct ft_reserve *)p; | ||
585 | pres->start = cpu_to_be64(physaddr); | ||
586 | pres->len = cpu_to_be64(size); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | void ft_begin_tree(struct ft_cxt *cxt) | ||
592 | { | ||
593 | cxt->p = cxt->rgn[FT_STRUCT].start; | ||
594 | } | ||
595 | |||
596 | void ft_end_tree(struct ft_cxt *cxt) | ||
597 | { | ||
598 | struct boot_param_header *bph = cxt->bph; | ||
599 | char *p, *oldstr, *str, *endp; | ||
600 | unsigned long ssize; | ||
601 | int adj; | ||
602 | |||
603 | if (!cxt->isordered) | ||
604 | return; /* we haven't touched anything */ | ||
605 | |||
606 | /* adjust string offsets */ | ||
607 | oldstr = cxt->rgn[FT_STRINGS].start; | ||
608 | adj = cxt->str_anchor - oldstr; | ||
609 | if (adj) | ||
610 | adjust_string_offsets(cxt, adj); | ||
611 | |||
612 | /* make strings end on 8-byte boundary */ | ||
613 | ssize = cxt->rgn[FT_STRINGS].size; | ||
614 | endp = (char *)_ALIGN((unsigned long)cxt->rgn[FT_STRUCT].start | ||
615 | + cxt->rgn[FT_STRUCT].size + ssize, 8); | ||
616 | str = endp - ssize; | ||
617 | |||
618 | /* move strings down to end of structs */ | ||
619 | memmove(str, oldstr, ssize); | ||
620 | cxt->str_anchor = str; | ||
621 | cxt->rgn[FT_STRINGS].start = str; | ||
622 | |||
623 | /* fill in header fields */ | ||
624 | p = (char *)bph; | ||
625 | bph->totalsize = cpu_to_be32(endp - p); | ||
626 | bph->off_mem_rsvmap = cpu_to_be32(cxt->rgn[FT_RSVMAP].start - p); | ||
627 | bph->off_dt_struct = cpu_to_be32(cxt->rgn[FT_STRUCT].start - p); | ||
628 | bph->off_dt_strings = cpu_to_be32(cxt->rgn[FT_STRINGS].start - p); | ||
629 | bph->dt_strings_size = cpu_to_be32(ssize); | ||
630 | } | ||
631 | |||
632 | void *ft_find_device(struct ft_cxt *cxt, const char *srch_path) | ||
633 | { | ||
634 | char *node; | ||
635 | |||
636 | /* require absolute path */ | ||
637 | if (srch_path[0] != '/') | ||
638 | return NULL; | ||
639 | node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path); | ||
640 | return ft_node_add(cxt, node); | ||
641 | } | ||
642 | |||
643 | void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path) | ||
644 | { | ||
645 | struct ft_atom atom; | ||
646 | char *p; | ||
647 | const char *cp, *q; | ||
648 | int cl; | ||
649 | int depth = -1; | ||
650 | int dmatch = 0; | ||
651 | const char *path_comp[FT_MAX_DEPTH]; | ||
652 | |||
653 | cp = srch_path; | ||
654 | cl = 0; | ||
655 | p = top; | ||
656 | |||
657 | while ((p = ft_next(cxt, p, &atom)) != NULL) { | ||
658 | switch (atom.tag) { | ||
659 | case OF_DT_BEGIN_NODE: | ||
660 | ++depth; | ||
661 | if (depth != dmatch) | ||
662 | break; | ||
663 | cxt->genealogy[depth] = atom.data; | ||
664 | cxt->genealogy[depth + 1] = NULL; | ||
665 | if (depth && !(strncmp(atom.name, cp, cl) == 0 | ||
666 | && (atom.name[cl] == '/' | ||
667 | || atom.name[cl] == '\0' | ||
668 | || atom.name[cl] == '@'))) | ||
669 | break; | ||
670 | path_comp[dmatch] = cp; | ||
671 | /* it matches so far, advance to next path component */ | ||
672 | cp += cl; | ||
673 | /* skip slashes */ | ||
674 | while (*cp == '/') | ||
675 | ++cp; | ||
676 | /* we're done if this is the end of the string */ | ||
677 | if (*cp == 0) | ||
678 | return atom.data; | ||
679 | /* look for end of this component */ | ||
680 | q = strchr(cp, '/'); | ||
681 | if (q) | ||
682 | cl = q - cp; | ||
683 | else | ||
684 | cl = strlen(cp); | ||
685 | ++dmatch; | ||
686 | break; | ||
687 | case OF_DT_END_NODE: | ||
688 | if (depth == 0) | ||
689 | return NULL; | ||
690 | if (dmatch > depth) { | ||
691 | --dmatch; | ||
692 | cl = cp - path_comp[dmatch] - 1; | ||
693 | cp = path_comp[dmatch]; | ||
694 | while (cl > 0 && cp[cl - 1] == '/') | ||
695 | --cl; | ||
696 | } | ||
697 | --depth; | ||
698 | break; | ||
699 | } | ||
700 | } | ||
701 | return NULL; | ||
702 | } | ||
703 | |||
704 | void *ft_get_parent(struct ft_cxt *cxt, const void *phandle) | ||
705 | { | ||
706 | void *node; | ||
707 | int d; | ||
708 | struct ft_atom atom; | ||
709 | char *p; | ||
710 | |||
711 | node = ft_node_ph2node(cxt, phandle); | ||
712 | if (node == NULL) | ||
713 | return NULL; | ||
714 | |||
715 | for (d = 0; cxt->genealogy[d] != NULL; ++d) | ||
716 | if (cxt->genealogy[d] == node) | ||
717 | return cxt->genealogy[d > 0 ? d - 1 : 0]; | ||
718 | |||
719 | /* have to do it the hard way... */ | ||
720 | p = cxt->rgn[FT_STRUCT].start; | ||
721 | d = 0; | ||
722 | while ((p = ft_next(cxt, p, &atom)) != NULL) { | ||
723 | switch (atom.tag) { | ||
724 | case OF_DT_BEGIN_NODE: | ||
725 | cxt->genealogy[d] = atom.data; | ||
726 | if (node == atom.data) { | ||
727 | /* found it */ | ||
728 | cxt->genealogy[d + 1] = NULL; | ||
729 | return d > 0 ? cxt->genealogy[d - 1] : node; | ||
730 | } | ||
731 | ++d; | ||
732 | break; | ||
733 | case OF_DT_END_NODE: | ||
734 | --d; | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | ||
742 | void *buf, const unsigned int buflen) | ||
743 | { | ||
744 | struct ft_atom atom; | ||
745 | void *node; | ||
746 | char *p; | ||
747 | int depth; | ||
748 | unsigned int size; | ||
749 | |||
750 | node = ft_node_ph2node(cxt, phandle); | ||
751 | if (node == NULL) | ||
752 | return -1; | ||
753 | |||
754 | depth = 0; | ||
755 | p = (char *)node; | ||
756 | |||
757 | while ((p = ft_next(cxt, p, &atom)) != NULL) { | ||
758 | switch (atom.tag) { | ||
759 | case OF_DT_BEGIN_NODE: | ||
760 | ++depth; | ||
761 | break; | ||
762 | case OF_DT_PROP: | ||
763 | if ((depth != 1) || strcmp(atom.name, propname)) | ||
764 | break; | ||
765 | size = min(atom.size, buflen); | ||
766 | memcpy(buf, atom.data, size); | ||
767 | return atom.size; | ||
768 | case OF_DT_END_NODE: | ||
769 | if (--depth <= 0) | ||
770 | return -1; | ||
771 | } | ||
772 | } | ||
773 | return -1; | ||
774 | } | ||
775 | |||
776 | int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | ||
777 | const void *buf, const unsigned int buflen) | ||
778 | { | ||
779 | struct ft_atom atom; | ||
780 | void *node; | ||
781 | char *p, *next; | ||
782 | int nextra, depth; | ||
783 | |||
784 | node = ft_node_ph2node(cxt, phandle); | ||
785 | if (node == NULL) | ||
786 | return -1; | ||
787 | |||
788 | depth = 0; | ||
789 | p = node; | ||
790 | |||
791 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | ||
792 | switch (atom.tag) { | ||
793 | case OF_DT_BEGIN_NODE: | ||
794 | ++depth; | ||
795 | break; | ||
796 | case OF_DT_END_NODE: | ||
797 | if (--depth > 0) | ||
798 | break; | ||
799 | /* haven't found the property, insert here */ | ||
800 | cxt->p = p; | ||
801 | return ft_prop(cxt, propname, buf, buflen); | ||
802 | case OF_DT_PROP: | ||
803 | if ((depth != 1) || strcmp(atom.name, propname)) | ||
804 | break; | ||
805 | /* found an existing property, overwrite it */ | ||
806 | nextra = _ALIGN(buflen, 4) - _ALIGN(atom.size, 4); | ||
807 | cxt->p = atom.data; | ||
808 | if (nextra && !ft_make_space(cxt, &cxt->p, FT_STRUCT, | ||
809 | nextra)) | ||
810 | return -1; | ||
811 | *(u32 *) (cxt->p - 8) = cpu_to_be32(buflen); | ||
812 | ft_put_bin(cxt, buf, buflen); | ||
813 | return 0; | ||
814 | } | ||
815 | p = next; | ||
816 | } | ||
817 | return -1; | ||
818 | } | ||
819 | |||
820 | int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname) | ||
821 | { | ||
822 | struct ft_atom atom; | ||
823 | void *node; | ||
824 | char *p, *next; | ||
825 | int size; | ||
826 | |||
827 | node = ft_node_ph2node(cxt, phandle); | ||
828 | if (node == NULL) | ||
829 | return -1; | ||
830 | |||
831 | p = node; | ||
832 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | ||
833 | switch (atom.tag) { | ||
834 | case OF_DT_BEGIN_NODE: | ||
835 | case OF_DT_END_NODE: | ||
836 | return -1; | ||
837 | case OF_DT_PROP: | ||
838 | if (strcmp(atom.name, propname)) | ||
839 | break; | ||
840 | /* found the property, remove it */ | ||
841 | size = 12 + -_ALIGN(atom.size, 4); | ||
842 | cxt->p = p; | ||
843 | if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, -size)) | ||
844 | return -1; | ||
845 | return 0; | ||
846 | } | ||
847 | p = next; | ||
848 | } | ||
849 | return -1; | ||
850 | } | ||
851 | |||
852 | void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path) | ||
853 | { | ||
854 | struct ft_atom atom; | ||
855 | char *p, *next; | ||
856 | int depth = 0; | ||
857 | |||
858 | p = cxt->rgn[FT_STRUCT].start; | ||
859 | while ((next = ft_next(cxt, p, &atom)) != NULL) { | ||
860 | switch (atom.tag) { | ||
861 | case OF_DT_BEGIN_NODE: | ||
862 | ++depth; | ||
863 | if (depth == 1 && strcmp(atom.name, path) == 0) | ||
864 | /* duplicate node path, return error */ | ||
865 | return NULL; | ||
866 | break; | ||
867 | case OF_DT_END_NODE: | ||
868 | --depth; | ||
869 | if (depth > 0) | ||
870 | break; | ||
871 | /* end of node, insert here */ | ||
872 | cxt->p = p; | ||
873 | ft_begin_node(cxt, path); | ||
874 | ft_end_node(cxt); | ||
875 | return p; | ||
876 | } | ||
877 | p = next; | ||
878 | } | ||
879 | return NULL; | ||
880 | } | ||
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h index 761c8dc84008..b9cd9f61f351 100644 --- a/arch/powerpc/boot/flatdevtree.h +++ b/arch/powerpc/boot/flatdevtree.h | |||
@@ -17,7 +17,7 @@ | |||
17 | #ifndef FLATDEVTREE_H | 17 | #ifndef FLATDEVTREE_H |
18 | #define FLATDEVTREE_H | 18 | #define FLATDEVTREE_H |
19 | 19 | ||
20 | #include "types.h" | 20 | #include "flatdevtree_env.h" |
21 | 21 | ||
22 | /* Definitions used by the flattened device tree */ | 22 | /* Definitions used by the flattened device tree */ |
23 | #define OF_DT_HEADER 0xd00dfeed /* marker */ | 23 | #define OF_DT_HEADER 0xd00dfeed /* marker */ |
@@ -43,4 +43,64 @@ struct boot_param_header { | |||
43 | u32 dt_strings_size; /* size of the DT strings block */ | 43 | u32 dt_strings_size; /* size of the DT strings block */ |
44 | }; | 44 | }; |
45 | 45 | ||
46 | struct ft_reserve { | ||
47 | u64 start; | ||
48 | u64 len; | ||
49 | }; | ||
50 | |||
51 | struct ft_region { | ||
52 | char *start; | ||
53 | unsigned long size; | ||
54 | }; | ||
55 | |||
56 | enum ft_rgn_id { | ||
57 | FT_RSVMAP, | ||
58 | FT_STRUCT, | ||
59 | FT_STRINGS, | ||
60 | FT_N_REGION | ||
61 | }; | ||
62 | |||
63 | #define FT_MAX_DEPTH 50 | ||
64 | |||
65 | struct ft_cxt { | ||
66 | struct boot_param_header *bph; | ||
67 | int max_size; /* maximum size of tree */ | ||
68 | int isordered; /* everything in standard order */ | ||
69 | void *(*realloc)(void *, unsigned long); | ||
70 | char *str_anchor; | ||
71 | char *p; /* current insertion point in structs */ | ||
72 | struct ft_region rgn[FT_N_REGION]; | ||
73 | void *genealogy[FT_MAX_DEPTH+1]; | ||
74 | char **node_tbl; | ||
75 | unsigned int node_max; | ||
76 | unsigned int nodes_used; | ||
77 | }; | ||
78 | |||
79 | int ft_begin_node(struct ft_cxt *cxt, const char *name); | ||
80 | void ft_end_node(struct ft_cxt *cxt); | ||
81 | |||
82 | void ft_begin_tree(struct ft_cxt *cxt); | ||
83 | void ft_end_tree(struct ft_cxt *cxt); | ||
84 | |||
85 | void ft_nop(struct ft_cxt *cxt); | ||
86 | int ft_prop(struct ft_cxt *cxt, const char *name, | ||
87 | const void *data, unsigned int sz); | ||
88 | int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); | ||
89 | int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val); | ||
90 | void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size, | ||
91 | void *(*realloc_fn)(void *, unsigned long)); | ||
92 | int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size, | ||
93 | unsigned int max_find_device, | ||
94 | void *(*realloc_fn)(void *, unsigned long)); | ||
95 | int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); | ||
96 | |||
97 | void ft_dump_blob(const void *bphp); | ||
98 | void ft_merge_blob(struct ft_cxt *cxt, void *blob); | ||
99 | void *ft_find_device(struct ft_cxt *cxt, const char *srch_path); | ||
100 | void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path); | ||
101 | int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | ||
102 | void *buf, const unsigned int buflen); | ||
103 | int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname, | ||
104 | const void *buf, const unsigned int buflen); | ||
105 | |||
46 | #endif /* FLATDEVTREE_H */ | 106 | #endif /* FLATDEVTREE_H */ |
diff --git a/arch/powerpc/boot/flatdevtree_env.h b/arch/powerpc/boot/flatdevtree_env.h new file mode 100644 index 000000000000..83bc1c718836 --- /dev/null +++ b/arch/powerpc/boot/flatdevtree_env.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * This file adds the header file glue so that the shared files | ||
3 | * flatdevicetree.[ch] can compile and work in the powerpc bootwrapper. | ||
4 | * | ||
5 | * strncmp & strchr copied from <file:lib/strings.c> | ||
6 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
7 | * | ||
8 | * Maintained by: Mark A. Greer <mgreer@mvista.com> | ||
9 | */ | ||
10 | #ifndef _PPC_BOOT_FLATDEVTREE_ENV_H_ | ||
11 | #define _PPC_BOOT_FLATDEVTREE_ENV_H_ | ||
12 | |||
13 | #include <stdarg.h> | ||
14 | #include <stddef.h> | ||
15 | #include "types.h" | ||
16 | #include "string.h" | ||
17 | #include "stdio.h" | ||
18 | #include "ops.h" | ||
19 | |||
20 | #define be16_to_cpu(x) (x) | ||
21 | #define cpu_to_be16(x) (x) | ||
22 | #define be32_to_cpu(x) (x) | ||
23 | #define cpu_to_be32(x) (x) | ||
24 | #define be64_to_cpu(x) (x) | ||
25 | #define cpu_to_be64(x) (x) | ||
26 | |||
27 | static inline int strncmp(const char *cs, const char *ct, size_t count) | ||
28 | { | ||
29 | signed char __res = 0; | ||
30 | |||
31 | while (count) { | ||
32 | if ((__res = *cs - *ct++) != 0 || !*cs++) | ||
33 | break; | ||
34 | count--; | ||
35 | } | ||
36 | return __res; | ||
37 | } | ||
38 | |||
39 | static inline char *strchr(const char *s, int c) | ||
40 | { | ||
41 | for (; *s != (char)c; ++s) | ||
42 | if (*s == '\0') | ||
43 | return NULL; | ||
44 | return (char *)s; | ||
45 | } | ||
46 | |||
47 | #endif /* _PPC_BOOT_FLATDEVTREE_ENV_H_ */ | ||
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c new file mode 100644 index 000000000000..c7f9adbf827d --- /dev/null +++ b/arch/powerpc/boot/flatdevtree_misc.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * This file does the necessary interface mapping between the bootwrapper | ||
3 | * device tree operations and the interface provided by shared source | ||
4 | * files flatdevicetree.[ch]. | ||
5 | * | ||
6 | * Author: Mark A. Greer <mgreer@mvista.com> | ||
7 | * | ||
8 | * 2006 (c) MontaVista Software, Inc. This file is licensed under | ||
9 | * the terms of the GNU General Public License version 2. This program | ||
10 | * is licensed "as is" without any warranty of any kind, whether express | ||
11 | * or implied. | ||
12 | */ | ||
13 | #include <stddef.h> | ||
14 | #include "flatdevtree.h" | ||
15 | #include "ops.h" | ||
16 | |||
17 | static struct ft_cxt cxt; | ||
18 | |||
19 | static void *ft_finddevice(const char *name) | ||
20 | { | ||
21 | return ft_find_device(&cxt, name); | ||
22 | } | ||
23 | |||
24 | static int ft_getprop(const void *phandle, const char *propname, void *buf, | ||
25 | const int buflen) | ||
26 | { | ||
27 | return ft_get_prop(&cxt, phandle, propname, buf, buflen); | ||
28 | } | ||
29 | |||
30 | static int ft_setprop(const void *phandle, const char *propname, | ||
31 | const void *buf, const int buflen) | ||
32 | { | ||
33 | return ft_set_prop(&cxt, phandle, propname, buf, buflen); | ||
34 | } | ||
35 | |||
36 | static void ft_pack(void) | ||
37 | { | ||
38 | ft_end_tree(&cxt); | ||
39 | } | ||
40 | |||
41 | static unsigned long ft_addr(void) | ||
42 | { | ||
43 | return (unsigned long)cxt.bph; | ||
44 | } | ||
45 | |||
46 | int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device) | ||
47 | { | ||
48 | dt_ops.finddevice = ft_finddevice; | ||
49 | dt_ops.getprop = ft_getprop; | ||
50 | dt_ops.setprop = ft_setprop; | ||
51 | dt_ops.ft_pack = ft_pack; | ||
52 | dt_ops.ft_addr = ft_addr; | ||
53 | |||
54 | return ft_open(&cxt, dt_blob, max_size, max_find_device, | ||
55 | platform_ops.realloc); | ||
56 | } | ||
diff --git a/arch/powerpc/boot/io.h b/arch/powerpc/boot/io.h new file mode 100644 index 000000000000..32974ed49e02 --- /dev/null +++ b/arch/powerpc/boot/io.h | |||
@@ -0,0 +1,53 @@ | |||
1 | #ifndef _IO_H | ||
2 | #define __IO_H | ||
3 | /* | ||
4 | * Low-level I/O routines. | ||
5 | * | ||
6 | * Copied from <file:include/asm-powerpc/io.h> (which has no copyright) | ||
7 | */ | ||
8 | static inline int in_8(const volatile unsigned char *addr) | ||
9 | { | ||
10 | int ret; | ||
11 | |||
12 | __asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync" | ||
13 | : "=r" (ret) : "m" (*addr)); | ||
14 | return ret; | ||
15 | } | ||
16 | |||
17 | static inline void out_8(volatile unsigned char *addr, int val) | ||
18 | { | ||
19 | __asm__ __volatile__("stb%U0%X0 %1,%0; sync" | ||
20 | : "=m" (*addr) : "r" (val)); | ||
21 | } | ||
22 | |||
23 | static inline unsigned in_le32(const volatile unsigned *addr) | ||
24 | { | ||
25 | unsigned ret; | ||
26 | |||
27 | __asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync" | ||
28 | : "=r" (ret) : "r" (addr), "m" (*addr)); | ||
29 | return ret; | ||
30 | } | ||
31 | |||
32 | static inline unsigned in_be32(const volatile unsigned *addr) | ||
33 | { | ||
34 | unsigned ret; | ||
35 | |||
36 | __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" | ||
37 | : "=r" (ret) : "m" (*addr)); | ||
38 | return ret; | ||
39 | } | ||
40 | |||
41 | static inline void out_le32(volatile unsigned *addr, int val) | ||
42 | { | ||
43 | __asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr) | ||
44 | : "r" (val), "r" (addr)); | ||
45 | } | ||
46 | |||
47 | static inline void out_be32(volatile unsigned *addr, int val) | ||
48 | { | ||
49 | __asm__ __volatile__("stw%U0%X0 %1,%0; sync" | ||
50 | : "=m" (*addr) : "r" (val)); | ||
51 | } | ||
52 | |||
53 | #endif /* _IO_H */ | ||
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c index d719bb9333d1..418497482b6e 100644 --- a/arch/powerpc/boot/main.c +++ b/arch/powerpc/boot/main.c | |||
@@ -27,6 +27,8 @@ extern char _vmlinux_start[]; | |||
27 | extern char _vmlinux_end[]; | 27 | extern char _vmlinux_end[]; |
28 | extern char _initrd_start[]; | 28 | extern char _initrd_start[]; |
29 | extern char _initrd_end[]; | 29 | extern char _initrd_end[]; |
30 | extern char _dtb_start[]; | ||
31 | extern char _dtb_end[]; | ||
30 | 32 | ||
31 | struct addr_range { | 33 | struct addr_range { |
32 | unsigned long addr; | 34 | unsigned long addr; |
@@ -250,10 +252,6 @@ static void prep_kernel(unsigned long *a1, unsigned long *a2) | |||
250 | flush_cache((void *)vmlinux.addr, vmlinux.size); | 252 | flush_cache((void *)vmlinux.addr, vmlinux.size); |
251 | } | 253 | } |
252 | 254 | ||
253 | void __attribute__ ((weak)) ft_init(void *dt_blob) | ||
254 | { | ||
255 | } | ||
256 | |||
257 | /* A buffer that may be edited by tools operating on a zImage binary so as to | 255 | /* A buffer that may be edited by tools operating on a zImage binary so as to |
258 | * edit the command line passed to vmlinux (by setting /chosen/bootargs). | 256 | * edit the command line passed to vmlinux (by setting /chosen/bootargs). |
259 | * The buffer is put in it's own section so that tools may locate it easier. | 257 | * The buffer is put in it's own section so that tools may locate it easier. |
@@ -285,19 +283,12 @@ static void set_cmdline(char *buf) | |||
285 | setprop(devp, "bootargs", buf, strlen(buf) + 1); | 283 | setprop(devp, "bootargs", buf, strlen(buf) + 1); |
286 | } | 284 | } |
287 | 285 | ||
288 | /* Section where ft can be tacked on after zImage is built */ | ||
289 | union blobspace { | ||
290 | struct boot_param_header hdr; | ||
291 | char space[8*1024]; | ||
292 | } dt_blob __attribute__((__section__("__builtin_ft"))); | ||
293 | |||
294 | struct platform_ops platform_ops; | 286 | struct platform_ops platform_ops; |
295 | struct dt_ops dt_ops; | 287 | struct dt_ops dt_ops; |
296 | struct console_ops console_ops; | 288 | struct console_ops console_ops; |
297 | 289 | ||
298 | void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) | 290 | void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) |
299 | { | 291 | { |
300 | int have_dt = 0; | ||
301 | kernel_entry_t kentry; | 292 | kernel_entry_t kentry; |
302 | char cmdline[COMMAND_LINE_SIZE]; | 293 | char cmdline[COMMAND_LINE_SIZE]; |
303 | 294 | ||
@@ -306,15 +297,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) | |||
306 | memset(&dt_ops, 0, sizeof(dt_ops)); | 297 | memset(&dt_ops, 0, sizeof(dt_ops)); |
307 | memset(&console_ops, 0, sizeof(console_ops)); | 298 | memset(&console_ops, 0, sizeof(console_ops)); |
308 | 299 | ||
309 | /* Override the dt_ops and device tree if there was an flat dev | 300 | if (platform_init(promptr, _dtb_start, _dtb_end)) |
310 | * tree attached to the zImage. | ||
311 | */ | ||
312 | if (dt_blob.hdr.magic == OF_DT_HEADER) { | ||
313 | have_dt = 1; | ||
314 | ft_init(&dt_blob); | ||
315 | } | ||
316 | |||
317 | if (platform_init(promptr)) | ||
318 | exit(); | 301 | exit(); |
319 | if (console_ops.open && (console_ops.open() < 0)) | 302 | if (console_ops.open && (console_ops.open() < 0)) |
320 | exit(); | 303 | exit(); |
@@ -342,8 +325,10 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) | |||
342 | console_ops.close(); | 325 | console_ops.close(); |
343 | 326 | ||
344 | kentry = (kernel_entry_t) vmlinux.addr; | 327 | kentry = (kernel_entry_t) vmlinux.addr; |
345 | if (have_dt) | 328 | if (_dtb_end > _dtb_start) { |
329 | dt_ops.ft_pack(); | ||
346 | kentry(dt_ops.ft_addr(), 0, NULL); | 330 | kentry(dt_ops.ft_addr(), 0, NULL); |
331 | } | ||
347 | else | 332 | else |
348 | /* XXX initrd addr/size should be passed in properties */ | 333 | /* XXX initrd addr/size should be passed in properties */ |
349 | kentry(a1, a2, promptr); | 334 | kentry(a1, a2, promptr); |
diff --git a/arch/powerpc/boot/mktree.c b/arch/powerpc/boot/mktree.c new file mode 100644 index 000000000000..4cb892993651 --- /dev/null +++ b/arch/powerpc/boot/mktree.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * Makes a tree bootable image for IBM Evaluation boards. | ||
3 | * Basically, just take a zImage, skip the ELF header, and stuff | ||
4 | * a 32 byte header on the front. | ||
5 | * | ||
6 | * We use htonl, which is a network macro, to make sure we're doing | ||
7 | * The Right Thing on an LE machine. It's non-obvious, but it should | ||
8 | * work on anything BSD'ish. | ||
9 | */ | ||
10 | |||
11 | #include <fcntl.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <sys/stat.h> | ||
16 | #include <unistd.h> | ||
17 | #include <netinet/in.h> | ||
18 | #ifdef __sun__ | ||
19 | #include <inttypes.h> | ||
20 | #else | ||
21 | #include <stdint.h> | ||
22 | #endif | ||
23 | |||
24 | /* This gets tacked on the front of the image. There are also a few | ||
25 | * bytes allocated after the _start label used by the boot rom (see | ||
26 | * head.S for details). | ||
27 | */ | ||
28 | typedef struct boot_block { | ||
29 | uint32_t bb_magic; /* 0x0052504F */ | ||
30 | uint32_t bb_dest; /* Target address of the image */ | ||
31 | uint32_t bb_num_512blocks; /* Size, rounded-up, in 512 byte blks */ | ||
32 | uint32_t bb_debug_flag; /* Run debugger or image after load */ | ||
33 | uint32_t bb_entry_point; /* The image address to start */ | ||
34 | uint32_t bb_checksum; /* 32 bit checksum including header */ | ||
35 | uint32_t reserved[2]; | ||
36 | } boot_block_t; | ||
37 | |||
38 | #define IMGBLK 512 | ||
39 | char tmpbuf[IMGBLK]; | ||
40 | |||
41 | int main(int argc, char *argv[]) | ||
42 | { | ||
43 | int in_fd, out_fd; | ||
44 | int nblks, i; | ||
45 | uint cksum, *cp; | ||
46 | struct stat st; | ||
47 | boot_block_t bt; | ||
48 | |||
49 | if (argc < 3) { | ||
50 | fprintf(stderr, "usage: %s <zImage-file> <boot-image> [entry-point]\n",argv[0]); | ||
51 | exit(1); | ||
52 | } | ||
53 | |||
54 | if (stat(argv[1], &st) < 0) { | ||
55 | perror("stat"); | ||
56 | exit(2); | ||
57 | } | ||
58 | |||
59 | nblks = (st.st_size + IMGBLK) / IMGBLK; | ||
60 | |||
61 | bt.bb_magic = htonl(0x0052504F); | ||
62 | |||
63 | /* If we have the optional entry point parameter, use it */ | ||
64 | if (argc == 4) | ||
65 | bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0)); | ||
66 | else | ||
67 | bt.bb_dest = bt.bb_entry_point = htonl(0x500000); | ||
68 | |||
69 | /* We know these from the linker command. | ||
70 | * ...and then move it up into memory a little more so the | ||
71 | * relocation can happen. | ||
72 | */ | ||
73 | bt.bb_num_512blocks = htonl(nblks); | ||
74 | bt.bb_debug_flag = 0; | ||
75 | |||
76 | bt.bb_checksum = 0; | ||
77 | |||
78 | /* To be neat and tidy :-). | ||
79 | */ | ||
80 | bt.reserved[0] = 0; | ||
81 | bt.reserved[1] = 0; | ||
82 | |||
83 | if ((in_fd = open(argv[1], O_RDONLY)) < 0) { | ||
84 | perror("zImage open"); | ||
85 | exit(3); | ||
86 | } | ||
87 | |||
88 | if ((out_fd = open(argv[2], (O_RDWR | O_CREAT | O_TRUNC), 0666)) < 0) { | ||
89 | perror("bootfile open"); | ||
90 | exit(3); | ||
91 | } | ||
92 | |||
93 | cksum = 0; | ||
94 | cp = (void *)&bt; | ||
95 | for (i=0; i<sizeof(bt)/sizeof(uint); i++) | ||
96 | cksum += *cp++; | ||
97 | |||
98 | /* Assume zImage is an ELF file, and skip the 64K header. | ||
99 | */ | ||
100 | if (read(in_fd, tmpbuf, IMGBLK) != IMGBLK) { | ||
101 | fprintf(stderr, "%s is too small to be an ELF image\n", | ||
102 | argv[1]); | ||
103 | exit(4); | ||
104 | } | ||
105 | |||
106 | if ((*(uint *)tmpbuf) != htonl(0x7f454c46)) { | ||
107 | fprintf(stderr, "%s is not an ELF image\n", argv[1]); | ||
108 | exit(4); | ||
109 | } | ||
110 | |||
111 | if (lseek(in_fd, (64 * 1024), SEEK_SET) < 0) { | ||
112 | fprintf(stderr, "%s failed to seek in ELF image\n", argv[1]); | ||
113 | exit(4); | ||
114 | } | ||
115 | |||
116 | nblks -= (64 * 1024) / IMGBLK; | ||
117 | |||
118 | /* And away we go...... | ||
119 | */ | ||
120 | if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) { | ||
121 | perror("boot-image write"); | ||
122 | exit(5); | ||
123 | } | ||
124 | |||
125 | while (nblks-- > 0) { | ||
126 | if (read(in_fd, tmpbuf, IMGBLK) < 0) { | ||
127 | perror("zImage read"); | ||
128 | exit(5); | ||
129 | } | ||
130 | cp = (uint *)tmpbuf; | ||
131 | for (i=0; i<sizeof(tmpbuf)/sizeof(uint); i++) | ||
132 | cksum += *cp++; | ||
133 | if (write(out_fd, tmpbuf, sizeof(tmpbuf)) != sizeof(tmpbuf)) { | ||
134 | perror("boot-image write"); | ||
135 | exit(5); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* rewrite the header with the computed checksum. | ||
140 | */ | ||
141 | bt.bb_checksum = htonl(cksum); | ||
142 | if (lseek(out_fd, 0, SEEK_SET) < 0) { | ||
143 | perror("rewrite seek"); | ||
144 | exit(1); | ||
145 | } | ||
146 | if (write(out_fd, &bt, sizeof(bt)) != sizeof(bt)) { | ||
147 | perror("boot-image rewrite"); | ||
148 | exit(1); | ||
149 | } | ||
150 | |||
151 | exit(0); | ||
152 | } | ||
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c new file mode 100644 index 000000000000..1ffe72e35cdc --- /dev/null +++ b/arch/powerpc/boot/ns16550.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * 16550 serial console support. | ||
3 | * | ||
4 | * Original copied from <file:arch/ppc/boot/common/ns16550.c> | ||
5 | * (which had no copyright) | ||
6 | * Modifications: 2006 (c) MontaVista Software, Inc. | ||
7 | * | ||
8 | * Modified by: Mark A. Greer <mgreer@mvista.com> | ||
9 | */ | ||
10 | #include <stdarg.h> | ||
11 | #include <stddef.h> | ||
12 | #include "types.h" | ||
13 | #include "string.h" | ||
14 | #include "stdio.h" | ||
15 | #include "io.h" | ||
16 | #include "ops.h" | ||
17 | |||
18 | #define UART_DLL 0 /* Out: Divisor Latch Low */ | ||
19 | #define UART_DLM 1 /* Out: Divisor Latch High */ | ||
20 | #define UART_FCR 2 /* Out: FIFO Control Register */ | ||
21 | #define UART_LCR 3 /* Out: Line Control Register */ | ||
22 | #define UART_MCR 4 /* Out: Modem Control Register */ | ||
23 | #define UART_LSR 5 /* In: Line Status Register */ | ||
24 | #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ | ||
25 | #define UART_LSR_DR 0x01 /* Receiver data ready */ | ||
26 | #define UART_MSR 6 /* In: Modem Status Register */ | ||
27 | #define UART_SCR 7 /* I/O: Scratch Register */ | ||
28 | |||
29 | static unsigned char *reg_base; | ||
30 | static u32 reg_shift; | ||
31 | |||
32 | static int ns16550_open(void) | ||
33 | { | ||
34 | out_8(reg_base + (UART_FCR << reg_shift), 0x06); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static void ns16550_putc(unsigned char c) | ||
39 | { | ||
40 | while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0); | ||
41 | out_8(reg_base, c); | ||
42 | } | ||
43 | |||
44 | static unsigned char ns16550_getc(void) | ||
45 | { | ||
46 | while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0); | ||
47 | return in_8(reg_base); | ||
48 | } | ||
49 | |||
50 | static u8 ns16550_tstc(void) | ||
51 | { | ||
52 | return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0); | ||
53 | } | ||
54 | |||
55 | int ns16550_console_init(void *devp, struct serial_console_data *scdp) | ||
56 | { | ||
57 | int n; | ||
58 | |||
59 | n = getprop(devp, "virtual-reg", ®_base, sizeof(reg_base)); | ||
60 | if (n != sizeof(reg_base)) | ||
61 | return -1; | ||
62 | |||
63 | n = getprop(devp, "reg-shift", ®_shift, sizeof(reg_shift)); | ||
64 | if (n != sizeof(reg_shift)) | ||
65 | reg_shift = 0; | ||
66 | |||
67 | scdp->open = ns16550_open; | ||
68 | scdp->putc = ns16550_putc; | ||
69 | scdp->getc = ns16550_getc; | ||
70 | scdp->tstc = ns16550_tstc; | ||
71 | scdp->close = NULL; | ||
72 | |||
73 | return 0; | ||
74 | } | ||
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c index 3a71845afc6c..0182f384f3e6 100644 --- a/arch/powerpc/boot/of.c +++ b/arch/powerpc/boot/of.c | |||
@@ -256,24 +256,18 @@ static void of_console_write(char *buf, int len) | |||
256 | call_prom("write", 3, 1, of_stdout_handle, buf, len); | 256 | call_prom("write", 3, 1, of_stdout_handle, buf, len); |
257 | } | 257 | } |
258 | 258 | ||
259 | int platform_init(void *promptr) | 259 | int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end) |
260 | { | 260 | { |
261 | platform_ops.fixups = NULL; | ||
262 | platform_ops.image_hdr = of_image_hdr; | 261 | platform_ops.image_hdr = of_image_hdr; |
263 | platform_ops.malloc = of_try_claim; | 262 | platform_ops.malloc = of_try_claim; |
264 | platform_ops.free = NULL; | ||
265 | platform_ops.exit = of_exit; | 263 | platform_ops.exit = of_exit; |
266 | 264 | ||
267 | dt_ops.finddevice = of_finddevice; | 265 | dt_ops.finddevice = of_finddevice; |
268 | dt_ops.getprop = of_getprop; | 266 | dt_ops.getprop = of_getprop; |
269 | dt_ops.setprop = of_setprop; | 267 | dt_ops.setprop = of_setprop; |
270 | dt_ops.translate_addr = NULL; | ||
271 | 268 | ||
272 | console_ops.open = of_console_open; | 269 | console_ops.open = of_console_open; |
273 | console_ops.write = of_console_write; | 270 | console_ops.write = of_console_write; |
274 | console_ops.edit_cmdline = NULL; | ||
275 | console_ops.close = NULL; | ||
276 | console_ops.data = NULL; | ||
277 | 271 | ||
278 | prom = (int (*)(void *))promptr; | 272 | prom = (int (*)(void *))promptr; |
279 | return 0; | 273 | return 0; |
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h index 135eb4bb03b4..59832fb0f276 100644 --- a/arch/powerpc/boot/ops.h +++ b/arch/powerpc/boot/ops.h | |||
@@ -22,7 +22,8 @@ struct platform_ops { | |||
22 | void (*fixups)(void); | 22 | void (*fixups)(void); |
23 | void (*image_hdr)(const void *); | 23 | void (*image_hdr)(const void *); |
24 | void * (*malloc)(u32 size); | 24 | void * (*malloc)(u32 size); |
25 | void (*free)(void *ptr, u32 size); | 25 | void (*free)(void *ptr); |
26 | void * (*realloc)(void *ptr, unsigned long size); | ||
26 | void (*exit)(void); | 27 | void (*exit)(void); |
27 | }; | 28 | }; |
28 | extern struct platform_ops platform_ops; | 29 | extern struct platform_ops platform_ops; |
@@ -30,12 +31,11 @@ extern struct platform_ops platform_ops; | |||
30 | /* Device Tree operations */ | 31 | /* Device Tree operations */ |
31 | struct dt_ops { | 32 | struct dt_ops { |
32 | void * (*finddevice)(const char *name); | 33 | void * (*finddevice)(const char *name); |
33 | int (*getprop)(const void *node, const char *name, void *buf, | 34 | int (*getprop)(const void *phandle, const char *name, void *buf, |
34 | const int buflen); | 35 | const int buflen); |
35 | int (*setprop)(const void *node, const char *name, | 36 | int (*setprop)(const void *phandle, const char *name, |
36 | const void *buf, const int buflen); | 37 | const void *buf, const int buflen); |
37 | u64 (*translate_addr)(const char *path, const u32 *in_addr, | 38 | void (*ft_pack)(void); |
38 | const u32 addr_len); | ||
39 | unsigned long (*ft_addr)(void); | 39 | unsigned long (*ft_addr)(void); |
40 | }; | 40 | }; |
41 | extern struct dt_ops dt_ops; | 41 | extern struct dt_ops dt_ops; |
@@ -59,10 +59,13 @@ struct serial_console_data { | |||
59 | void (*close)(void); | 59 | void (*close)(void); |
60 | }; | 60 | }; |
61 | 61 | ||
62 | extern int platform_init(void *promptr); | 62 | int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end); |
63 | extern void simple_alloc_init(void); | 63 | int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device); |
64 | extern void ft_init(void *dt_blob); | 64 | int serial_console_init(void); |
65 | extern int serial_console_init(void); | 65 | int ns16550_console_init(void *devp, struct serial_console_data *scdp); |
66 | void *simple_alloc_init(char *base, u32 heap_size, u32 granularity, | ||
67 | u32 max_allocs); | ||
68 | |||
66 | 69 | ||
67 | static inline void *finddevice(const char *name) | 70 | static inline void *finddevice(const char *name) |
68 | { | 71 | { |
@@ -84,10 +87,10 @@ static inline void *malloc(u32 size) | |||
84 | return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL; | 87 | return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL; |
85 | } | 88 | } |
86 | 89 | ||
87 | static inline void free(void *ptr, u32 size) | 90 | static inline void free(void *ptr) |
88 | { | 91 | { |
89 | if (platform_ops.free) | 92 | if (platform_ops.free) |
90 | platform_ops.free(ptr, size); | 93 | platform_ops.free(ptr); |
91 | } | 94 | } |
92 | 95 | ||
93 | static inline void exit(void) | 96 | static inline void exit(void) |
diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c new file mode 100644 index 000000000000..e8de4cf59be7 --- /dev/null +++ b/arch/powerpc/boot/serial.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * Generic serial console support | ||
3 | * | ||
4 | * Author: Mark A. Greer <mgreer@mvista.com> | ||
5 | * | ||
6 | * Code in serial_edit_cmdline() copied from <file:arch/ppc/boot/simple/misc.c> | ||
7 | * and was written by Matt Porter <mporter@kernel.crashing.org>. | ||
8 | * | ||
9 | * 2001,2006 (c) MontaVista Software, Inc. This file is licensed under | ||
10 | * the terms of the GNU General Public License version 2. This program | ||
11 | * is licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | */ | ||
14 | #include <stdarg.h> | ||
15 | #include <stddef.h> | ||
16 | #include "types.h" | ||
17 | #include "string.h" | ||
18 | #include "stdio.h" | ||
19 | #include "io.h" | ||
20 | #include "ops.h" | ||
21 | |||
22 | extern void udelay(long delay); | ||
23 | |||
24 | static int serial_open(void) | ||
25 | { | ||
26 | struct serial_console_data *scdp = console_ops.data; | ||
27 | return scdp->open(); | ||
28 | } | ||
29 | |||
30 | static void serial_write(char *buf, int len) | ||
31 | { | ||
32 | struct serial_console_data *scdp = console_ops.data; | ||
33 | |||
34 | while (*buf != '\0') | ||
35 | scdp->putc(*buf++); | ||
36 | } | ||
37 | |||
38 | static void serial_edit_cmdline(char *buf, int len) | ||
39 | { | ||
40 | int timer = 0, count; | ||
41 | char ch, *cp; | ||
42 | struct serial_console_data *scdp = console_ops.data; | ||
43 | |||
44 | cp = buf; | ||
45 | count = strlen(buf); | ||
46 | cp = &buf[count]; | ||
47 | count++; | ||
48 | |||
49 | while (timer++ < 5*1000) { | ||
50 | if (scdp->tstc()) { | ||
51 | while (((ch = scdp->getc()) != '\n') && (ch != '\r')) { | ||
52 | /* Test for backspace/delete */ | ||
53 | if ((ch == '\b') || (ch == '\177')) { | ||
54 | if (cp != buf) { | ||
55 | cp--; | ||
56 | count--; | ||
57 | printf("\b \b"); | ||
58 | } | ||
59 | /* Test for ^x/^u (and wipe the line) */ | ||
60 | } else if ((ch == '\030') || (ch == '\025')) { | ||
61 | while (cp != buf) { | ||
62 | cp--; | ||
63 | count--; | ||
64 | printf("\b \b"); | ||
65 | } | ||
66 | } else if (count < len) { | ||
67 | *cp++ = ch; | ||
68 | count++; | ||
69 | scdp->putc(ch); | ||
70 | } | ||
71 | } | ||
72 | break; /* Exit 'timer' loop */ | ||
73 | } | ||
74 | udelay(1000); /* 1 msec */ | ||
75 | } | ||
76 | *cp = 0; | ||
77 | } | ||
78 | |||
79 | static void serial_close(void) | ||
80 | { | ||
81 | struct serial_console_data *scdp = console_ops.data; | ||
82 | |||
83 | if (scdp->close) | ||
84 | scdp->close(); | ||
85 | } | ||
86 | |||
87 | static void *serial_get_stdout_devp(void) | ||
88 | { | ||
89 | void *devp; | ||
90 | char devtype[MAX_PROP_LEN]; | ||
91 | char path[MAX_PATH_LEN]; | ||
92 | |||
93 | devp = finddevice("/chosen"); | ||
94 | if (devp == NULL) | ||
95 | goto err_out; | ||
96 | |||
97 | if (getprop(devp, "linux,stdout-path", path, MAX_PATH_LEN) > 0) { | ||
98 | devp = finddevice(path); | ||
99 | if (devp == NULL) | ||
100 | goto err_out; | ||
101 | |||
102 | if ((getprop(devp, "device_type", devtype, sizeof(devtype)) > 0) | ||
103 | && !strcmp(devtype, "serial")) | ||
104 | return devp; | ||
105 | } | ||
106 | err_out: | ||
107 | return NULL; | ||
108 | } | ||
109 | |||
110 | static struct serial_console_data serial_cd; | ||
111 | |||
112 | /* Node's "compatible" property determines which serial driver to use */ | ||
113 | int serial_console_init(void) | ||
114 | { | ||
115 | void *devp; | ||
116 | int rc = -1; | ||
117 | char compat[MAX_PROP_LEN]; | ||
118 | |||
119 | devp = serial_get_stdout_devp(); | ||
120 | if (devp == NULL) | ||
121 | goto err_out; | ||
122 | |||
123 | if (getprop(devp, "compatible", compat, sizeof(compat)) < 0) | ||
124 | goto err_out; | ||
125 | |||
126 | if (!strcmp(compat, "ns16550")) | ||
127 | rc = ns16550_console_init(devp, &serial_cd); | ||
128 | |||
129 | /* Add other serial console driver calls here */ | ||
130 | |||
131 | if (!rc) { | ||
132 | console_ops.open = serial_open; | ||
133 | console_ops.write = serial_write; | ||
134 | console_ops.edit_cmdline = serial_edit_cmdline; | ||
135 | console_ops.close = serial_close; | ||
136 | console_ops.data = &serial_cd; | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | err_out: | ||
141 | return -1; | ||
142 | } | ||
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c new file mode 100644 index 000000000000..cfe3a7505ba0 --- /dev/null +++ b/arch/powerpc/boot/simple_alloc.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Implement primitive realloc(3) functionality. | ||
3 | * | ||
4 | * Author: Mark A. Greer <mgreer@mvista.com> | ||
5 | * | ||
6 | * 2006 (c) MontaVista, Software, Inc. This file is licensed under | ||
7 | * the terms of the GNU General Public License version 2. This program | ||
8 | * is licensed "as is" without any warranty of any kind, whether express | ||
9 | * or implied. | ||
10 | */ | ||
11 | |||
12 | #include <stddef.h> | ||
13 | #include "types.h" | ||
14 | #include "page.h" | ||
15 | #include "string.h" | ||
16 | #include "ops.h" | ||
17 | |||
18 | #define ENTRY_BEEN_USED 0x01 | ||
19 | #define ENTRY_IN_USE 0x02 | ||
20 | |||
21 | static struct alloc_info { | ||
22 | u32 flags; | ||
23 | u32 base; | ||
24 | u32 size; | ||
25 | } *alloc_tbl; | ||
26 | |||
27 | static u32 tbl_entries; | ||
28 | static u32 alloc_min; | ||
29 | static u32 next_base; | ||
30 | static u32 space_left; | ||
31 | |||
32 | /* | ||
33 | * First time an entry is used, its base and size are set. | ||
34 | * An entry can be freed and re-malloc'd but its base & size don't change. | ||
35 | * Should be smart enough for needs of bootwrapper. | ||
36 | */ | ||
37 | static void *simple_malloc(u32 size) | ||
38 | { | ||
39 | u32 i; | ||
40 | struct alloc_info *p = alloc_tbl; | ||
41 | |||
42 | if (size == 0) | ||
43 | goto err_out; | ||
44 | |||
45 | size = _ALIGN_UP(size, alloc_min); | ||
46 | |||
47 | for (i=0; i<tbl_entries; i++, p++) | ||
48 | if (!(p->flags & ENTRY_BEEN_USED)) { /* never been used */ | ||
49 | if (size <= space_left) { | ||
50 | p->base = next_base; | ||
51 | p->size = size; | ||
52 | p->flags = ENTRY_BEEN_USED | ENTRY_IN_USE; | ||
53 | next_base += size; | ||
54 | space_left -= size; | ||
55 | return (void *)p->base; | ||
56 | } | ||
57 | goto err_out; /* not enough space left */ | ||
58 | } | ||
59 | /* reuse an entry keeping same base & size */ | ||
60 | else if (!(p->flags & ENTRY_IN_USE) && (size <= p->size)) { | ||
61 | p->flags |= ENTRY_IN_USE; | ||
62 | return (void *)p->base; | ||
63 | } | ||
64 | err_out: | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | static struct alloc_info *simple_find_entry(void *ptr) | ||
69 | { | ||
70 | u32 i; | ||
71 | struct alloc_info *p = alloc_tbl; | ||
72 | |||
73 | for (i=0; i<tbl_entries; i++,p++) { | ||
74 | if (!(p->flags & ENTRY_BEEN_USED)) | ||
75 | break; | ||
76 | if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr)) | ||
77 | return p; | ||
78 | } | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static void simple_free(void *ptr) | ||
83 | { | ||
84 | struct alloc_info *p = simple_find_entry(ptr); | ||
85 | |||
86 | if (p != NULL) | ||
87 | p->flags &= ~ENTRY_IN_USE; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Change size of area pointed to by 'ptr' to 'size'. | ||
92 | * If 'ptr' is NULL, then its a malloc(). If 'size' is 0, then its a free(). | ||
93 | * 'ptr' must be NULL or a pointer to a non-freed area previously returned by | ||
94 | * simple_realloc() or simple_malloc(). | ||
95 | */ | ||
96 | static void *simple_realloc(void *ptr, unsigned long size) | ||
97 | { | ||
98 | struct alloc_info *p; | ||
99 | void *new; | ||
100 | |||
101 | if (size == 0) { | ||
102 | simple_free(ptr); | ||
103 | return NULL; | ||
104 | } | ||
105 | |||
106 | if (ptr == NULL) | ||
107 | return simple_malloc(size); | ||
108 | |||
109 | p = simple_find_entry(ptr); | ||
110 | if (p == NULL) /* ptr not from simple_malloc/simple_realloc */ | ||
111 | return NULL; | ||
112 | if (size <= p->size) /* fits in current block */ | ||
113 | return ptr; | ||
114 | |||
115 | new = simple_malloc(size); | ||
116 | memcpy(new, ptr, p->size); | ||
117 | simple_free(ptr); | ||
118 | return new; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Returns addr of first byte after heap so caller can see if it took | ||
123 | * too much space. If so, change args & try again. | ||
124 | */ | ||
125 | void *simple_alloc_init(char *base, u32 heap_size, u32 granularity, | ||
126 | u32 max_allocs) | ||
127 | { | ||
128 | u32 heap_base, tbl_size; | ||
129 | |||
130 | heap_size = _ALIGN_UP(heap_size, granularity); | ||
131 | alloc_min = granularity; | ||
132 | tbl_entries = max_allocs; | ||
133 | |||
134 | tbl_size = tbl_entries * sizeof(struct alloc_info); | ||
135 | |||
136 | alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8); | ||
137 | memset(alloc_tbl, 0, tbl_size); | ||
138 | |||
139 | heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min); | ||
140 | |||
141 | next_base = heap_base; | ||
142 | space_left = heap_size; | ||
143 | |||
144 | platform_ops.malloc = simple_malloc; | ||
145 | platform_ops.free = simple_free; | ||
146 | platform_ops.realloc = simple_realloc; | ||
147 | |||
148 | return (void *)(heap_base + heap_size); | ||
149 | } | ||
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c index 6d5f6382e1ce..0a9feeb98342 100644 --- a/arch/powerpc/boot/stdio.c +++ b/arch/powerpc/boot/stdio.c | |||
@@ -320,6 +320,7 @@ printf(const char *fmt, ...) | |||
320 | va_start(args, fmt); | 320 | va_start(args, fmt); |
321 | n = vsprintf(sprint_buf, fmt, args); | 321 | n = vsprintf(sprint_buf, fmt, args); |
322 | va_end(args); | 322 | va_end(args); |
323 | console_ops.write(sprint_buf, n); | 323 | if (console_ops.write) |
324 | console_ops.write(sprint_buf, n); | ||
324 | return n; | 325 | return n; |
325 | } | 326 | } |
diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S new file mode 100644 index 000000000000..427ddfc11991 --- /dev/null +++ b/arch/powerpc/boot/util.S | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copied from <file:arch/powerpc/kernel/misc_32.S> | ||
3 | * | ||
4 | * This file contains miscellaneous low-level functions. | ||
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
6 | * | ||
7 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | ||
8 | * and Paul Mackerras. | ||
9 | * | ||
10 | * kexec bits: | ||
11 | * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> | ||
12 | * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version | ||
17 | * 2 of the License, or (at your option) any later version. | ||
18 | * | ||
19 | */ | ||
20 | #include "ppc_asm.h" | ||
21 | |||
22 | #define SPRN_PVR 0x11F /* Processor Version Register */ | ||
23 | |||
24 | .text | ||
25 | |||
26 | /* udelay (on non-601 processors) needs to know the period of the | ||
27 | * timebase in nanoseconds. This used to be hardcoded to be 60ns | ||
28 | * (period of 66MHz/4). Now a variable is used that is initialized to | ||
29 | * 60 for backward compatibility, but it can be overridden as necessary | ||
30 | * with code something like this: | ||
31 | * extern unsigned long timebase_period_ns; | ||
32 | * timebase_period_ns = 1000000000 / bd->bi_tbfreq; | ||
33 | */ | ||
34 | .data | ||
35 | .globl timebase_period_ns | ||
36 | timebase_period_ns: | ||
37 | .long 60 | ||
38 | |||
39 | .text | ||
40 | /* | ||
41 | * Delay for a number of microseconds | ||
42 | */ | ||
43 | .globl udelay | ||
44 | udelay: | ||
45 | mfspr r4,SPRN_PVR | ||
46 | srwi r4,r4,16 | ||
47 | cmpwi 0,r4,1 /* 601 ? */ | ||
48 | bne .udelay_not_601 | ||
49 | 00: li r0,86 /* Instructions / microsecond? */ | ||
50 | mtctr r0 | ||
51 | 10: addi r0,r0,0 /* NOP */ | ||
52 | bdnz 10b | ||
53 | subic. r3,r3,1 | ||
54 | bne 00b | ||
55 | blr | ||
56 | |||
57 | .udelay_not_601: | ||
58 | mulli r4,r3,1000 /* nanoseconds */ | ||
59 | /* Change r4 to be the number of ticks using: | ||
60 | * (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns | ||
61 | * timebase_period_ns defaults to 60 (16.6MHz) */ | ||
62 | mflr r5 | ||
63 | bl 0f | ||
64 | 0: mflr r6 | ||
65 | mtlr r5 | ||
66 | lis r5,0b@ha | ||
67 | addi r5,r5,0b@l | ||
68 | subf r5,r5,r6 /* In case we're relocated */ | ||
69 | addis r5,r5,timebase_period_ns@ha | ||
70 | lwz r5,timebase_period_ns@l(r5) | ||
71 | add r4,r4,r5 | ||
72 | addi r4,r4,-1 | ||
73 | divw r4,r4,r5 /* BUS ticks */ | ||
74 | 1: mftbu r5 | ||
75 | mftb r6 | ||
76 | mftbu r7 | ||
77 | cmpw 0,r5,r7 | ||
78 | bne 1b /* Get [synced] base time */ | ||
79 | addc r9,r6,r4 /* Compute end time */ | ||
80 | addze r8,r5 | ||
81 | 2: mftbu r5 | ||
82 | cmpw 0,r5,r8 | ||
83 | blt 2b | ||
84 | bgt 3f | ||
85 | mftb r6 | ||
86 | cmpw 0,r6,r9 | ||
87 | blt 2b | ||
88 | 3: blr | ||
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index b5fb1fee76f8..024e4d425c59 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper | |||
@@ -184,6 +184,9 @@ fi | |||
184 | 184 | ||
185 | if [ -n "$dtb" ]; then | 185 | if [ -n "$dtb" ]; then |
186 | addsec $tmp "$dtb" .kernel:dtb | 186 | addsec $tmp "$dtb" .kernel:dtb |
187 | if [ -n "$dts" ]; then | ||
188 | rm $dtb | ||
189 | fi | ||
187 | fi | 190 | fi |
188 | 191 | ||
189 | if [ "$platform" != "miboot" ]; then | 192 | if [ "$platform" != "miboot" ]; then |
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S index 05f32388b953..a360905e5428 100644 --- a/arch/powerpc/boot/zImage.coff.lds.S +++ b/arch/powerpc/boot/zImage.coff.lds.S | |||
@@ -21,6 +21,10 @@ SECTIONS | |||
21 | *(.got2) | 21 | *(.got2) |
22 | __got2_end = .; | 22 | __got2_end = .; |
23 | 23 | ||
24 | _dtb_start = .; | ||
25 | *(.kernel:dtb) | ||
26 | _dtb_end = .; | ||
27 | |||
24 | _vmlinux_start = .; | 28 | _vmlinux_start = .; |
25 | *(.kernel:vmlinux.strip) | 29 | *(.kernel:vmlinux.strip) |
26 | _vmlinux_end = .; | 30 | _vmlinux_end = .; |
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 0aba06d7d2ec..dbcd4e3329d0 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig | |||
@@ -139,7 +139,19 @@ CONFIG_RTAS_FLASH=y | |||
139 | CONFIG_MMIO_NVRAM=y | 139 | CONFIG_MMIO_NVRAM=y |
140 | # CONFIG_PPC_MPC106 is not set | 140 | # CONFIG_PPC_MPC106 is not set |
141 | # CONFIG_PPC_970_NAP is not set | 141 | # CONFIG_PPC_970_NAP is not set |
142 | # CONFIG_CPU_FREQ is not set | 142 | CONFIG_CPU_FREQ=y |
143 | CONFIG_CPU_FREQ_TABLE=y | ||
144 | CONFIG_CPU_FREQ_DEBUG=y | ||
145 | CONFIG_CPU_FREQ_STAT=y | ||
146 | # CONFIG_CPU_FREQ_STAT_DETAILS is not set | ||
147 | CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y | ||
148 | # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set | ||
149 | CONFIG_CPU_FREQ_GOV_PERFORMANCE=y | ||
150 | CONFIG_CPU_FREQ_GOV_POWERSAVE=y | ||
151 | CONFIG_CPU_FREQ_GOV_USERSPACE=y | ||
152 | CONFIG_CPU_FREQ_GOV_ONDEMAND=y | ||
153 | CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y | ||
154 | # CONFIG_CPU_FREQ_PMAC64 is not set | ||
143 | # CONFIG_WANT_EARLY_SERIAL is not set | 155 | # CONFIG_WANT_EARLY_SERIAL is not set |
144 | # CONFIG_MPIC is not set | 156 | # CONFIG_MPIC is not set |
145 | 157 | ||
@@ -149,6 +161,8 @@ CONFIG_MMIO_NVRAM=y | |||
149 | CONFIG_SPU_FS=m | 161 | CONFIG_SPU_FS=m |
150 | CONFIG_SPU_BASE=y | 162 | CONFIG_SPU_BASE=y |
151 | CONFIG_CBE_RAS=y | 163 | CONFIG_CBE_RAS=y |
164 | CONFIG_CBE_THERM=m | ||
165 | CONFIG_CBE_CPUFREQ=m | ||
152 | 166 | ||
153 | # | 167 | # |
154 | # Kernel options | 168 | # Kernel options |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 7af23c43fd4b..d8240ce22120 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -17,7 +17,7 @@ obj-y += vdso32/ | |||
17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ | 17 | obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ |
18 | signal_64.o ptrace32.o \ | 18 | signal_64.o ptrace32.o \ |
19 | paca.o cpu_setup_ppc970.o \ | 19 | paca.o cpu_setup_ppc970.o \ |
20 | firmware.o sysfs.o | 20 | firmware.o sysfs.o nvram_64.o |
21 | obj-$(CONFIG_PPC64) += vdso64/ | 21 | obj-$(CONFIG_PPC64) += vdso64/ |
22 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o | 22 | obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o |
23 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o | 23 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o |
@@ -32,7 +32,6 @@ obj-$(CONFIG_LPARCFG) += lparcfg.o | |||
32 | obj-$(CONFIG_IBMVIO) += vio.o | 32 | obj-$(CONFIG_IBMVIO) += vio.o |
33 | obj-$(CONFIG_IBMEBUS) += ibmebus.o | 33 | obj-$(CONFIG_IBMEBUS) += ibmebus.o |
34 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 34 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
35 | obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o | ||
36 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 35 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
37 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o | 36 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o |
38 | obj-$(CONFIG_TAU) += tau_6xx.o | 37 | obj-$(CONFIG_TAU) += tau_6xx.o |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index d06f378597bb..e96521530d21 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -118,7 +118,8 @@ int main(void) | |||
118 | DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); | 118 | DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr)); |
119 | DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); | 119 | DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1)); |
120 | DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); | 120 | DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc)); |
121 | DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled)); | 121 | DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); |
122 | DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); | ||
122 | DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); | 123 | DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache)); |
123 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); | 124 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); |
124 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); | 125 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); |
diff --git a/arch/powerpc/kernel/cpu_setup_ppc970.S b/arch/powerpc/kernel/cpu_setup_ppc970.S index 652594891d58..bf118c385752 100644 --- a/arch/powerpc/kernel/cpu_setup_ppc970.S +++ b/arch/powerpc/kernel/cpu_setup_ppc970.S | |||
@@ -83,6 +83,22 @@ _GLOBAL(__setup_cpu_ppc970) | |||
83 | rldimi r0,r11,52,8 /* set NAP and DPM */ | 83 | rldimi r0,r11,52,8 /* set NAP and DPM */ |
84 | li r11,0 | 84 | li r11,0 |
85 | rldimi r0,r11,32,31 /* clear EN_ATTN */ | 85 | rldimi r0,r11,32,31 /* clear EN_ATTN */ |
86 | b load_hids /* Jump to shared code */ | ||
87 | |||
88 | |||
89 | _GLOBAL(__setup_cpu_ppc970MP) | ||
90 | /* Do nothing if not running in HV mode */ | ||
91 | mfmsr r0 | ||
92 | rldicl. r0,r0,4,63 | ||
93 | beqlr | ||
94 | |||
95 | mfspr r0,SPRN_HID0 | ||
96 | li r11,0x15 /* clear DOZE and SLEEP */ | ||
97 | rldimi r0,r11,52,6 /* set DEEPNAP, NAP and DPM */ | ||
98 | li r11,0 | ||
99 | rldimi r0,r11,32,31 /* clear EN_ATTN */ | ||
100 | |||
101 | load_hids: | ||
86 | mtspr SPRN_HID0,r0 | 102 | mtspr SPRN_HID0,r0 |
87 | mfspr r0,SPRN_HID0 | 103 | mfspr r0,SPRN_HID0 |
88 | mfspr r0,SPRN_HID0 | 104 | mfspr r0,SPRN_HID0 |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index bfd499ee3753..1e4ed0731d15 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -42,6 +42,7 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec); | |||
42 | #endif /* CONFIG_PPC32 */ | 42 | #endif /* CONFIG_PPC32 */ |
43 | #ifdef CONFIG_PPC64 | 43 | #ifdef CONFIG_PPC64 |
44 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); | 44 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); |
45 | extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); | ||
45 | extern void __restore_cpu_ppc970(void); | 46 | extern void __restore_cpu_ppc970(void); |
46 | #endif /* CONFIG_PPC64 */ | 47 | #endif /* CONFIG_PPC64 */ |
47 | 48 | ||
@@ -222,7 +223,7 @@ static struct cpu_spec cpu_specs[] = { | |||
222 | .icache_bsize = 128, | 223 | .icache_bsize = 128, |
223 | .dcache_bsize = 128, | 224 | .dcache_bsize = 128, |
224 | .num_pmcs = 8, | 225 | .num_pmcs = 8, |
225 | .cpu_setup = __setup_cpu_ppc970, | 226 | .cpu_setup = __setup_cpu_ppc970MP, |
226 | .cpu_restore = __restore_cpu_ppc970, | 227 | .cpu_restore = __restore_cpu_ppc970, |
227 | .oprofile_cpu_type = "ppc64/970", | 228 | .oprofile_cpu_type = "ppc64/970", |
228 | .oprofile_type = PPC_OPROFILE_POWER4, | 229 | .oprofile_type = PPC_OPROFILE_POWER4, |
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 1af41f7616dc..89b03c8da9d2 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -111,7 +111,7 @@ void crash_ipi_callback(struct pt_regs *regs) | |||
111 | if (!cpu_online(cpu)) | 111 | if (!cpu_online(cpu)) |
112 | return; | 112 | return; |
113 | 113 | ||
114 | local_irq_disable(); | 114 | hard_irq_disable(); |
115 | if (!cpu_isset(cpu, cpus_in_crash)) | 115 | if (!cpu_isset(cpu, cpus_in_crash)) |
116 | crash_save_this_cpu(regs, cpu); | 116 | crash_save_this_cpu(regs, cpu); |
117 | cpu_set(cpu, cpus_in_crash); | 117 | cpu_set(cpu, cpus_in_crash); |
@@ -289,7 +289,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
289 | * an SMP system. | 289 | * an SMP system. |
290 | * The kernel is broken so disable interrupts. | 290 | * The kernel is broken so disable interrupts. |
291 | */ | 291 | */ |
292 | local_irq_disable(); | 292 | hard_irq_disable(); |
293 | 293 | ||
294 | for_each_irq(irq) { | 294 | for_each_irq(irq) { |
295 | struct irq_desc *desc = irq_desc + irq; | 295 | struct irq_desc *desc = irq_desc + irq; |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 748e74fcf541..ec754c92ba94 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -87,6 +87,10 @@ system_call_common: | |||
87 | addi r9,r1,STACK_FRAME_OVERHEAD | 87 | addi r9,r1,STACK_FRAME_OVERHEAD |
88 | ld r11,exception_marker@toc(r2) | 88 | ld r11,exception_marker@toc(r2) |
89 | std r11,-16(r9) /* "regshere" marker */ | 89 | std r11,-16(r9) /* "regshere" marker */ |
90 | li r10,1 | ||
91 | stb r10,PACASOFTIRQEN(r13) | ||
92 | stb r10,PACAHARDIRQEN(r13) | ||
93 | std r10,SOFTE(r1) | ||
90 | #ifdef CONFIG_PPC_ISERIES | 94 | #ifdef CONFIG_PPC_ISERIES |
91 | BEGIN_FW_FTR_SECTION | 95 | BEGIN_FW_FTR_SECTION |
92 | /* Hack for handling interrupts when soft-enabling on iSeries */ | 96 | /* Hack for handling interrupts when soft-enabling on iSeries */ |
@@ -94,8 +98,6 @@ BEGIN_FW_FTR_SECTION | |||
94 | andi. r10,r12,MSR_PR /* from kernel */ | 98 | andi. r10,r12,MSR_PR /* from kernel */ |
95 | crand 4*cr0+eq,4*cr1+eq,4*cr0+eq | 99 | crand 4*cr0+eq,4*cr1+eq,4*cr0+eq |
96 | beq hardware_interrupt_entry | 100 | beq hardware_interrupt_entry |
97 | lbz r10,PACAPROCENABLED(r13) | ||
98 | std r10,SOFTE(r1) | ||
99 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 101 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
100 | #endif | 102 | #endif |
101 | mfmsr r11 | 103 | mfmsr r11 |
@@ -460,9 +462,9 @@ _GLOBAL(ret_from_except_lite) | |||
460 | #endif | 462 | #endif |
461 | 463 | ||
462 | restore: | 464 | restore: |
465 | ld r5,SOFTE(r1) | ||
463 | #ifdef CONFIG_PPC_ISERIES | 466 | #ifdef CONFIG_PPC_ISERIES |
464 | BEGIN_FW_FTR_SECTION | 467 | BEGIN_FW_FTR_SECTION |
465 | ld r5,SOFTE(r1) | ||
466 | cmpdi 0,r5,0 | 468 | cmpdi 0,r5,0 |
467 | beq 4f | 469 | beq 4f |
468 | /* Check for pending interrupts (iSeries) */ | 470 | /* Check for pending interrupts (iSeries) */ |
@@ -472,21 +474,25 @@ BEGIN_FW_FTR_SECTION | |||
472 | beq+ 4f /* skip do_IRQ if no interrupts */ | 474 | beq+ 4f /* skip do_IRQ if no interrupts */ |
473 | 475 | ||
474 | li r3,0 | 476 | li r3,0 |
475 | stb r3,PACAPROCENABLED(r13) /* ensure we are soft-disabled */ | 477 | stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ |
476 | ori r10,r10,MSR_EE | 478 | ori r10,r10,MSR_EE |
477 | mtmsrd r10 /* hard-enable again */ | 479 | mtmsrd r10 /* hard-enable again */ |
478 | addi r3,r1,STACK_FRAME_OVERHEAD | 480 | addi r3,r1,STACK_FRAME_OVERHEAD |
479 | bl .do_IRQ | 481 | bl .do_IRQ |
480 | b .ret_from_except_lite /* loop back and handle more */ | 482 | b .ret_from_except_lite /* loop back and handle more */ |
481 | 483 | 4: | |
482 | 4: stb r5,PACAPROCENABLED(r13) | ||
483 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 484 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
484 | #endif | 485 | #endif |
486 | stb r5,PACASOFTIRQEN(r13) | ||
485 | 487 | ||
486 | ld r3,_MSR(r1) | 488 | ld r3,_MSR(r1) |
487 | andi. r0,r3,MSR_RI | 489 | andi. r0,r3,MSR_RI |
488 | beq- unrecov_restore | 490 | beq- unrecov_restore |
489 | 491 | ||
492 | /* extract EE bit and use it to restore paca->hard_enabled */ | ||
493 | rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ | ||
494 | stb r4,PACAHARDIRQEN(r13) | ||
495 | |||
490 | andi. r0,r3,MSR_PR | 496 | andi. r0,r3,MSR_PR |
491 | 497 | ||
492 | /* | 498 | /* |
@@ -538,25 +544,15 @@ do_work: | |||
538 | /* Check that preempt_count() == 0 and interrupts are enabled */ | 544 | /* Check that preempt_count() == 0 and interrupts are enabled */ |
539 | lwz r8,TI_PREEMPT(r9) | 545 | lwz r8,TI_PREEMPT(r9) |
540 | cmpwi cr1,r8,0 | 546 | cmpwi cr1,r8,0 |
541 | #ifdef CONFIG_PPC_ISERIES | ||
542 | BEGIN_FW_FTR_SECTION | ||
543 | ld r0,SOFTE(r1) | 547 | ld r0,SOFTE(r1) |
544 | cmpdi r0,0 | 548 | cmpdi r0,0 |
545 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
546 | #endif | ||
547 | BEGIN_FW_FTR_SECTION | ||
548 | andi. r0,r3,MSR_EE | ||
549 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
550 | crandc eq,cr1*4+eq,eq | 549 | crandc eq,cr1*4+eq,eq |
551 | bne restore | 550 | bne restore |
552 | /* here we are preempting the current task */ | 551 | /* here we are preempting the current task */ |
553 | 1: | 552 | 1: |
554 | #ifdef CONFIG_PPC_ISERIES | ||
555 | BEGIN_FW_FTR_SECTION | ||
556 | li r0,1 | 553 | li r0,1 |
557 | stb r0,PACAPROCENABLED(r13) | 554 | stb r0,PACASOFTIRQEN(r13) |
558 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 555 | stb r0,PACAHARDIRQEN(r13) |
559 | #endif | ||
560 | ori r10,r10,MSR_EE | 556 | ori r10,r10,MSR_EE |
561 | mtmsrd r10,1 /* reenable interrupts */ | 557 | mtmsrd r10,1 /* reenable interrupts */ |
562 | bl .preempt_schedule | 558 | bl .preempt_schedule |
@@ -639,8 +635,7 @@ _GLOBAL(enter_rtas) | |||
639 | /* There is no way it is acceptable to get here with interrupts enabled, | 635 | /* There is no way it is acceptable to get here with interrupts enabled, |
640 | * check it with the asm equivalent of WARN_ON | 636 | * check it with the asm equivalent of WARN_ON |
641 | */ | 637 | */ |
642 | mfmsr r6 | 638 | lbz r0,PACASOFTIRQEN(r13) |
643 | andi. r0,r6,MSR_EE | ||
644 | 1: tdnei r0,0 | 639 | 1: tdnei r0,0 |
645 | .section __bug_table,"a" | 640 | .section __bug_table,"a" |
646 | .llong 1b,__LINE__ + 0x1000000, 1f, 2f | 641 | .llong 1b,__LINE__ + 0x1000000, 1f, 2f |
@@ -649,7 +644,13 @@ _GLOBAL(enter_rtas) | |||
649 | 1: .asciz __FILE__ | 644 | 1: .asciz __FILE__ |
650 | 2: .asciz "enter_rtas" | 645 | 2: .asciz "enter_rtas" |
651 | .previous | 646 | .previous |
652 | 647 | ||
648 | /* Hard-disable interrupts */ | ||
649 | mfmsr r6 | ||
650 | rldicl r7,r6,48,1 | ||
651 | rotldi r7,r7,16 | ||
652 | mtmsrd r7,1 | ||
653 | |||
653 | /* Unfortunately, the stack pointer and the MSR are also clobbered, | 654 | /* Unfortunately, the stack pointer and the MSR are also clobbered, |
654 | * so they are saved in the PACA which allows us to restore | 655 | * so they are saved in the PACA which allows us to restore |
655 | * our original state after RTAS returns. | 656 | * our original state after RTAS returns. |
@@ -735,8 +736,6 @@ _STATIC(rtas_restore_regs) | |||
735 | 736 | ||
736 | #endif /* CONFIG_PPC_RTAS */ | 737 | #endif /* CONFIG_PPC_RTAS */ |
737 | 738 | ||
738 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
739 | |||
740 | _GLOBAL(enter_prom) | 739 | _GLOBAL(enter_prom) |
741 | mflr r0 | 740 | mflr r0 |
742 | std r0,16(r1) | 741 | std r0,16(r1) |
@@ -821,5 +820,3 @@ _GLOBAL(enter_prom) | |||
821 | ld r0,16(r1) | 820 | ld r0,16(r1) |
822 | mtlr r0 | 821 | mtlr r0 |
823 | blr | 822 | blr |
824 | |||
825 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index e720729f3e55..8cdff5a1f3e2 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -35,9 +35,7 @@ | |||
35 | #include <asm/thread_info.h> | 35 | #include <asm/thread_info.h> |
36 | #include <asm/firmware.h> | 36 | #include <asm/firmware.h> |
37 | 37 | ||
38 | #ifdef CONFIG_PPC_ISERIES | ||
39 | #define DO_SOFT_DISABLE | 38 | #define DO_SOFT_DISABLE |
40 | #endif | ||
41 | 39 | ||
42 | /* | 40 | /* |
43 | * We layout physical memory as follows: | 41 | * We layout physical memory as follows: |
@@ -74,13 +72,11 @@ | |||
74 | .text | 72 | .text |
75 | .globl _stext | 73 | .globl _stext |
76 | _stext: | 74 | _stext: |
77 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
78 | _GLOBAL(__start) | 75 | _GLOBAL(__start) |
79 | /* NOP this out unconditionally */ | 76 | /* NOP this out unconditionally */ |
80 | BEGIN_FTR_SECTION | 77 | BEGIN_FTR_SECTION |
81 | b .__start_initialization_multiplatform | 78 | b .__start_initialization_multiplatform |
82 | END_FTR_SECTION(0, 1) | 79 | END_FTR_SECTION(0, 1) |
83 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
84 | 80 | ||
85 | /* Catch branch to 0 in real mode */ | 81 | /* Catch branch to 0 in real mode */ |
86 | trap | 82 | trap |
@@ -308,7 +304,9 @@ exception_marker: | |||
308 | std r9,_LINK(r1); \ | 304 | std r9,_LINK(r1); \ |
309 | mfctr r10; /* save CTR in stackframe */ \ | 305 | mfctr r10; /* save CTR in stackframe */ \ |
310 | std r10,_CTR(r1); \ | 306 | std r10,_CTR(r1); \ |
307 | lbz r10,PACASOFTIRQEN(r13); \ | ||
311 | mfspr r11,SPRN_XER; /* save XER in stackframe */ \ | 308 | mfspr r11,SPRN_XER; /* save XER in stackframe */ \ |
309 | std r10,SOFTE(r1); \ | ||
312 | std r11,_XER(r1); \ | 310 | std r11,_XER(r1); \ |
313 | li r9,(n)+1; \ | 311 | li r9,(n)+1; \ |
314 | std r9,_TRAP(r1); /* set trap number */ \ | 312 | std r9,_TRAP(r1); /* set trap number */ \ |
@@ -343,6 +341,34 @@ label##_pSeries: \ | |||
343 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) | 341 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) |
344 | 342 | ||
345 | 343 | ||
344 | #define MASKABLE_EXCEPTION_PSERIES(n, label) \ | ||
345 | . = n; \ | ||
346 | .globl label##_pSeries; \ | ||
347 | label##_pSeries: \ | ||
348 | HMT_MEDIUM; \ | ||
349 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ | ||
350 | mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \ | ||
351 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ | ||
352 | std r10,PACA_EXGEN+EX_R10(r13); \ | ||
353 | lbz r10,PACASOFTIRQEN(r13); \ | ||
354 | mfcr r9; \ | ||
355 | cmpwi r10,0; \ | ||
356 | beq masked_interrupt; \ | ||
357 | mfspr r10,SPRN_SPRG1; \ | ||
358 | std r10,PACA_EXGEN+EX_R13(r13); \ | ||
359 | std r11,PACA_EXGEN+EX_R11(r13); \ | ||
360 | std r12,PACA_EXGEN+EX_R12(r13); \ | ||
361 | clrrdi r12,r13,32; /* get high part of &label */ \ | ||
362 | mfmsr r10; \ | ||
363 | mfspr r11,SPRN_SRR0; /* save SRR0 */ \ | ||
364 | LOAD_HANDLER(r12,label##_common) \ | ||
365 | ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \ | ||
366 | mtspr SPRN_SRR0,r12; \ | ||
367 | mfspr r12,SPRN_SRR1; /* and SRR1 */ \ | ||
368 | mtspr SPRN_SRR1,r10; \ | ||
369 | rfid; \ | ||
370 | b . /* prevent speculative execution */ | ||
371 | |||
346 | #define STD_EXCEPTION_ISERIES(n, label, area) \ | 372 | #define STD_EXCEPTION_ISERIES(n, label, area) \ |
347 | .globl label##_iSeries; \ | 373 | .globl label##_iSeries; \ |
348 | label##_iSeries: \ | 374 | label##_iSeries: \ |
@@ -358,40 +384,32 @@ label##_iSeries: \ | |||
358 | HMT_MEDIUM; \ | 384 | HMT_MEDIUM; \ |
359 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ | 385 | mtspr SPRN_SPRG1,r13; /* save r13 */ \ |
360 | EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ | 386 | EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ |
361 | lbz r10,PACAPROCENABLED(r13); \ | 387 | lbz r10,PACASOFTIRQEN(r13); \ |
362 | cmpwi 0,r10,0; \ | 388 | cmpwi 0,r10,0; \ |
363 | beq- label##_iSeries_masked; \ | 389 | beq- label##_iSeries_masked; \ |
364 | EXCEPTION_PROLOG_ISERIES_2; \ | 390 | EXCEPTION_PROLOG_ISERIES_2; \ |
365 | b label##_common; \ | 391 | b label##_common; \ |
366 | 392 | ||
367 | #ifdef DO_SOFT_DISABLE | 393 | #ifdef CONFIG_PPC_ISERIES |
368 | #define DISABLE_INTS \ | 394 | #define DISABLE_INTS \ |
369 | BEGIN_FW_FTR_SECTION; \ | ||
370 | lbz r10,PACAPROCENABLED(r13); \ | ||
371 | li r11,0; \ | 395 | li r11,0; \ |
372 | std r10,SOFTE(r1); \ | 396 | stb r11,PACASOFTIRQEN(r13); \ |
397 | BEGIN_FW_FTR_SECTION; \ | ||
398 | stb r11,PACAHARDIRQEN(r13); \ | ||
399 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | ||
400 | BEGIN_FW_FTR_SECTION; \ | ||
373 | mfmsr r10; \ | 401 | mfmsr r10; \ |
374 | stb r11,PACAPROCENABLED(r13); \ | ||
375 | ori r10,r10,MSR_EE; \ | 402 | ori r10,r10,MSR_EE; \ |
376 | mtmsrd r10,1; \ | 403 | mtmsrd r10,1; \ |
377 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 404 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
378 | 405 | ||
379 | #define ENABLE_INTS \ | 406 | #else |
380 | BEGIN_FW_FTR_SECTION; \ | 407 | #define DISABLE_INTS \ |
381 | lbz r10,PACAPROCENABLED(r13); \ | 408 | li r11,0; \ |
382 | mfmsr r11; \ | 409 | stb r11,PACASOFTIRQEN(r13); \ |
383 | std r10,SOFTE(r1); \ | 410 | stb r11,PACAHARDIRQEN(r13) |
384 | ori r11,r11,MSR_EE; \ | ||
385 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ | ||
386 | BEGIN_FW_FTR_SECTION; \ | ||
387 | ld r12,_MSR(r1); \ | ||
388 | mfmsr r11; \ | ||
389 | rlwimi r11,r12,0,MSR_EE; \ | ||
390 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | ||
391 | mtmsrd r11,1 | ||
392 | 411 | ||
393 | #else /* hard enable/disable interrupts */ | 412 | #endif /* CONFIG_PPC_ISERIES */ |
394 | #define DISABLE_INTS | ||
395 | 413 | ||
396 | #define ENABLE_INTS \ | 414 | #define ENABLE_INTS \ |
397 | ld r12,_MSR(r1); \ | 415 | ld r12,_MSR(r1); \ |
@@ -399,8 +417,6 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | |||
399 | rlwimi r11,r12,0,MSR_EE; \ | 417 | rlwimi r11,r12,0,MSR_EE; \ |
400 | mtmsrd r11,1 | 418 | mtmsrd r11,1 |
401 | 419 | ||
402 | #endif | ||
403 | |||
404 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ | 420 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ |
405 | .align 7; \ | 421 | .align 7; \ |
406 | .globl label##_common; \ | 422 | .globl label##_common; \ |
@@ -541,11 +557,11 @@ instruction_access_slb_pSeries: | |||
541 | mfspr r12,SPRN_SRR1 /* and SRR1 */ | 557 | mfspr r12,SPRN_SRR1 /* and SRR1 */ |
542 | b .slb_miss_realmode /* Rel. branch works in real mode */ | 558 | b .slb_miss_realmode /* Rel. branch works in real mode */ |
543 | 559 | ||
544 | STD_EXCEPTION_PSERIES(0x500, hardware_interrupt) | 560 | MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt) |
545 | STD_EXCEPTION_PSERIES(0x600, alignment) | 561 | STD_EXCEPTION_PSERIES(0x600, alignment) |
546 | STD_EXCEPTION_PSERIES(0x700, program_check) | 562 | STD_EXCEPTION_PSERIES(0x700, program_check) |
547 | STD_EXCEPTION_PSERIES(0x800, fp_unavailable) | 563 | STD_EXCEPTION_PSERIES(0x800, fp_unavailable) |
548 | STD_EXCEPTION_PSERIES(0x900, decrementer) | 564 | MASKABLE_EXCEPTION_PSERIES(0x900, decrementer) |
549 | STD_EXCEPTION_PSERIES(0xa00, trap_0a) | 565 | STD_EXCEPTION_PSERIES(0xa00, trap_0a) |
550 | STD_EXCEPTION_PSERIES(0xb00, trap_0b) | 566 | STD_EXCEPTION_PSERIES(0xb00, trap_0b) |
551 | 567 | ||
@@ -597,7 +613,24 @@ system_call_pSeries: | |||
597 | /*** pSeries interrupt support ***/ | 613 | /*** pSeries interrupt support ***/ |
598 | 614 | ||
599 | /* moved from 0xf00 */ | 615 | /* moved from 0xf00 */ |
600 | STD_EXCEPTION_PSERIES(., performance_monitor) | 616 | MASKABLE_EXCEPTION_PSERIES(., performance_monitor) |
617 | |||
618 | /* | ||
619 | * An interrupt came in while soft-disabled; clear EE in SRR1, | ||
620 | * clear paca->hard_enabled and return. | ||
621 | */ | ||
622 | masked_interrupt: | ||
623 | stb r10,PACAHARDIRQEN(r13) | ||
624 | mtcrf 0x80,r9 | ||
625 | ld r9,PACA_EXGEN+EX_R9(r13) | ||
626 | mfspr r10,SPRN_SRR1 | ||
627 | rldicl r10,r10,48,1 /* clear MSR_EE */ | ||
628 | rotldi r10,r10,16 | ||
629 | mtspr SPRN_SRR1,r10 | ||
630 | ld r10,PACA_EXGEN+EX_R10(r13) | ||
631 | mfspr r13,SPRN_SPRG1 | ||
632 | rfid | ||
633 | b . | ||
601 | 634 | ||
602 | .align 7 | 635 | .align 7 |
603 | do_stab_bolted_pSeries: | 636 | do_stab_bolted_pSeries: |
@@ -926,10 +959,18 @@ bad_stack: | |||
926 | * any task or sent any task a signal, you should use | 959 | * any task or sent any task a signal, you should use |
927 | * ret_from_except or ret_from_except_lite instead of this. | 960 | * ret_from_except or ret_from_except_lite instead of this. |
928 | */ | 961 | */ |
962 | fast_exc_return_irq: /* restores irq state too */ | ||
963 | ld r3,SOFTE(r1) | ||
964 | ld r12,_MSR(r1) | ||
965 | stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */ | ||
966 | rldicl r4,r12,49,63 /* get MSR_EE to LSB */ | ||
967 | stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ | ||
968 | b 1f | ||
969 | |||
929 | .globl fast_exception_return | 970 | .globl fast_exception_return |
930 | fast_exception_return: | 971 | fast_exception_return: |
931 | ld r12,_MSR(r1) | 972 | ld r12,_MSR(r1) |
932 | ld r11,_NIP(r1) | 973 | 1: ld r11,_NIP(r1) |
933 | andi. r3,r12,MSR_RI /* check if RI is set */ | 974 | andi. r3,r12,MSR_RI /* check if RI is set */ |
934 | beq- unrecov_fer | 975 | beq- unrecov_fer |
935 | 976 | ||
@@ -952,7 +993,8 @@ fast_exception_return: | |||
952 | REST_8GPRS(2, r1) | 993 | REST_8GPRS(2, r1) |
953 | 994 | ||
954 | mfmsr r10 | 995 | mfmsr r10 |
955 | clrrdi r10,r10,2 /* clear RI (LE is 0 already) */ | 996 | rldicl r10,r10,48,1 /* clear EE */ |
997 | rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ | ||
956 | mtmsrd r10,1 | 998 | mtmsrd r10,1 |
957 | 999 | ||
958 | mtspr SPRN_SRR1,r12 | 1000 | mtspr SPRN_SRR1,r12 |
@@ -1326,6 +1368,16 @@ BEGIN_FW_FTR_SECTION | |||
1326 | * interrupts if necessary. | 1368 | * interrupts if necessary. |
1327 | */ | 1369 | */ |
1328 | beq 13f | 1370 | beq 13f |
1371 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1372 | #endif | ||
1373 | BEGIN_FW_FTR_SECTION | ||
1374 | /* | ||
1375 | * Here we have interrupts hard-disabled, so it is sufficient | ||
1376 | * to restore paca->{soft,hard}_enable and get out. | ||
1377 | */ | ||
1378 | beq fast_exc_return_irq /* Return from exception on success */ | ||
1379 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1380 | |||
1329 | /* For a hash failure, we don't bother re-enabling interrupts */ | 1381 | /* For a hash failure, we don't bother re-enabling interrupts */ |
1330 | ble- 12f | 1382 | ble- 12f |
1331 | 1383 | ||
@@ -1337,14 +1389,6 @@ BEGIN_FW_FTR_SECTION | |||
1337 | ld r3,SOFTE(r1) | 1389 | ld r3,SOFTE(r1) |
1338 | bl .local_irq_restore | 1390 | bl .local_irq_restore |
1339 | b 11f | 1391 | b 11f |
1340 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1341 | #endif | ||
1342 | BEGIN_FW_FTR_SECTION | ||
1343 | beq fast_exception_return /* Return from exception on success */ | ||
1344 | ble- 12f /* Failure return from hash_page */ | ||
1345 | |||
1346 | /* fall through */ | ||
1347 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1348 | 1392 | ||
1349 | /* Here we have a page fault that hash_page can't handle. */ | 1393 | /* Here we have a page fault that hash_page can't handle. */ |
1350 | handle_page_fault: | 1394 | handle_page_fault: |
@@ -1362,6 +1406,8 @@ handle_page_fault: | |||
1362 | bl .bad_page_fault | 1406 | bl .bad_page_fault |
1363 | b .ret_from_except | 1407 | b .ret_from_except |
1364 | 1408 | ||
1409 | 13: b .ret_from_except_lite | ||
1410 | |||
1365 | /* We have a page fault that hash_page could handle but HV refused | 1411 | /* We have a page fault that hash_page could handle but HV refused |
1366 | * the PTE insertion | 1412 | * the PTE insertion |
1367 | */ | 1413 | */ |
@@ -1371,8 +1417,6 @@ handle_page_fault: | |||
1371 | bl .low_hash_fault | 1417 | bl .low_hash_fault |
1372 | b .ret_from_except | 1418 | b .ret_from_except |
1373 | 1419 | ||
1374 | 13: b .ret_from_except_lite | ||
1375 | |||
1376 | /* here we have a segment miss */ | 1420 | /* here we have a segment miss */ |
1377 | do_ste_alloc: | 1421 | do_ste_alloc: |
1378 | bl .ste_allocate /* try to insert stab entry */ | 1422 | bl .ste_allocate /* try to insert stab entry */ |
@@ -1595,7 +1639,6 @@ _STATIC(__start_initialization_iSeries) | |||
1595 | b .start_here_common | 1639 | b .start_here_common |
1596 | #endif /* CONFIG_PPC_ISERIES */ | 1640 | #endif /* CONFIG_PPC_ISERIES */ |
1597 | 1641 | ||
1598 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1599 | 1642 | ||
1600 | _STATIC(__mmu_off) | 1643 | _STATIC(__mmu_off) |
1601 | mfmsr r3 | 1644 | mfmsr r3 |
@@ -1621,13 +1664,11 @@ _STATIC(__mmu_off) | |||
1621 | * | 1664 | * |
1622 | */ | 1665 | */ |
1623 | _GLOBAL(__start_initialization_multiplatform) | 1666 | _GLOBAL(__start_initialization_multiplatform) |
1624 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1625 | /* | 1667 | /* |
1626 | * Are we booted from a PROM Of-type client-interface ? | 1668 | * Are we booted from a PROM Of-type client-interface ? |
1627 | */ | 1669 | */ |
1628 | cmpldi cr0,r5,0 | 1670 | cmpldi cr0,r5,0 |
1629 | bne .__boot_from_prom /* yes -> prom */ | 1671 | bne .__boot_from_prom /* yes -> prom */ |
1630 | #endif | ||
1631 | 1672 | ||
1632 | /* Save parameters */ | 1673 | /* Save parameters */ |
1633 | mr r31,r3 | 1674 | mr r31,r3 |
@@ -1656,7 +1697,6 @@ _GLOBAL(__start_initialization_multiplatform) | |||
1656 | bl .__mmu_off | 1697 | bl .__mmu_off |
1657 | b .__after_prom_start | 1698 | b .__after_prom_start |
1658 | 1699 | ||
1659 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1660 | _STATIC(__boot_from_prom) | 1700 | _STATIC(__boot_from_prom) |
1661 | /* Save parameters */ | 1701 | /* Save parameters */ |
1662 | mr r31,r3 | 1702 | mr r31,r3 |
@@ -1696,7 +1736,6 @@ _STATIC(__boot_from_prom) | |||
1696 | bl .prom_init | 1736 | bl .prom_init |
1697 | /* We never return */ | 1737 | /* We never return */ |
1698 | trap | 1738 | trap |
1699 | #endif | ||
1700 | 1739 | ||
1701 | /* | 1740 | /* |
1702 | * At this point, r3 contains the physical address we are running at, | 1741 | * At this point, r3 contains the physical address we are running at, |
@@ -1752,8 +1791,6 @@ _STATIC(__after_prom_start) | |||
1752 | bl .copy_and_flush /* copy the rest */ | 1791 | bl .copy_and_flush /* copy the rest */ |
1753 | b .start_here_multiplatform | 1792 | b .start_here_multiplatform |
1754 | 1793 | ||
1755 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1756 | |||
1757 | /* | 1794 | /* |
1758 | * Copy routine used to copy the kernel to start at physical address 0 | 1795 | * Copy routine used to copy the kernel to start at physical address 0 |
1759 | * and flush and invalidate the caches as needed. | 1796 | * and flush and invalidate the caches as needed. |
@@ -1877,11 +1914,16 @@ _GLOBAL(__secondary_start) | |||
1877 | /* enable MMU and jump to start_secondary */ | 1914 | /* enable MMU and jump to start_secondary */ |
1878 | LOAD_REG_ADDR(r3, .start_secondary_prolog) | 1915 | LOAD_REG_ADDR(r3, .start_secondary_prolog) |
1879 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) | 1916 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) |
1880 | #ifdef DO_SOFT_DISABLE | 1917 | #ifdef CONFIG_PPC_ISERIES |
1881 | BEGIN_FW_FTR_SECTION | 1918 | BEGIN_FW_FTR_SECTION |
1882 | ori r4,r4,MSR_EE | 1919 | ori r4,r4,MSR_EE |
1883 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 1920 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
1884 | #endif | 1921 | #endif |
1922 | BEGIN_FW_FTR_SECTION | ||
1923 | stb r7,PACASOFTIRQEN(r13) | ||
1924 | stb r7,PACAHARDIRQEN(r13) | ||
1925 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
1926 | |||
1885 | mtspr SPRN_SRR0,r3 | 1927 | mtspr SPRN_SRR0,r3 |
1886 | mtspr SPRN_SRR1,r4 | 1928 | mtspr SPRN_SRR1,r4 |
1887 | rfid | 1929 | rfid |
@@ -1913,7 +1955,6 @@ _GLOBAL(enable_64b_mode) | |||
1913 | isync | 1955 | isync |
1914 | blr | 1956 | blr |
1915 | 1957 | ||
1916 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
1917 | /* | 1958 | /* |
1918 | * This is where the main kernel code starts. | 1959 | * This is where the main kernel code starts. |
1919 | */ | 1960 | */ |
@@ -1977,7 +2018,6 @@ _STATIC(start_here_multiplatform) | |||
1977 | mtspr SPRN_SRR1,r4 | 2018 | mtspr SPRN_SRR1,r4 |
1978 | rfid | 2019 | rfid |
1979 | b . /* prevent speculative execution */ | 2020 | b . /* prevent speculative execution */ |
1980 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1981 | 2021 | ||
1982 | /* This is where all platforms converge execution */ | 2022 | /* This is where all platforms converge execution */ |
1983 | _STATIC(start_here_common) | 2023 | _STATIC(start_here_common) |
@@ -2005,15 +2045,18 @@ _STATIC(start_here_common) | |||
2005 | 2045 | ||
2006 | /* Load up the kernel context */ | 2046 | /* Load up the kernel context */ |
2007 | 5: | 2047 | 5: |
2008 | #ifdef DO_SOFT_DISABLE | ||
2009 | BEGIN_FW_FTR_SECTION | ||
2010 | li r5,0 | 2048 | li r5,0 |
2011 | stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ | 2049 | stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */ |
2050 | #ifdef CONFIG_PPC_ISERIES | ||
2051 | BEGIN_FW_FTR_SECTION | ||
2012 | mfmsr r5 | 2052 | mfmsr r5 |
2013 | ori r5,r5,MSR_EE /* Hard Enabled */ | 2053 | ori r5,r5,MSR_EE /* Hard Enabled */ |
2014 | mtmsrd r5 | 2054 | mtmsrd r5 |
2015 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | 2055 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
2016 | #endif | 2056 | #endif |
2057 | BEGIN_FW_FTR_SECTION | ||
2058 | stb r5,PACAHARDIRQEN(r13) | ||
2059 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
2017 | 2060 | ||
2018 | bl .start_kernel | 2061 | bl .start_kernel |
2019 | 2062 | ||
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index 4180c3998b39..8994af327b47 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -39,6 +39,13 @@ | |||
39 | #define cpu_should_die() 0 | 39 | #define cpu_should_die() 0 |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | static int __init powersave_off(char *arg) | ||
43 | { | ||
44 | ppc_md.power_save = NULL; | ||
45 | return 0; | ||
46 | } | ||
47 | __setup("powersave=off", powersave_off); | ||
48 | |||
42 | /* | 49 | /* |
43 | * The body of the idle task. | 50 | * The body of the idle task. |
44 | */ | 51 | */ |
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index 30de81da7b40..ba3195478600 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S | |||
@@ -30,6 +30,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) | |||
30 | beqlr | 30 | beqlr |
31 | 31 | ||
32 | /* Go to NAP now */ | 32 | /* Go to NAP now */ |
33 | mfmsr r7 | ||
34 | rldicl r0,r7,48,1 | ||
35 | rotldi r0,r0,16 | ||
36 | mtmsrd r0,1 /* hard-disable interrupts */ | ||
37 | li r0,1 | ||
38 | stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ | ||
39 | stb r0,PACAHARDIRQEN(r13) | ||
33 | BEGIN_FTR_SECTION | 40 | BEGIN_FTR_SECTION |
34 | DSSALL | 41 | DSSALL |
35 | sync | 42 | sync |
@@ -38,7 +45,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
38 | ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ | 45 | ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ |
39 | ori r8,r8,_TLF_NAPPING /* so when we take an exception */ | 46 | ori r8,r8,_TLF_NAPPING /* so when we take an exception */ |
40 | std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ | 47 | std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ |
41 | mfmsr r7 | ||
42 | ori r7,r7,MSR_EE | 48 | ori r7,r7,MSR_EE |
43 | oris r7,r7,MSR_POW@h | 49 | oris r7,r7,MSR_POW@h |
44 | 1: sync | 50 | 1: sync |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5e37bf14ef2d..eb9fc621e057 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -64,8 +64,9 @@ | |||
64 | #include <asm/ptrace.h> | 64 | #include <asm/ptrace.h> |
65 | #include <asm/machdep.h> | 65 | #include <asm/machdep.h> |
66 | #include <asm/udbg.h> | 66 | #include <asm/udbg.h> |
67 | #ifdef CONFIG_PPC_ISERIES | 67 | #ifdef CONFIG_PPC64 |
68 | #include <asm/paca.h> | 68 | #include <asm/paca.h> |
69 | #include <asm/firmware.h> | ||
69 | #endif | 70 | #endif |
70 | 71 | ||
71 | int __irq_offset_value; | 72 | int __irq_offset_value; |
@@ -95,6 +96,27 @@ extern atomic_t ipi_sent; | |||
95 | EXPORT_SYMBOL(irq_desc); | 96 | EXPORT_SYMBOL(irq_desc); |
96 | 97 | ||
97 | int distribute_irqs = 1; | 98 | int distribute_irqs = 1; |
99 | |||
100 | void local_irq_restore(unsigned long en) | ||
101 | { | ||
102 | get_paca()->soft_enabled = en; | ||
103 | if (!en) | ||
104 | return; | ||
105 | |||
106 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
107 | if (get_paca()->lppaca_ptr->int_dword.any_int) | ||
108 | iseries_handle_interrupts(); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | if (get_paca()->hard_enabled) | ||
113 | return; | ||
114 | /* need to hard-enable interrupts here */ | ||
115 | get_paca()->hard_enabled = en; | ||
116 | if ((int)mfspr(SPRN_DEC) < 0) | ||
117 | mtspr(SPRN_DEC, 1); | ||
118 | hard_irq_enable(); | ||
119 | } | ||
98 | #endif /* CONFIG_PPC64 */ | 120 | #endif /* CONFIG_PPC64 */ |
99 | 121 | ||
100 | int show_interrupts(struct seq_file *p, void *v) | 122 | int show_interrupts(struct seq_file *p, void *v) |
@@ -626,10 +648,14 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); | |||
626 | 648 | ||
627 | void irq_dispose_mapping(unsigned int virq) | 649 | void irq_dispose_mapping(unsigned int virq) |
628 | { | 650 | { |
629 | struct irq_host *host = irq_map[virq].host; | 651 | struct irq_host *host; |
630 | irq_hw_number_t hwirq; | 652 | irq_hw_number_t hwirq; |
631 | unsigned long flags; | 653 | unsigned long flags; |
632 | 654 | ||
655 | if (virq == NO_IRQ) | ||
656 | return; | ||
657 | |||
658 | host = irq_map[virq].host; | ||
633 | WARN_ON (host == NULL); | 659 | WARN_ON (host == NULL); |
634 | if (host == NULL) | 660 | if (host == NULL) |
635 | return; | 661 | return; |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 9bae8a5bf671..80ae9ea15cdc 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -42,11 +42,9 @@ | |||
42 | unsigned long pci_probe_only = 1; | 42 | unsigned long pci_probe_only = 1; |
43 | int pci_assign_all_buses = 0; | 43 | int pci_assign_all_buses = 0; |
44 | 44 | ||
45 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
46 | static void fixup_resource(struct resource *res, struct pci_dev *dev); | 45 | static void fixup_resource(struct resource *res, struct pci_dev *dev); |
47 | static void do_bus_setup(struct pci_bus *bus); | 46 | static void do_bus_setup(struct pci_bus *bus); |
48 | static void phbs_remap_io(void); | 47 | static void phbs_remap_io(void); |
49 | #endif | ||
50 | 48 | ||
51 | /* pci_io_base -- the base address from which io bars are offsets. | 49 | /* pci_io_base -- the base address from which io bars are offsets. |
52 | * This is the lowest I/O base address (so bar values are always positive), | 50 | * This is the lowest I/O base address (so bar values are always positive), |
@@ -251,7 +249,6 @@ static void __init pcibios_claim_of_setup(void) | |||
251 | pcibios_claim_one_bus(b); | 249 | pcibios_claim_one_bus(b); |
252 | } | 250 | } |
253 | 251 | ||
254 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
255 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) | 252 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) |
256 | { | 253 | { |
257 | const u32 *prop; | 254 | const u32 *prop; |
@@ -506,7 +503,6 @@ void __devinit of_scan_pci_bridge(struct device_node *node, | |||
506 | pci_scan_child_bus(bus); | 503 | pci_scan_child_bus(bus); |
507 | } | 504 | } |
508 | EXPORT_SYMBOL(of_scan_pci_bridge); | 505 | EXPORT_SYMBOL(of_scan_pci_bridge); |
509 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
510 | 506 | ||
511 | void __devinit scan_phb(struct pci_controller *hose) | 507 | void __devinit scan_phb(struct pci_controller *hose) |
512 | { | 508 | { |
@@ -540,7 +536,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
540 | } | 536 | } |
541 | 537 | ||
542 | mode = PCI_PROBE_NORMAL; | 538 | mode = PCI_PROBE_NORMAL; |
543 | #ifdef CONFIG_PPC_MULTIPLATFORM | 539 | |
544 | if (node && ppc_md.pci_probe_mode) | 540 | if (node && ppc_md.pci_probe_mode) |
545 | mode = ppc_md.pci_probe_mode(bus); | 541 | mode = ppc_md.pci_probe_mode(bus); |
546 | DBG(" probe mode: %d\n", mode); | 542 | DBG(" probe mode: %d\n", mode); |
@@ -548,7 +544,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
548 | bus->subordinate = hose->last_busno; | 544 | bus->subordinate = hose->last_busno; |
549 | of_scan_bus(node, bus); | 545 | of_scan_bus(node, bus); |
550 | } | 546 | } |
551 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 547 | |
552 | if (mode == PCI_PROBE_NORMAL) | 548 | if (mode == PCI_PROBE_NORMAL) |
553 | hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); | 549 | hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); |
554 | } | 550 | } |
@@ -592,11 +588,9 @@ static int __init pcibios_init(void) | |||
592 | if (ppc64_isabridge_dev != NULL) | 588 | if (ppc64_isabridge_dev != NULL) |
593 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); | 589 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); |
594 | 590 | ||
595 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
596 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 591 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
597 | /* map in PCI I/O space */ | 592 | /* map in PCI I/O space */ |
598 | phbs_remap_io(); | 593 | phbs_remap_io(); |
599 | #endif | ||
600 | 594 | ||
601 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); | 595 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); |
602 | 596 | ||
@@ -873,8 +867,6 @@ void pcibios_add_platform_entries(struct pci_dev *pdev) | |||
873 | device_create_file(&pdev->dev, &dev_attr_devspec); | 867 | device_create_file(&pdev->dev, &dev_attr_devspec); |
874 | } | 868 | } |
875 | 869 | ||
876 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
877 | |||
878 | #define ISA_SPACE_MASK 0x1 | 870 | #define ISA_SPACE_MASK 0x1 |
879 | #define ISA_SPACE_IO 0x1 | 871 | #define ISA_SPACE_IO 0x1 |
880 | 872 | ||
@@ -1343,8 +1335,6 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) | |||
1343 | return NULL; | 1335 | return NULL; |
1344 | } | 1336 | } |
1345 | 1337 | ||
1346 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
1347 | |||
1348 | unsigned long pci_address_to_pio(phys_addr_t address) | 1338 | unsigned long pci_address_to_pio(phys_addr_t address) |
1349 | { | 1339 | { |
1350 | struct pci_controller *hose, *tmp; | 1340 | struct pci_controller *hose, *tmp; |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 807193a3c784..9179f0739ea2 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -49,6 +49,10 @@ | |||
49 | #include <asm/commproc.h> | 49 | #include <asm/commproc.h> |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #ifdef CONFIG_PPC64 | ||
53 | EXPORT_SYMBOL(local_irq_restore); | ||
54 | #endif | ||
55 | |||
52 | #ifdef CONFIG_PPC32 | 56 | #ifdef CONFIG_PPC32 |
53 | extern void transfer_to_handler(void); | 57 | extern void transfer_to_handler(void); |
54 | extern void do_IRQ(struct pt_regs *regs); | 58 | extern void do_IRQ(struct pt_regs *regs); |
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index bdb412d4b748..16d29d16b96f 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -1674,6 +1674,7 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) | |||
1674 | } | 1674 | } |
1675 | return NULL; | 1675 | return NULL; |
1676 | } | 1676 | } |
1677 | EXPORT_SYMBOL(of_get_cpu_node); | ||
1677 | 1678 | ||
1678 | #ifdef DEBUG | 1679 | #ifdef DEBUG |
1679 | static struct debugfs_blob_wrapper flat_dt_blob; | 1680 | static struct debugfs_blob_wrapper flat_dt_blob; |
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c index 603dff3ad62a..346fb7bf9a05 100644 --- a/arch/powerpc/kernel/prom_parse.c +++ b/arch/powerpc/kernel/prom_parse.c | |||
@@ -25,6 +25,12 @@ | |||
25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | 25 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ |
26 | (ns) > 0) | 26 | (ns) > 0) |
27 | 27 | ||
28 | static struct of_bus *of_match_bus(struct device_node *np); | ||
29 | static int __of_address_to_resource(struct device_node *dev, | ||
30 | const u32 *addrp, u64 size, unsigned int flags, | ||
31 | struct resource *r); | ||
32 | |||
33 | |||
28 | /* Debug utility */ | 34 | /* Debug utility */ |
29 | #ifdef DEBUG | 35 | #ifdef DEBUG |
30 | static void of_dump_addr(const char *s, const u32 *addr, int na) | 36 | static void of_dump_addr(const char *s, const u32 *addr, int na) |
@@ -101,6 +107,7 @@ static unsigned int of_bus_default_get_flags(const u32 *addr) | |||
101 | } | 107 | } |
102 | 108 | ||
103 | 109 | ||
110 | #ifdef CONFIG_PCI | ||
104 | /* | 111 | /* |
105 | * PCI bus specific translator | 112 | * PCI bus specific translator |
106 | */ | 113 | */ |
@@ -162,6 +169,145 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr) | |||
162 | return flags; | 169 | return flags; |
163 | } | 170 | } |
164 | 171 | ||
172 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
173 | unsigned int *flags) | ||
174 | { | ||
175 | const u32 *prop; | ||
176 | unsigned int psize; | ||
177 | struct device_node *parent; | ||
178 | struct of_bus *bus; | ||
179 | int onesize, i, na, ns; | ||
180 | |||
181 | /* Get parent & match bus type */ | ||
182 | parent = of_get_parent(dev); | ||
183 | if (parent == NULL) | ||
184 | return NULL; | ||
185 | bus = of_match_bus(parent); | ||
186 | if (strcmp(bus->name, "pci")) { | ||
187 | of_node_put(parent); | ||
188 | return NULL; | ||
189 | } | ||
190 | bus->count_cells(dev, &na, &ns); | ||
191 | of_node_put(parent); | ||
192 | if (!OF_CHECK_COUNTS(na, ns)) | ||
193 | return NULL; | ||
194 | |||
195 | /* Get "reg" or "assigned-addresses" property */ | ||
196 | prop = get_property(dev, bus->addresses, &psize); | ||
197 | if (prop == NULL) | ||
198 | return NULL; | ||
199 | psize /= 4; | ||
200 | |||
201 | onesize = na + ns; | ||
202 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
203 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
204 | if (size) | ||
205 | *size = of_read_number(prop + na, ns); | ||
206 | if (flags) | ||
207 | *flags = bus->get_flags(prop); | ||
208 | return prop; | ||
209 | } | ||
210 | return NULL; | ||
211 | } | ||
212 | EXPORT_SYMBOL(of_get_pci_address); | ||
213 | |||
214 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
215 | struct resource *r) | ||
216 | { | ||
217 | const u32 *addrp; | ||
218 | u64 size; | ||
219 | unsigned int flags; | ||
220 | |||
221 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
222 | if (addrp == NULL) | ||
223 | return -EINVAL; | ||
224 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
225 | } | ||
226 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
227 | |||
228 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
229 | { | ||
230 | return (((pin - 1) + slot) % 4) + 1; | ||
231 | } | ||
232 | |||
233 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
234 | { | ||
235 | struct device_node *dn, *ppnode; | ||
236 | struct pci_dev *ppdev; | ||
237 | u32 lspec; | ||
238 | u32 laddr[3]; | ||
239 | u8 pin; | ||
240 | int rc; | ||
241 | |||
242 | /* Check if we have a device node, if yes, fallback to standard OF | ||
243 | * parsing | ||
244 | */ | ||
245 | dn = pci_device_to_OF_node(pdev); | ||
246 | if (dn) | ||
247 | return of_irq_map_one(dn, 0, out_irq); | ||
248 | |||
249 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
250 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
251 | * for PCI. If you do different, then don't use that routine. | ||
252 | */ | ||
253 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
254 | if (rc != 0) | ||
255 | return rc; | ||
256 | /* No pin, exit */ | ||
257 | if (pin == 0) | ||
258 | return -ENODEV; | ||
259 | |||
260 | /* Now we walk up the PCI tree */ | ||
261 | lspec = pin; | ||
262 | for (;;) { | ||
263 | /* Get the pci_dev of our parent */ | ||
264 | ppdev = pdev->bus->self; | ||
265 | |||
266 | /* Ouch, it's a host bridge... */ | ||
267 | if (ppdev == NULL) { | ||
268 | #ifdef CONFIG_PPC64 | ||
269 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
270 | #else | ||
271 | struct pci_controller *host; | ||
272 | host = pci_bus_to_host(pdev->bus); | ||
273 | ppnode = host ? host->arch_data : NULL; | ||
274 | #endif | ||
275 | /* No node for host bridge ? give up */ | ||
276 | if (ppnode == NULL) | ||
277 | return -EINVAL; | ||
278 | } else | ||
279 | /* We found a P2P bridge, check if it has a node */ | ||
280 | ppnode = pci_device_to_OF_node(ppdev); | ||
281 | |||
282 | /* Ok, we have found a parent with a device-node, hand over to | ||
283 | * the OF parsing code. | ||
284 | * We build a unit address from the linux device to be used for | ||
285 | * resolution. Note that we use the linux bus number which may | ||
286 | * not match your firmware bus numbering. | ||
287 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
288 | * the bus number as part of the matching. | ||
289 | * You should still be careful about that though if you intend | ||
290 | * to rely on this function (you ship a firmware that doesn't | ||
291 | * create device nodes for all PCI devices). | ||
292 | */ | ||
293 | if (ppnode) | ||
294 | break; | ||
295 | |||
296 | /* We can only get here if we hit a P2P bridge with no node, | ||
297 | * let's do standard swizzling and try again | ||
298 | */ | ||
299 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
300 | pdev = ppdev; | ||
301 | } | ||
302 | |||
303 | laddr[0] = (pdev->bus->number << 16) | ||
304 | | (pdev->devfn << 8); | ||
305 | laddr[1] = laddr[2] = 0; | ||
306 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
307 | } | ||
308 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
309 | #endif /* CONFIG_PCI */ | ||
310 | |||
165 | /* | 311 | /* |
166 | * ISA bus specific translator | 312 | * ISA bus specific translator |
167 | */ | 313 | */ |
@@ -223,6 +369,7 @@ static unsigned int of_bus_isa_get_flags(const u32 *addr) | |||
223 | */ | 369 | */ |
224 | 370 | ||
225 | static struct of_bus of_busses[] = { | 371 | static struct of_bus of_busses[] = { |
372 | #ifdef CONFIG_PCI | ||
226 | /* PCI */ | 373 | /* PCI */ |
227 | { | 374 | { |
228 | .name = "pci", | 375 | .name = "pci", |
@@ -233,6 +380,7 @@ static struct of_bus of_busses[] = { | |||
233 | .translate = of_bus_pci_translate, | 380 | .translate = of_bus_pci_translate, |
234 | .get_flags = of_bus_pci_get_flags, | 381 | .get_flags = of_bus_pci_get_flags, |
235 | }, | 382 | }, |
383 | #endif /* CONFIG_PCI */ | ||
236 | /* ISA */ | 384 | /* ISA */ |
237 | { | 385 | { |
238 | .name = "isa", | 386 | .name = "isa", |
@@ -445,48 +593,6 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size, | |||
445 | } | 593 | } |
446 | EXPORT_SYMBOL(of_get_address); | 594 | EXPORT_SYMBOL(of_get_address); |
447 | 595 | ||
448 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
449 | unsigned int *flags) | ||
450 | { | ||
451 | const u32 *prop; | ||
452 | unsigned int psize; | ||
453 | struct device_node *parent; | ||
454 | struct of_bus *bus; | ||
455 | int onesize, i, na, ns; | ||
456 | |||
457 | /* Get parent & match bus type */ | ||
458 | parent = of_get_parent(dev); | ||
459 | if (parent == NULL) | ||
460 | return NULL; | ||
461 | bus = of_match_bus(parent); | ||
462 | if (strcmp(bus->name, "pci")) { | ||
463 | of_node_put(parent); | ||
464 | return NULL; | ||
465 | } | ||
466 | bus->count_cells(dev, &na, &ns); | ||
467 | of_node_put(parent); | ||
468 | if (!OF_CHECK_COUNTS(na, ns)) | ||
469 | return NULL; | ||
470 | |||
471 | /* Get "reg" or "assigned-addresses" property */ | ||
472 | prop = get_property(dev, bus->addresses, &psize); | ||
473 | if (prop == NULL) | ||
474 | return NULL; | ||
475 | psize /= 4; | ||
476 | |||
477 | onesize = na + ns; | ||
478 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
479 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
480 | if (size) | ||
481 | *size = of_read_number(prop + na, ns); | ||
482 | if (flags) | ||
483 | *flags = bus->get_flags(prop); | ||
484 | return prop; | ||
485 | } | ||
486 | return NULL; | ||
487 | } | ||
488 | EXPORT_SYMBOL(of_get_pci_address); | ||
489 | |||
490 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, | 596 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, |
491 | u64 size, unsigned int flags, | 597 | u64 size, unsigned int flags, |
492 | struct resource *r) | 598 | struct resource *r) |
@@ -529,20 +635,6 @@ int of_address_to_resource(struct device_node *dev, int index, | |||
529 | } | 635 | } |
530 | EXPORT_SYMBOL_GPL(of_address_to_resource); | 636 | EXPORT_SYMBOL_GPL(of_address_to_resource); |
531 | 637 | ||
532 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
533 | struct resource *r) | ||
534 | { | ||
535 | const u32 *addrp; | ||
536 | u64 size; | ||
537 | unsigned int flags; | ||
538 | |||
539 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
540 | if (addrp == NULL) | ||
541 | return -EINVAL; | ||
542 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
543 | } | ||
544 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
545 | |||
546 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, | 638 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, |
547 | unsigned long *busno, unsigned long *phys, unsigned long *size) | 639 | unsigned long *busno, unsigned long *phys, unsigned long *size) |
548 | { | 640 | { |
@@ -898,87 +990,3 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq | |||
898 | return res; | 990 | return res; |
899 | } | 991 | } |
900 | EXPORT_SYMBOL_GPL(of_irq_map_one); | 992 | EXPORT_SYMBOL_GPL(of_irq_map_one); |
901 | |||
902 | #ifdef CONFIG_PCI | ||
903 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
904 | { | ||
905 | return (((pin - 1) + slot) % 4) + 1; | ||
906 | } | ||
907 | |||
908 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
909 | { | ||
910 | struct device_node *dn, *ppnode; | ||
911 | struct pci_dev *ppdev; | ||
912 | u32 lspec; | ||
913 | u32 laddr[3]; | ||
914 | u8 pin; | ||
915 | int rc; | ||
916 | |||
917 | /* Check if we have a device node, if yes, fallback to standard OF | ||
918 | * parsing | ||
919 | */ | ||
920 | dn = pci_device_to_OF_node(pdev); | ||
921 | if (dn) | ||
922 | return of_irq_map_one(dn, 0, out_irq); | ||
923 | |||
924 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
925 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
926 | * for PCI. If you do different, then don't use that routine. | ||
927 | */ | ||
928 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
929 | if (rc != 0) | ||
930 | return rc; | ||
931 | /* No pin, exit */ | ||
932 | if (pin == 0) | ||
933 | return -ENODEV; | ||
934 | |||
935 | /* Now we walk up the PCI tree */ | ||
936 | lspec = pin; | ||
937 | for (;;) { | ||
938 | /* Get the pci_dev of our parent */ | ||
939 | ppdev = pdev->bus->self; | ||
940 | |||
941 | /* Ouch, it's a host bridge... */ | ||
942 | if (ppdev == NULL) { | ||
943 | #ifdef CONFIG_PPC64 | ||
944 | ppnode = pci_bus_to_OF_node(pdev->bus); | ||
945 | #else | ||
946 | struct pci_controller *host; | ||
947 | host = pci_bus_to_host(pdev->bus); | ||
948 | ppnode = host ? host->arch_data : NULL; | ||
949 | #endif | ||
950 | /* No node for host bridge ? give up */ | ||
951 | if (ppnode == NULL) | ||
952 | return -EINVAL; | ||
953 | } else | ||
954 | /* We found a P2P bridge, check if it has a node */ | ||
955 | ppnode = pci_device_to_OF_node(ppdev); | ||
956 | |||
957 | /* Ok, we have found a parent with a device-node, hand over to | ||
958 | * the OF parsing code. | ||
959 | * We build a unit address from the linux device to be used for | ||
960 | * resolution. Note that we use the linux bus number which may | ||
961 | * not match your firmware bus numbering. | ||
962 | * Fortunately, in most cases, interrupt-map-mask doesn't include | ||
963 | * the bus number as part of the matching. | ||
964 | * You should still be careful about that though if you intend | ||
965 | * to rely on this function (you ship a firmware that doesn't | ||
966 | * create device nodes for all PCI devices). | ||
967 | */ | ||
968 | if (ppnode) | ||
969 | break; | ||
970 | |||
971 | /* We can only get here if we hit a P2P bridge with no node, | ||
972 | * let's do standard swizzling and try again | ||
973 | */ | ||
974 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
975 | pdev = ppdev; | ||
976 | } | ||
977 | |||
978 | laddr[0] = (pdev->bus->number << 16) | ||
979 | | (pdev->devfn << 8); | ||
980 | laddr[1] = laddr[2] = 0; | ||
981 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
982 | } | ||
983 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
984 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index a4c2964a3ca6..04df53a3c86d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -63,10 +63,6 @@ unsigned int DMA_MODE_WRITE; | |||
63 | 63 | ||
64 | int have_of = 1; | 64 | int have_of = 1; |
65 | 65 | ||
66 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
67 | dev_t boot_dev; | ||
68 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
69 | |||
70 | #ifdef CONFIG_VGA_CONSOLE | 66 | #ifdef CONFIG_VGA_CONSOLE |
71 | unsigned long vgacon_remap_base; | 67 | unsigned long vgacon_remap_base; |
72 | #endif | 68 | #endif |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 16278968dab6..b0f1c82df994 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -71,7 +71,6 @@ | |||
71 | 71 | ||
72 | int have_of = 1; | 72 | int have_of = 1; |
73 | int boot_cpuid = 0; | 73 | int boot_cpuid = 0; |
74 | dev_t boot_dev; | ||
75 | u64 ppc64_pft_size; | 74 | u64 ppc64_pft_size; |
76 | 75 | ||
77 | /* Pick defaults since we might want to patch instructions | 76 | /* Pick defaults since we might want to patch instructions |
@@ -226,8 +225,8 @@ void early_setup_secondary(void) | |||
226 | { | 225 | { |
227 | struct paca_struct *lpaca = get_paca(); | 226 | struct paca_struct *lpaca = get_paca(); |
228 | 227 | ||
229 | /* Mark enabled in PACA */ | 228 | /* Mark interrupts enabled in PACA */ |
230 | lpaca->proc_enabled = 0; | 229 | lpaca->soft_enabled = 0; |
231 | 230 | ||
232 | /* Initialize hash table for that CPU */ | 231 | /* Initialize hash table for that CPU */ |
233 | htab_initialize_secondary(); | 232 | htab_initialize_secondary(); |
@@ -392,7 +391,8 @@ void __init setup_system(void) | |||
392 | * setting up the hash table pointers. It also sets up some interrupt-mapping | 391 | * setting up the hash table pointers. It also sets up some interrupt-mapping |
393 | * related options that will be used by finish_device_tree() | 392 | * related options that will be used by finish_device_tree() |
394 | */ | 393 | */ |
395 | ppc_md.init_early(); | 394 | if (ppc_md.init_early) |
395 | ppc_md.init_early(); | ||
396 | 396 | ||
397 | /* | 397 | /* |
398 | * We can discover serial ports now since the above did setup the | 398 | * We can discover serial ports now since the above did setup the |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 35c6309bdb76..9b28c238b6c0 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -65,6 +65,7 @@ cpumask_t cpu_sibling_map[NR_CPUS] = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; | |||
65 | 65 | ||
66 | EXPORT_SYMBOL(cpu_online_map); | 66 | EXPORT_SYMBOL(cpu_online_map); |
67 | EXPORT_SYMBOL(cpu_possible_map); | 67 | EXPORT_SYMBOL(cpu_possible_map); |
68 | EXPORT_SYMBOL(cpu_sibling_map); | ||
68 | 69 | ||
69 | /* SMP operations for this machine */ | 70 | /* SMP operations for this machine */ |
70 | struct smp_ops_t *smp_ops; | 71 | struct smp_ops_t *smp_ops; |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d45a168bdaca..cda21a27490a 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -299,6 +299,72 @@ static struct notifier_block __cpuinitdata sysfs_cpu_nb = { | |||
299 | .notifier_call = sysfs_cpu_notify, | 299 | .notifier_call = sysfs_cpu_notify, |
300 | }; | 300 | }; |
301 | 301 | ||
302 | static DEFINE_MUTEX(cpu_mutex); | ||
303 | |||
304 | int cpu_add_sysdev_attr(struct sysdev_attribute *attr) | ||
305 | { | ||
306 | int cpu; | ||
307 | |||
308 | mutex_lock(&cpu_mutex); | ||
309 | |||
310 | for_each_possible_cpu(cpu) { | ||
311 | sysdev_create_file(get_cpu_sysdev(cpu), attr); | ||
312 | } | ||
313 | |||
314 | mutex_unlock(&cpu_mutex); | ||
315 | return 0; | ||
316 | } | ||
317 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr); | ||
318 | |||
319 | int cpu_add_sysdev_attr_group(struct attribute_group *attrs) | ||
320 | { | ||
321 | int cpu; | ||
322 | struct sys_device *sysdev; | ||
323 | |||
324 | mutex_lock(&cpu_mutex); | ||
325 | |||
326 | for_each_possible_cpu(cpu) { | ||
327 | sysdev = get_cpu_sysdev(cpu); | ||
328 | sysfs_create_group(&sysdev->kobj, attrs); | ||
329 | } | ||
330 | |||
331 | mutex_unlock(&cpu_mutex); | ||
332 | return 0; | ||
333 | } | ||
334 | EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group); | ||
335 | |||
336 | |||
337 | void cpu_remove_sysdev_attr(struct sysdev_attribute *attr) | ||
338 | { | ||
339 | int cpu; | ||
340 | |||
341 | mutex_lock(&cpu_mutex); | ||
342 | |||
343 | for_each_possible_cpu(cpu) { | ||
344 | sysdev_remove_file(get_cpu_sysdev(cpu), attr); | ||
345 | } | ||
346 | |||
347 | mutex_unlock(&cpu_mutex); | ||
348 | } | ||
349 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr); | ||
350 | |||
351 | void cpu_remove_sysdev_attr_group(struct attribute_group *attrs) | ||
352 | { | ||
353 | int cpu; | ||
354 | struct sys_device *sysdev; | ||
355 | |||
356 | mutex_lock(&cpu_mutex); | ||
357 | |||
358 | for_each_possible_cpu(cpu) { | ||
359 | sysdev = get_cpu_sysdev(cpu); | ||
360 | sysfs_remove_group(&sysdev->kobj, attrs); | ||
361 | } | ||
362 | |||
363 | mutex_unlock(&cpu_mutex); | ||
364 | } | ||
365 | EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group); | ||
366 | |||
367 | |||
302 | /* NUMA stuff */ | 368 | /* NUMA stuff */ |
303 | 369 | ||
304 | #ifdef CONFIG_NUMA | 370 | #ifdef CONFIG_NUMA |
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index e8fa50624b70..03aeb3a46077 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -426,18 +426,21 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | |||
426 | 426 | ||
427 | /* kernel has accessed a bad area */ | 427 | /* kernel has accessed a bad area */ |
428 | 428 | ||
429 | printk(KERN_ALERT "Unable to handle kernel paging request for "); | ||
430 | switch (regs->trap) { | 429 | switch (regs->trap) { |
431 | case 0x300: | 430 | case 0x300: |
432 | case 0x380: | 431 | case 0x380: |
433 | printk("data at address 0x%08lx\n", regs->dar); | 432 | printk(KERN_ALERT "Unable to handle kernel paging request for " |
434 | break; | 433 | "data at address 0x%08lx\n", regs->dar); |
435 | case 0x400: | 434 | break; |
436 | case 0x480: | 435 | case 0x400: |
437 | printk("instruction fetch\n"); | 436 | case 0x480: |
438 | break; | 437 | printk(KERN_ALERT "Unable to handle kernel paging request for " |
439 | default: | 438 | "instruction fetch\n"); |
440 | printk("unknown fault\n"); | 439 | break; |
440 | default: | ||
441 | printk(KERN_ALERT "Unable to handle kernel paging request for " | ||
442 | "unknown fault\n"); | ||
443 | break; | ||
441 | } | 444 | } |
442 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", | 445 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", |
443 | regs->nip); | 446 | regs->nip); |
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c index c90f124f3c71..6f1016acdbf6 100644 --- a/arch/powerpc/mm/hash_native_64.c +++ b/arch/powerpc/mm/hash_native_64.c | |||
@@ -123,7 +123,7 @@ static inline void native_unlock_hpte(hpte_t *hptep) | |||
123 | clear_bit(HPTE_LOCK_BIT, word); | 123 | clear_bit(HPTE_LOCK_BIT, word); |
124 | } | 124 | } |
125 | 125 | ||
126 | long native_hpte_insert(unsigned long hpte_group, unsigned long va, | 126 | static long native_hpte_insert(unsigned long hpte_group, unsigned long va, |
127 | unsigned long pa, unsigned long rflags, | 127 | unsigned long pa, unsigned long rflags, |
128 | unsigned long vflags, int psize) | 128 | unsigned long vflags, int psize) |
129 | { | 129 | { |
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) | |||
5 | obj-$(CONFIG_PPC_PMAC) += powermac/ | 5 | obj-$(CONFIG_PPC_PMAC) += powermac/ |
6 | endif | 6 | endif |
7 | endif | 7 | endif |
8 | obj-$(CONFIG_PPC_EFIKA) += efika/ | ||
8 | obj-$(CONFIG_PPC_CHRP) += chrp/ | 9 | obj-$(CONFIG_PPC_CHRP) += chrp/ |
9 | obj-$(CONFIG_4xx) += 4xx/ | 10 | obj-$(CONFIG_4xx) += 4xx/ |
10 | obj-$(CONFIG_PPC_83xx) += 83xx/ | 11 | obj-$(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 | ||
23 | config CBE_THERM | ||
24 | tristate "CBE thermal support" | ||
25 | default m | ||
26 | depends on CBE_RAS | ||
27 | |||
28 | config 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 | |||
23 | endmenu | 37 | endmenu |
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 @@ | |||
1 | obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \ | 1 | obj-$(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 | ||
3 | obj-$(CONFIG_CBE_RAS) += ras.o | 4 | obj-$(CONFIG_CBE_RAS) += ras.o |
4 | 5 | ||
6 | obj-$(CONFIG_CBE_THERM) += cbe_thermal.o | ||
7 | obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o | ||
8 | |||
5 | ifeq ($(CONFIG_SMP),y) | 9 | ifeq ($(CONFIG_SMP),y) |
6 | obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o | 10 | obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o |
7 | endif | 11 | endif |
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 | |||
34 | static DEFINE_MUTEX(cbe_switch_mutex); | ||
35 | |||
36 | |||
37 | /* the CBE supports an 8 step frequency scaling */ | ||
38 | static 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 */ | ||
51 | static u64 MIC_Slow_Fast_Timer_table[] = { | ||
52 | [0 ... 7] = 0x007fc00000000000ull, | ||
53 | }; | ||
54 | |||
55 | /* more values for the MIC */ | ||
56 | static 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 | |||
71 | static 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 | |||
82 | static 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 | |||
127 | static 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 | |||
176 | static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) | ||
177 | { | ||
178 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int cbe_cpufreq_verify(struct cpufreq_policy *policy) | ||
183 | { | ||
184 | return cpufreq_frequency_table_verify(policy, cbe_freqs); | ||
185 | } | ||
186 | |||
187 | |||
188 | static 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 | |||
220 | static 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 | |||
234 | static int __init cbe_cpufreq_init(void) | ||
235 | { | ||
236 | return cpufreq_register_driver(&cbe_cpufreq_driver); | ||
237 | } | ||
238 | |||
239 | static void __exit cbe_cpufreq_exit(void) | ||
240 | { | ||
241 | cpufreq_unregister_driver(&cbe_cpufreq_driver); | ||
242 | } | ||
243 | |||
244 | module_init(cbe_cpufreq_init); | ||
245 | module_exit(cbe_cpufreq_exit); | ||
246 | |||
247 | MODULE_LICENSE("GPL"); | ||
248 | MODULE_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]; |
34 | static int cbe_regs_map_count; | 35 | static int cbe_regs_map_count; |
35 | 36 | ||
@@ -42,6 +43,19 @@ static struct cbe_thread_map | |||
42 | static struct cbe_regs_map *cbe_find_map(struct device_node *np) | 43 | static 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 | } |
73 | EXPORT_SYMBOL_GPL(cbe_get_pmd_regs); | ||
59 | 74 | ||
60 | struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu) | 75 | struct 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 | } |
82 | EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs); | ||
83 | |||
84 | struct 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 | ||
92 | struct 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 | ||
69 | struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np) | 100 | struct 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 | |||
76 | struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu) | 108 | struct 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 | ||
116 | struct 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 | |||
124 | struct 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 | } | ||
131 | EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs); | ||
132 | |||
133 | |||
84 | void __init cbe_regs_init(void) | 134 | void __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 | |||
43 | union spe_reg { | ||
44 | u64 val; | ||
45 | u8 spe[8]; | ||
46 | }; | ||
47 | |||
48 | union ppe_spe_reg { | ||
49 | u64 val; | ||
50 | struct { | ||
51 | u32 ppe; | ||
52 | u32 spe; | ||
53 | }; | ||
54 | }; | ||
55 | |||
56 | |||
32 | struct cbe_pmd_regs { | 57 | struct 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 | ||
73 | extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); | 125 | extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np); |
74 | extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu); | 126 | extern 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 | |||
145 | struct 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 | |||
160 | extern struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np); | ||
161 | extern 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); | |||
122 | extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu); | 211 | extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu); |
123 | 212 | ||
124 | 213 | ||
214 | struct 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 | |||
253 | extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np); | ||
254 | extern 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 */ |
126 | extern void cbe_regs_init(void); | 257 | extern 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 | |||
33 | static 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 */ | ||
43 | static 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(®->val); | ||
54 | |||
55 | return value.spe[*id]; | ||
56 | } | ||
57 | |||
58 | static 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 | |||
76 | static 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 */ | ||
99 | static 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 */ | ||
105 | static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf) | ||
106 | { | ||
107 | return ppe_show_temp(sysdev, buf, 0); | ||
108 | } | ||
109 | |||
110 | static struct sysdev_attribute attr_spu_temperature = { | ||
111 | .attr = {.name = "temperature", .mode = 0400 }, | ||
112 | .show = spu_show_temp, | ||
113 | }; | ||
114 | |||
115 | static struct attribute *spu_attributes[] = { | ||
116 | &attr_spu_temperature.attr, | ||
117 | }; | ||
118 | |||
119 | static struct attribute_group spu_attribute_group = { | ||
120 | .name = "thermal", | ||
121 | .attrs = spu_attributes, | ||
122 | }; | ||
123 | |||
124 | static struct sysdev_attribute attr_ppe_temperature0 = { | ||
125 | .attr = {.name = "temperature0", .mode = 0400 }, | ||
126 | .show = ppe_show_temp0, | ||
127 | }; | ||
128 | |||
129 | static struct sysdev_attribute attr_ppe_temperature1 = { | ||
130 | .attr = {.name = "temperature1", .mode = 0400 }, | ||
131 | .show = ppe_show_temp1, | ||
132 | }; | ||
133 | |||
134 | static struct attribute *ppe_attributes[] = { | ||
135 | &attr_ppe_temperature0.attr, | ||
136 | &attr_ppe_temperature1.attr, | ||
137 | }; | ||
138 | |||
139 | static struct attribute_group ppe_attribute_group = { | ||
140 | .name = "thermal", | ||
141 | .attrs = ppe_attributes, | ||
142 | }; | ||
143 | |||
144 | /* | ||
145 | * initialize throttling with default values | ||
146 | */ | ||
147 | static 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 | |||
205 | static 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 | } | ||
214 | module_init(thermal_init); | ||
215 | |||
216 | static 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 | } | ||
221 | module_exit(thermal_exit); | ||
222 | |||
223 | MODULE_LICENSE("GPL"); | ||
224 | MODULE_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 | ||
41 | static DEFINE_SPINLOCK(cbe_pervasive_lock); | 41 | static void cbe_power_save(void) |
42 | |||
43 | static 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 | ||
81 | out: | 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 | |||
85 | static 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 | ||
132 | static int cbe_system_reset_exception(struct pt_regs *regs) | 79 | static 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 | ||
159 | void __init cbe_pervasive_init(void) | 106 | void __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(®s->pmcr, in_be64(®s->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 | |||
71 | u32 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 | |||
89 | void 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 | |||
121 | u32 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 | |||
134 | void 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 | |||
158 | u32 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 | |||
168 | void 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 | |||
178 | u32 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 | |||
219 | void 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 | |||
260 | u32 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 | |||
272 | void 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 | |||
296 | void 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 | |||
308 | void 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 | |||
321 | void 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 | |||
28 | enum 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 | |||
39 | extern u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr); | ||
40 | extern void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val); | ||
41 | extern u32 cbe_read_ctr(u32 cpu, u32 ctr); | ||
42 | extern void cbe_write_ctr(u32 cpu, u32 ctr, u32 val); | ||
43 | |||
44 | extern u32 cbe_read_pm07_control(u32 cpu, u32 ctr); | ||
45 | extern void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val); | ||
46 | extern u32 cbe_read_pm (u32 cpu, enum pm_reg_name reg); | ||
47 | extern void cbe_write_pm (u32 cpu, enum pm_reg_name reg, u32 val); | ||
48 | |||
49 | extern u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr); | ||
50 | extern void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size); | ||
51 | |||
52 | extern void cbe_enable_pm(u32 cpu); | ||
53 | extern void cbe_disable_pm(u32 cpu); | ||
54 | |||
55 | extern 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 | ||
322 | static struct list_head spu_list[MAX_NUMNODES]; | 336 | static struct list_head spu_list[MAX_NUMNODES]; |
337 | static LIST_HEAD(spu_full_list); | ||
323 | static DEFINE_MUTEX(spu_mutex); | 338 | static DEFINE_MUTEX(spu_mutex); |
324 | 339 | ||
325 | static void spu_init_channels(struct spu *spu) | 340 | static 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 | ||
761 | static ssize_t spu_show_isrc(struct sys_device *sysdev, char *buf) | 774 | int 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 | } |
767 | static SYSDEV_ATTR(isrc, 0400, spu_show_isrc, NULL); | 785 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr); |
786 | |||
787 | int spu_add_sysdev_attr_group(struct attribute_group *attrs) | ||
788 | { | ||
789 | struct spu *spu; | ||
790 | mutex_lock(&spu_mutex); | ||
768 | 791 | ||
769 | extern 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 | } | ||
798 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); | ||
799 | |||
800 | |||
801 | void 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 | } | ||
811 | EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr); | ||
812 | |||
813 | void 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 | } | ||
823 | EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group); | ||
770 | 824 | ||
771 | static int spu_create_sysdev(struct spu *spu) | 825 | static 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 | ||
791 | static void spu_destroy_sysdev(struct spu *spu) | 843 | static 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: | |||
866 | static void destroy_spu(struct spu *spu) | 920 | static 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 | } |
917 | module_init(init_spu_base); | 977 | module_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 | ||
87 | static void mfc_sdr_set(struct spu *spu, u64 sdr) | 87 | static 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 | ||
92 | static void mfc_sr1_set(struct spu *spu, u64 sr1) | 92 | static 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 | ||
123 | int 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 | |||
144 | out: | ||
145 | if (ret) | ||
146 | up_write(&ctx->state_sema); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
123 | int spu_acquire_runnable(struct spu_context *ctx) | 150 | int 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 | |||
1347 | static 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 | |||
1353 | static 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 | |||
1372 | static struct file_operations spufs_recycle_fops = { | ||
1373 | .open = spufs_recycle_open, | ||
1374 | .write = spufs_recycle_write, | ||
1375 | }; | ||
1376 | |||
1346 | static void spufs_npc_set(void *data, u64 val) | 1377 | static 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 | |||
1566 | struct 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 | ||
220 | static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val) | 220 | static 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 | ||
226 | static void spu_hw_runcntl_stop(struct spu_context *ctx) | 229 | static 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 | ||
43 | static kmem_cache_t *spufs_inode_cache; | 45 | static kmem_cache_t *spufs_inode_cache; |
46 | static char *isolated_loader; | ||
44 | 47 | ||
45 | static struct inode * | 48 | static struct inode * |
46 | spufs_alloc_inode(struct super_block *sb) | 49 | spufs_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 | ||
238 | static 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 | |||
311 | out_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 | |||
316 | out_unlock: | ||
317 | spu_release_exclusive(ctx); | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | int spu_recycle_isolated(struct spu_context *ctx) | ||
322 | { | ||
323 | ctx->ops->runcntl_stop(ctx); | ||
324 | return spu_setup_isolated(ctx); | ||
325 | } | ||
326 | |||
235 | static int | 327 | static int |
236 | spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, | 328 | spufs_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, | |||
326 | out_unlock: | 432 | out_unlock: |
327 | mutex_unlock(&inode->i_mutex); | 433 | mutex_unlock(&inode->i_mutex); |
328 | out: | 434 | out: |
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 | ||
656 | static void | ||
657 | spufs_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 | |||
543 | static int | 680 | static int |
544 | spufs_create_root(struct super_block *sb, void *data) | 681 | spufs_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; |
629 | out_fs: | 768 | out_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) | |||
51 | static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | 53 | static 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 | ||
137 | extern struct tree_descr spufs_dir_contents[]; | 137 | extern struct tree_descr spufs_dir_contents[]; |
138 | extern struct tree_descr spufs_dir_nosched_contents[]; | ||
138 | 139 | ||
139 | /* system call implementation */ | 140 | /* system call implementation */ |
140 | long spufs_run_spu(struct file *file, | 141 | long spufs_run_spu(struct file *file, |
@@ -162,6 +163,12 @@ void spu_acquire(struct spu_context *ctx); | |||
162 | void spu_release(struct spu_context *ctx); | 163 | void spu_release(struct spu_context *ctx); |
163 | int spu_acquire_runnable(struct spu_context *ctx); | 164 | int spu_acquire_runnable(struct spu_context *ctx); |
164 | void spu_acquire_saved(struct spu_context *ctx); | 165 | void spu_acquire_saved(struct spu_context *ctx); |
166 | int spu_acquire_exclusive(struct spu_context *ctx); | ||
167 | |||
168 | static inline void spu_release_exclusive(struct spu_context *ctx) | ||
169 | { | ||
170 | up_write(&ctx->state_sema); | ||
171 | } | ||
165 | 172 | ||
166 | int spu_activate(struct spu_context *ctx, u64 flags); | 173 | int spu_activate(struct spu_context *ctx, u64 flags); |
167 | void spu_deactivate(struct spu_context *ctx); | 174 | void spu_deactivate(struct spu_context *ctx); |
@@ -169,6 +176,7 @@ void spu_yield(struct spu_context *ctx); | |||
169 | int __init spu_sched_init(void); | 176 | int __init spu_sched_init(void); |
170 | void __exit spu_sched_exit(void); | 177 | void __exit spu_sched_exit(void); |
171 | 178 | ||
179 | int 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 | ||
1919 | static 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 | */ | ||
1951 | static 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 | |||
1919 | static void harvest(struct spu_state *prev, struct spu *spu) | 1964 | static 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 | } |
2105 | EXPORT_SYMBOL_GPL(spu_save); | 2151 | EXPORT_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 | |||
17 | extern 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 | */ | ||
21 | static 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 | |||
36 | static 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 | |||
50 | static struct pci_ops rtas_pci_ops = { | ||
51 | rtas_read_config, | ||
52 | rtas_write_config | ||
53 | }; | ||
54 | |||
55 | void __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 | ||
117 | void __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 | |||
36 | static 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 | |||
67 | static 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 | |||
86 | static 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 | |||
114 | static 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 | |||
131 | define_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 | ||
209 | static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name, | 209 | static 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 | ||
216 | static void __init dt_prop_u64_list(struct iseries_flat_dt *dt, | 215 | static 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 | ||
308 | static 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 | |||
309 | static void __init dt_do_vdevice(struct iseries_flat_dt *dt, | 319 | static 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); | |||
19 | EXPORT_SYMBOL(HvCall5); | 19 | EXPORT_SYMBOL(HvCall5); |
20 | EXPORT_SYMBOL(HvCall6); | 20 | EXPORT_SYMBOL(HvCall6); |
21 | EXPORT_SYMBOL(HvCall7); | 21 | EXPORT_SYMBOL(HvCall7); |
22 | |||
23 | #ifdef CONFIG_SMP | ||
24 | EXPORT_SYMBOL(local_get_flags); | ||
25 | EXPORT_SYMBOL(local_irq_disable); | ||
26 | EXPORT_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); | |||
80 | static void iSeries_pci_final_fixup(void) { } | 79 | static void iSeries_pci_final_fixup(void) { } |
81 | #endif | 80 | #endif |
82 | 81 | ||
83 | extern int rd_size; /* Defined in drivers/block/rd.c */ | ||
84 | |||
85 | extern unsigned long iSeries_recal_tb; | 82 | extern unsigned long iSeries_recal_tb; |
86 | extern unsigned long iSeries_recal_titan; | 83 | extern 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 | ||
487 | static u32 save_fcr[6]; | 487 | static u32 save_fcr[6]; |
488 | static u32 save_mbcr; | 488 | static u32 save_mbcr; |
489 | static u32 save_gpio_levels[2]; | ||
490 | static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; | ||
491 | static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; | ||
492 | static u32 save_unin_clock_ctl; | ||
493 | static struct dbdma_regs save_dbdma[13]; | 489 | static struct dbdma_regs save_dbdma[13]; |
494 | static struct dbdma_regs save_alt_dbdma[13]; | 490 | static 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 |
1547 | static u32 save_gpio_levels[2]; | ||
1548 | static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; | ||
1549 | static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; | ||
1550 | static u32 save_unin_clock_ctl; | ||
1551 | 1551 | ||
1552 | static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode) | 1552 | static 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; | |||
361 | void *boot_host; | 361 | void *boot_host; |
362 | int boot_target; | 362 | int boot_target; |
363 | int boot_part; | 363 | int boot_part; |
364 | extern dev_t boot_dev; | 364 | static dev_t boot_dev; |
365 | 365 | ||
366 | #ifdef CONFIG_SCSI | 366 | #ifdef CONFIG_SCSI |
367 | void __init note_scsi_host(struct device_node *node, void *host) | 367 | void __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 | ||
285 | long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 285 | static 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 | */ |
509 | void pSeries_lpar_flush_hash_range(unsigned long number, int local) | 509 | static 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; |
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 91f052d8cce0..5b87f7b42a1f 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -10,9 +10,9 @@ obj-$(CONFIG_40x) += dcr.o | |||
10 | obj-$(CONFIG_U3_DART) += dart_iommu.o | 10 | obj-$(CONFIG_U3_DART) += dart_iommu.o |
11 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o | 11 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o |
12 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o | 12 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o |
13 | obj-$(CONFIG_PPC_TODC) += todc.o | ||
14 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o | 13 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o |
15 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ | 14 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ |
15 | obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_pic.o | ||
16 | 16 | ||
17 | ifeq ($(CONFIG_PPC_MERGE),y) | 17 | ifeq ($(CONFIG_PPC_MERGE),y) |
18 | obj-$(CONFIG_PPC_I8259) += i8259.o | 18 | obj-$(CONFIG_PPC_I8259) += i8259.o |
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index dbe92ae20333..ad31e56e892b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/phy.h> | ||
25 | #include <linux/fsl_devices.h> | 26 | #include <linux/fsl_devices.h> |
26 | #include <linux/fs_enet_pd.h> | 27 | #include <linux/fs_enet_pd.h> |
27 | #include <linux/fs_uart_pd.h> | 28 | #include <linux/fs_uart_pd.h> |
@@ -146,7 +147,7 @@ static int __init gfar_mdio_of_init(void) | |||
146 | } | 147 | } |
147 | 148 | ||
148 | for (k = 0; k < 32; k++) | 149 | for (k = 0; k < 32; k++) |
149 | mdio_data.irq[k] = -1; | 150 | mdio_data.irq[k] = PHY_POLL; |
150 | 151 | ||
151 | while ((child = of_get_next_child(np, child)) != NULL) { | 152 | while ((child = of_get_next_child(np, child)) != NULL) { |
152 | int irq = irq_of_parse_and_map(child, 0); | 153 | int irq = irq_of_parse_and_map(child, 0); |
@@ -177,6 +178,7 @@ static const char *gfar_tx_intr = "tx"; | |||
177 | static const char *gfar_rx_intr = "rx"; | 178 | static const char *gfar_rx_intr = "rx"; |
178 | static const char *gfar_err_intr = "error"; | 179 | static const char *gfar_err_intr = "error"; |
179 | 180 | ||
181 | |||
180 | static int __init gfar_of_init(void) | 182 | static int __init gfar_of_init(void) |
181 | { | 183 | { |
182 | struct device_node *np; | 184 | struct device_node *np; |
@@ -204,8 +206,7 @@ static int __init gfar_of_init(void) | |||
204 | if (ret) | 206 | if (ret) |
205 | goto err; | 207 | goto err; |
206 | 208 | ||
207 | r[1].start = r[1].end = irq_of_parse_and_map(np, 0); | 209 | of_irq_to_resource(np, 0, &r[1]); |
208 | r[1].flags = IORESOURCE_IRQ; | ||
209 | 210 | ||
210 | model = get_property(np, "model", NULL); | 211 | model = get_property(np, "model", NULL); |
211 | 212 | ||
@@ -214,12 +215,10 @@ static int __init gfar_of_init(void) | |||
214 | r[1].name = gfar_tx_intr; | 215 | r[1].name = gfar_tx_intr; |
215 | 216 | ||
216 | r[2].name = gfar_rx_intr; | 217 | r[2].name = gfar_rx_intr; |
217 | r[2].start = r[2].end = irq_of_parse_and_map(np, 1); | 218 | of_irq_to_resource(np, 1, &r[2]); |
218 | r[2].flags = IORESOURCE_IRQ; | ||
219 | 219 | ||
220 | r[3].name = gfar_err_intr; | 220 | r[3].name = gfar_err_intr; |
221 | r[3].start = r[3].end = irq_of_parse_and_map(np, 2); | 221 | of_irq_to_resource(np, 2, &r[3]); |
222 | r[3].flags = IORESOURCE_IRQ; | ||
223 | 222 | ||
224 | n_res += 2; | 223 | n_res += 2; |
225 | } | 224 | } |
@@ -323,8 +322,7 @@ static int __init fsl_i2c_of_init(void) | |||
323 | if (ret) | 322 | if (ret) |
324 | goto err; | 323 | goto err; |
325 | 324 | ||
326 | r[1].start = r[1].end = irq_of_parse_and_map(np, 0); | 325 | of_irq_to_resource(np, 0, &r[1]); |
327 | r[1].flags = IORESOURCE_IRQ; | ||
328 | 326 | ||
329 | i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2); | 327 | i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2); |
330 | if (IS_ERR(i2c_dev)) { | 328 | if (IS_ERR(i2c_dev)) { |
@@ -459,8 +457,7 @@ static int __init fsl_usb_of_init(void) | |||
459 | if (ret) | 457 | if (ret) |
460 | goto err; | 458 | goto err; |
461 | 459 | ||
462 | r[1].start = r[1].end = irq_of_parse_and_map(np, 0); | 460 | of_irq_to_resource(np, 0, &r[1]); |
463 | r[1].flags = IORESOURCE_IRQ; | ||
464 | 461 | ||
465 | usb_dev_mph = | 462 | usb_dev_mph = |
466 | platform_device_register_simple("fsl-ehci", i, r, 2); | 463 | platform_device_register_simple("fsl-ehci", i, r, 2); |
@@ -507,8 +504,7 @@ static int __init fsl_usb_of_init(void) | |||
507 | if (ret) | 504 | if (ret) |
508 | goto unreg_mph; | 505 | goto unreg_mph; |
509 | 506 | ||
510 | r[1].start = r[1].end = irq_of_parse_and_map(np, 0); | 507 | of_irq_to_resource(np, 0, &r[1]); |
511 | r[1].flags = IORESOURCE_IRQ; | ||
512 | 508 | ||
513 | usb_dev_dr = | 509 | usb_dev_dr = |
514 | platform_device_register_simple("fsl-ehci", i, r, 2); | 510 | platform_device_register_simple("fsl-ehci", i, r, 2); |
@@ -591,8 +587,7 @@ static int __init fs_enet_of_init(void) | |||
591 | r[2].name = fcc_regs_c; | 587 | r[2].name = fcc_regs_c; |
592 | fs_enet_data.fcc_regs_c = r[2].start; | 588 | fs_enet_data.fcc_regs_c = r[2].start; |
593 | 589 | ||
594 | r[3].start = r[3].end = irq_of_parse_and_map(np, 0); | 590 | of_irq_to_resource(np, 0, &r[3]); |
595 | r[3].flags = IORESOURCE_IRQ; | ||
596 | 591 | ||
597 | fs_enet_dev = | 592 | fs_enet_dev = |
598 | platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); | 593 | platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4); |
@@ -754,8 +749,7 @@ static int __init cpm_uart_of_init(void) | |||
754 | goto err; | 749 | goto err; |
755 | r[1].name = scc_pram; | 750 | r[1].name = scc_pram; |
756 | 751 | ||
757 | r[2].start = r[2].end = irq_of_parse_and_map(np, 0); | 752 | of_irq_to_resource(np, 0, &r[2]); |
758 | r[2].flags = IORESOURCE_IRQ; | ||
759 | 753 | ||
760 | cpm_uart_dev = | 754 | cpm_uart_dev = |
761 | platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3); | 755 | platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3); |
diff --git a/arch/powerpc/sysdev/mpc52xx_pic.c b/arch/powerpc/sysdev/mpc52xx_pic.c new file mode 100644 index 000000000000..6df51f04b8f5 --- /dev/null +++ b/arch/powerpc/sysdev/mpc52xx_pic.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Programmable Interrupt Controller functions for the Freescale MPC52xx. | ||
4 | * | ||
5 | * Copyright (C) 2006 bplan GmbH | ||
6 | * | ||
7 | * Based on the code from the 2.4 kernel by | ||
8 | * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. | ||
9 | * | ||
10 | * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> | ||
11 | * Copyright (C) 2003 Montavista Software, Inc | ||
12 | * | ||
13 | * This file is licensed under the terms of the GNU General Public License | ||
14 | * version 2. This program is licensed "as is" without any warranty of any | ||
15 | * kind, whether express or implied. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/signal.h> | ||
25 | #include <linux/stddef.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/hardirq.h> | ||
29 | |||
30 | #include <asm/io.h> | ||
31 | #include <asm/processor.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/irq.h> | ||
34 | #include <asm/prom.h> | ||
35 | #include <asm/mpc52xx.h> | ||
36 | |||
37 | /* | ||
38 | * | ||
39 | */ | ||
40 | |||
41 | static struct mpc52xx_intr __iomem *intr; | ||
42 | static struct mpc52xx_sdma __iomem *sdma; | ||
43 | static struct irq_host *mpc52xx_irqhost = NULL; | ||
44 | |||
45 | static unsigned char mpc52xx_map_senses[4] = { | ||
46 | IRQ_TYPE_LEVEL_HIGH, | ||
47 | IRQ_TYPE_EDGE_RISING, | ||
48 | IRQ_TYPE_EDGE_FALLING, | ||
49 | IRQ_TYPE_LEVEL_LOW, | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * | ||
54 | */ | ||
55 | |||
56 | static inline void io_be_setbit(u32 __iomem * addr, int bitno) | ||
57 | { | ||
58 | out_be32(addr, in_be32(addr) | (1 << bitno)); | ||
59 | } | ||
60 | |||
61 | static inline void io_be_clrbit(u32 __iomem * addr, int bitno) | ||
62 | { | ||
63 | out_be32(addr, in_be32(addr) & ~(1 << bitno)); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * IRQ[0-3] interrupt irq_chip | ||
68 | */ | ||
69 | |||
70 | static void mpc52xx_extirq_mask(unsigned int virq) | ||
71 | { | ||
72 | int irq; | ||
73 | int l2irq; | ||
74 | |||
75 | irq = irq_map[virq].hwirq; | ||
76 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
77 | |||
78 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
79 | |||
80 | io_be_clrbit(&intr->ctrl, 11 - l2irq); | ||
81 | } | ||
82 | |||
83 | static void mpc52xx_extirq_unmask(unsigned int virq) | ||
84 | { | ||
85 | int irq; | ||
86 | int l2irq; | ||
87 | |||
88 | irq = irq_map[virq].hwirq; | ||
89 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
90 | |||
91 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
92 | |||
93 | io_be_setbit(&intr->ctrl, 11 - l2irq); | ||
94 | } | ||
95 | |||
96 | static void mpc52xx_extirq_ack(unsigned int virq) | ||
97 | { | ||
98 | int irq; | ||
99 | int l2irq; | ||
100 | |||
101 | irq = irq_map[virq].hwirq; | ||
102 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
103 | |||
104 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
105 | |||
106 | io_be_setbit(&intr->ctrl, 27 - l2irq); | ||
107 | } | ||
108 | |||
109 | static struct irq_chip mpc52xx_extirq_irqchip = { | ||
110 | .typename = " MPC52xx IRQ[0-3] ", | ||
111 | .mask = mpc52xx_extirq_mask, | ||
112 | .unmask = mpc52xx_extirq_unmask, | ||
113 | .ack = mpc52xx_extirq_ack, | ||
114 | }; | ||
115 | |||
116 | /* | ||
117 | * Main interrupt irq_chip | ||
118 | */ | ||
119 | |||
120 | static void mpc52xx_main_mask(unsigned int virq) | ||
121 | { | ||
122 | int irq; | ||
123 | int l2irq; | ||
124 | |||
125 | irq = irq_map[virq].hwirq; | ||
126 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
127 | |||
128 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
129 | |||
130 | io_be_setbit(&intr->main_mask, 15 - l2irq); | ||
131 | } | ||
132 | |||
133 | static void mpc52xx_main_unmask(unsigned int virq) | ||
134 | { | ||
135 | int irq; | ||
136 | int l2irq; | ||
137 | |||
138 | irq = irq_map[virq].hwirq; | ||
139 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
140 | |||
141 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
142 | |||
143 | io_be_clrbit(&intr->main_mask, 15 - l2irq); | ||
144 | } | ||
145 | |||
146 | static struct irq_chip mpc52xx_main_irqchip = { | ||
147 | .typename = "MPC52xx Main", | ||
148 | .mask = mpc52xx_main_mask, | ||
149 | .mask_ack = mpc52xx_main_mask, | ||
150 | .unmask = mpc52xx_main_unmask, | ||
151 | }; | ||
152 | |||
153 | /* | ||
154 | * Peripherals interrupt irq_chip | ||
155 | */ | ||
156 | |||
157 | static void mpc52xx_periph_mask(unsigned int virq) | ||
158 | { | ||
159 | int irq; | ||
160 | int l2irq; | ||
161 | |||
162 | irq = irq_map[virq].hwirq; | ||
163 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
164 | |||
165 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
166 | |||
167 | io_be_setbit(&intr->per_mask, 31 - l2irq); | ||
168 | } | ||
169 | |||
170 | static void mpc52xx_periph_unmask(unsigned int virq) | ||
171 | { | ||
172 | int irq; | ||
173 | int l2irq; | ||
174 | |||
175 | irq = irq_map[virq].hwirq; | ||
176 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
177 | |||
178 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
179 | |||
180 | io_be_clrbit(&intr->per_mask, 31 - l2irq); | ||
181 | } | ||
182 | |||
183 | static struct irq_chip mpc52xx_periph_irqchip = { | ||
184 | .typename = "MPC52xx Peripherals", | ||
185 | .mask = mpc52xx_periph_mask, | ||
186 | .mask_ack = mpc52xx_periph_mask, | ||
187 | .unmask = mpc52xx_periph_unmask, | ||
188 | }; | ||
189 | |||
190 | /* | ||
191 | * SDMA interrupt irq_chip | ||
192 | */ | ||
193 | |||
194 | static void mpc52xx_sdma_mask(unsigned int virq) | ||
195 | { | ||
196 | int irq; | ||
197 | int l2irq; | ||
198 | |||
199 | irq = irq_map[virq].hwirq; | ||
200 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
201 | |||
202 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
203 | |||
204 | io_be_setbit(&sdma->IntMask, l2irq); | ||
205 | } | ||
206 | |||
207 | static void mpc52xx_sdma_unmask(unsigned int virq) | ||
208 | { | ||
209 | int irq; | ||
210 | int l2irq; | ||
211 | |||
212 | irq = irq_map[virq].hwirq; | ||
213 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
214 | |||
215 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
216 | |||
217 | io_be_clrbit(&sdma->IntMask, l2irq); | ||
218 | } | ||
219 | |||
220 | static void mpc52xx_sdma_ack(unsigned int virq) | ||
221 | { | ||
222 | int irq; | ||
223 | int l2irq; | ||
224 | |||
225 | irq = irq_map[virq].hwirq; | ||
226 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
227 | |||
228 | pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); | ||
229 | |||
230 | out_be32(&sdma->IntPend, 1 << l2irq); | ||
231 | } | ||
232 | |||
233 | static struct irq_chip mpc52xx_sdma_irqchip = { | ||
234 | .typename = "MPC52xx SDMA", | ||
235 | .mask = mpc52xx_sdma_mask, | ||
236 | .unmask = mpc52xx_sdma_unmask, | ||
237 | .ack = mpc52xx_sdma_ack, | ||
238 | }; | ||
239 | |||
240 | /* | ||
241 | * irq_host | ||
242 | */ | ||
243 | |||
244 | static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) | ||
245 | { | ||
246 | pr_debug("%s: node=%p\n", __func__, node); | ||
247 | return mpc52xx_irqhost->host_data == node; | ||
248 | } | ||
249 | |||
250 | static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, | ||
251 | u32 * intspec, unsigned int intsize, | ||
252 | irq_hw_number_t * out_hwirq, | ||
253 | unsigned int *out_flags) | ||
254 | { | ||
255 | int intrvect_l1; | ||
256 | int intrvect_l2; | ||
257 | int intrvect_type; | ||
258 | int intrvect_linux; | ||
259 | |||
260 | if (intsize != 3) | ||
261 | return -1; | ||
262 | |||
263 | intrvect_l1 = (int)intspec[0]; | ||
264 | intrvect_l2 = (int)intspec[1]; | ||
265 | intrvect_type = (int)intspec[2]; | ||
266 | |||
267 | intrvect_linux = | ||
268 | (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; | ||
269 | intrvect_linux |= | ||
270 | (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; | ||
271 | |||
272 | pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, | ||
273 | intrvect_l2); | ||
274 | |||
275 | *out_hwirq = intrvect_linux; | ||
276 | *out_flags = mpc52xx_map_senses[intrvect_type]; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * this function retrieves the correct IRQ type out | ||
283 | * of the MPC regs | ||
284 | * Only externals IRQs needs this | ||
285 | */ | ||
286 | static int mpc52xx_irqx_gettype(int irq) | ||
287 | { | ||
288 | int type; | ||
289 | u32 ctrl_reg; | ||
290 | |||
291 | ctrl_reg = in_be32(&intr->ctrl); | ||
292 | type = (ctrl_reg >> (22 - irq * 2)) & 0x3; | ||
293 | |||
294 | return mpc52xx_map_senses[type]; | ||
295 | } | ||
296 | |||
297 | static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, | ||
298 | irq_hw_number_t irq) | ||
299 | { | ||
300 | int l1irq; | ||
301 | int l2irq; | ||
302 | struct irq_chip *good_irqchip; | ||
303 | void *good_handle; | ||
304 | int type; | ||
305 | |||
306 | l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; | ||
307 | l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; | ||
308 | |||
309 | /* | ||
310 | * Most of ours IRQs will be level low | ||
311 | * Only external IRQs on some platform may be others | ||
312 | */ | ||
313 | type = IRQ_TYPE_LEVEL_LOW; | ||
314 | |||
315 | switch (l1irq) { | ||
316 | case MPC52xx_IRQ_L1_CRIT: | ||
317 | pr_debug("%s: Critical. l2=%x\n", __func__, l2irq); | ||
318 | |||
319 | BUG_ON(l2irq != 0); | ||
320 | |||
321 | type = mpc52xx_irqx_gettype(l2irq); | ||
322 | good_irqchip = &mpc52xx_extirq_irqchip; | ||
323 | break; | ||
324 | |||
325 | case MPC52xx_IRQ_L1_MAIN: | ||
326 | pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq); | ||
327 | |||
328 | if ((l2irq >= 1) && (l2irq <= 3)) { | ||
329 | type = mpc52xx_irqx_gettype(l2irq); | ||
330 | good_irqchip = &mpc52xx_extirq_irqchip; | ||
331 | } else { | ||
332 | good_irqchip = &mpc52xx_main_irqchip; | ||
333 | } | ||
334 | break; | ||
335 | |||
336 | case MPC52xx_IRQ_L1_PERP: | ||
337 | pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq); | ||
338 | good_irqchip = &mpc52xx_periph_irqchip; | ||
339 | break; | ||
340 | |||
341 | case MPC52xx_IRQ_L1_SDMA: | ||
342 | pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq); | ||
343 | good_irqchip = &mpc52xx_sdma_irqchip; | ||
344 | break; | ||
345 | |||
346 | default: | ||
347 | pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq); | ||
348 | printk(KERN_ERR "Unknow IRQ!\n"); | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
352 | switch (type) { | ||
353 | case IRQ_TYPE_EDGE_FALLING: | ||
354 | case IRQ_TYPE_EDGE_RISING: | ||
355 | good_handle = handle_edge_irq; | ||
356 | break; | ||
357 | default: | ||
358 | good_handle = handle_level_irq; | ||
359 | } | ||
360 | |||
361 | set_irq_chip_and_handler(virq, good_irqchip, good_handle); | ||
362 | |||
363 | pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq, | ||
364 | (int)irq, type); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static struct irq_host_ops mpc52xx_irqhost_ops = { | ||
370 | .match = mpc52xx_irqhost_match, | ||
371 | .xlate = mpc52xx_irqhost_xlate, | ||
372 | .map = mpc52xx_irqhost_map, | ||
373 | }; | ||
374 | |||
375 | /* | ||
376 | * init (public) | ||
377 | */ | ||
378 | |||
379 | void __init mpc52xx_init_irq(void) | ||
380 | { | ||
381 | struct device_node *picnode = NULL; | ||
382 | int picnode_regsize; | ||
383 | u32 picnode_regoffset; | ||
384 | |||
385 | struct device_node *sdmanode = NULL; | ||
386 | int sdmanode_regsize; | ||
387 | u32 sdmanode_regoffset; | ||
388 | |||
389 | u64 size64; | ||
390 | int flags; | ||
391 | |||
392 | u32 intr_ctrl; | ||
393 | |||
394 | picnode = of_find_compatible_node(NULL, "interrupt-controller", | ||
395 | "mpc5200-pic"); | ||
396 | if (picnode == NULL) { | ||
397 | printk(KERN_ERR "MPC52xx PIC: " | ||
398 | "Unable to find the interrupt controller " | ||
399 | "in the OpenFirmware device tree\n"); | ||
400 | goto end; | ||
401 | } | ||
402 | |||
403 | sdmanode = of_find_compatible_node(NULL, "dma-controller", | ||
404 | "mpc5200-bestcomm"); | ||
405 | if (sdmanode == NULL) { | ||
406 | printk(KERN_ERR "MPC52xx PIC" | ||
407 | "Unable to find the Bestcomm DMA controller device " | ||
408 | "in the OpenFirmware device tree\n"); | ||
409 | goto end; | ||
410 | } | ||
411 | |||
412 | /* Retrieve PIC ressources */ | ||
413 | picnode_regoffset = (u32) of_get_address(picnode, 0, &size64, &flags); | ||
414 | if (picnode_regoffset == 0) { | ||
415 | printk(KERN_ERR "MPC52xx PIC" | ||
416 | "Unable to get the interrupt controller address\n"); | ||
417 | goto end; | ||
418 | } | ||
419 | |||
420 | picnode_regoffset = | ||
421 | of_translate_address(picnode, (u32 *) picnode_regoffset); | ||
422 | picnode_regsize = (int)size64; | ||
423 | |||
424 | /* Retrieve SDMA ressources */ | ||
425 | sdmanode_regoffset = (u32) of_get_address(sdmanode, 0, &size64, &flags); | ||
426 | if (sdmanode_regoffset == 0) { | ||
427 | printk(KERN_ERR "MPC52xx PIC: " | ||
428 | "Unable to get the Bestcomm DMA controller address\n"); | ||
429 | goto end; | ||
430 | } | ||
431 | |||
432 | sdmanode_regoffset = | ||
433 | of_translate_address(sdmanode, (u32 *) sdmanode_regoffset); | ||
434 | sdmanode_regsize = (int)size64; | ||
435 | |||
436 | /* Remap the necessary zones */ | ||
437 | intr = ioremap(picnode_regoffset, picnode_regsize); | ||
438 | if (intr == NULL) { | ||
439 | printk(KERN_ERR "MPC52xx PIC: " | ||
440 | "Unable to ioremap interrupt controller registers!\n"); | ||
441 | goto end; | ||
442 | } | ||
443 | |||
444 | sdma = ioremap(sdmanode_regoffset, sdmanode_regsize); | ||
445 | if (sdma == NULL) { | ||
446 | iounmap(intr); | ||
447 | printk(KERN_ERR "MPC52xx PIC: " | ||
448 | "Unable to ioremap Bestcomm DMA registers!\n"); | ||
449 | goto end; | ||
450 | } | ||
451 | |||
452 | printk(KERN_INFO "MPC52xx PIC: MPC52xx PIC Remapped at 0x%8.8x\n", | ||
453 | picnode_regoffset); | ||
454 | printk(KERN_INFO "MPC52xx PIC: MPC52xx SDMA Remapped at 0x%8.8x\n", | ||
455 | sdmanode_regoffset); | ||
456 | |||
457 | /* Disable all interrupt sources. */ | ||
458 | out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ | ||
459 | out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ | ||
460 | out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ | ||
461 | out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ | ||
462 | intr_ctrl = in_be32(&intr->ctrl); | ||
463 | intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ | ||
464 | intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ | ||
465 | 0x00001000 | /* MEE master external enable */ | ||
466 | 0x00000000 | /* 0 means disable IRQ 0-3 */ | ||
467 | 0x00000001; /* CEb route critical normally */ | ||
468 | out_be32(&intr->ctrl, intr_ctrl); | ||
469 | |||
470 | /* Zero a bunch of the priority settings. */ | ||
471 | out_be32(&intr->per_pri1, 0); | ||
472 | out_be32(&intr->per_pri2, 0); | ||
473 | out_be32(&intr->per_pri3, 0); | ||
474 | out_be32(&intr->main_pri1, 0); | ||
475 | out_be32(&intr->main_pri2, 0); | ||
476 | |||
477 | /* | ||
478 | * As last step, add an irq host to translate the real | ||
479 | * hw irq information provided by the ofw to linux virq | ||
480 | */ | ||
481 | |||
482 | mpc52xx_irqhost = | ||
483 | irq_alloc_host(IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, | ||
484 | &mpc52xx_irqhost_ops, -1); | ||
485 | |||
486 | if (mpc52xx_irqhost) { | ||
487 | mpc52xx_irqhost->host_data = picnode; | ||
488 | printk(KERN_INFO "MPC52xx PIC is up and running!\n"); | ||
489 | } else { | ||
490 | printk(KERN_ERR | ||
491 | "MPC52xx PIC: Unable to allocate the IRQ host\n"); | ||
492 | } | ||
493 | |||
494 | end: | ||
495 | of_node_put(picnode); | ||
496 | of_node_put(sdmanode); | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * get_irq (public) | ||
501 | */ | ||
502 | unsigned int mpc52xx_get_irq(void) | ||
503 | { | ||
504 | u32 status; | ||
505 | int irq = NO_IRQ_IGNORE; | ||
506 | |||
507 | status = in_be32(&intr->enc_status); | ||
508 | if (status & 0x00000400) { /* critical */ | ||
509 | irq = (status >> 8) & 0x3; | ||
510 | if (irq == 2) /* high priority peripheral */ | ||
511 | goto peripheral; | ||
512 | irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & | ||
513 | MPC52xx_IRQ_L1_MASK; | ||
514 | } else if (status & 0x00200000) { /* main */ | ||
515 | irq = (status >> 16) & 0x1f; | ||
516 | if (irq == 4) /* low priority peripheral */ | ||
517 | goto peripheral; | ||
518 | irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & | ||
519 | MPC52xx_IRQ_L1_MASK; | ||
520 | } else if (status & 0x20000000) { /* peripheral */ | ||
521 | peripheral: | ||
522 | irq = (status >> 24) & 0x1f; | ||
523 | if (irq == 0) { /* bestcomm */ | ||
524 | status = in_be32(&sdma->IntPend); | ||
525 | irq = ffs(status) - 1; | ||
526 | irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & | ||
527 | MPC52xx_IRQ_L1_MASK; | ||
528 | } else | ||
529 | irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & | ||
530 | MPC52xx_IRQ_L1_MASK; | ||
531 | } | ||
532 | |||
533 | pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, | ||
534 | irq_linear_revmap(mpc52xx_irqhost, irq)); | ||
535 | |||
536 | return irq_linear_revmap(mpc52xx_irqhost, irq); | ||
537 | } | ||
538 | |||
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index e4223226a7a8..e3d71e083f35 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c | |||
@@ -174,8 +174,7 @@ void qe_setbrg(u32 brg, u32 rate) | |||
174 | u32 divisor, tempval; | 174 | u32 divisor, tempval; |
175 | int div16 = 0; | 175 | int div16 = 0; |
176 | 176 | ||
177 | bp = &qe_immr->brg.brgc1; | 177 | bp = &qe_immr->brg.brgc[brg]; |
178 | bp += brg; | ||
179 | 178 | ||
180 | divisor = (get_brg_clk() / rate); | 179 | divisor = (get_brg_clk() / rate); |
181 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { | 180 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { |
diff --git a/arch/powerpc/sysdev/todc.c b/arch/powerpc/sysdev/todc.c deleted file mode 100644 index 0a65980efb50..000000000000 --- a/arch/powerpc/sysdev/todc.c +++ /dev/null | |||
@@ -1,392 +0,0 @@ | |||
1 | /* | ||
2 | * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818 | ||
3 | * Real Time Clocks/Timekeepers. | ||
4 | * | ||
5 | * Author: Mark A. Greer <mgreer@mvista.com> | ||
6 | * | ||
7 | * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
8 | * the terms of the GNU General Public License version 2. This program | ||
9 | * is licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | */ | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/time.h> | ||
16 | #include <linux/timex.h> | ||
17 | #include <linux/bcd.h> | ||
18 | #include <linux/mc146818rtc.h> | ||
19 | |||
20 | #include <asm/machdep.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/todc.h> | ||
24 | |||
25 | /* | ||
26 | * Depending on the hardware on your board and your board design, the | ||
27 | * RTC/NVRAM may be accessed either directly (like normal memory) or via | ||
28 | * address/data registers. If your board uses the direct method, set | ||
29 | * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and | ||
30 | * 'nvram_as1' NULL. If your board uses address/data regs to access nvram, | ||
31 | * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the | ||
32 | * address of the upper byte (leave NULL if using mc146818), and set | ||
33 | * 'nvram_data' to the address of the 8-bit data register. | ||
34 | * | ||
35 | * Note: Even though the documentation for the various RTC chips say that it | ||
36 | * take up to a second before it starts updating once the 'R' bit is | ||
37 | * cleared, they always seem to update even though we bang on it many | ||
38 | * times a second. This is true, except for the Dallas Semi 1746/1747 | ||
39 | * (possibly others). Those chips seem to have a real problem whenever | ||
40 | * we set the 'R' bit before reading them, they basically stop counting. | ||
41 | * --MAG | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * 'todc_info' should be initialized in your *_setup.c file to | ||
46 | * point to a fully initialized 'todc_info_t' structure. | ||
47 | * This structure holds all the register offsets for your particular | ||
48 | * TODC/RTC chip. | ||
49 | * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you. | ||
50 | */ | ||
51 | |||
52 | #ifdef RTC_FREQ_SELECT | ||
53 | #undef RTC_FREQ_SELECT | ||
54 | #define RTC_FREQ_SELECT control_b /* Register A */ | ||
55 | #endif | ||
56 | |||
57 | #ifdef RTC_CONTROL | ||
58 | #undef RTC_CONTROL | ||
59 | #define RTC_CONTROL control_a /* Register B */ | ||
60 | #endif | ||
61 | |||
62 | #ifdef RTC_INTR_FLAGS | ||
63 | #undef RTC_INTR_FLAGS | ||
64 | #define RTC_INTR_FLAGS watchdog /* Register C */ | ||
65 | #endif | ||
66 | |||
67 | #ifdef RTC_VALID | ||
68 | #undef RTC_VALID | ||
69 | #define RTC_VALID interrupts /* Register D */ | ||
70 | #endif | ||
71 | |||
72 | /* Access routines when RTC accessed directly (like normal memory) */ | ||
73 | u_char | ||
74 | todc_direct_read_val(int addr) | ||
75 | { | ||
76 | return readb((void __iomem *)(todc_info->nvram_data + addr)); | ||
77 | } | ||
78 | |||
79 | void | ||
80 | todc_direct_write_val(int addr, unsigned char val) | ||
81 | { | ||
82 | writeb(val, (void __iomem *)(todc_info->nvram_data + addr)); | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | /* Access routines for accessing m48txx type chips via addr/data regs */ | ||
87 | u_char | ||
88 | todc_m48txx_read_val(int addr) | ||
89 | { | ||
90 | outb(addr, todc_info->nvram_as0); | ||
91 | outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); | ||
92 | return inb(todc_info->nvram_data); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | todc_m48txx_write_val(int addr, unsigned char val) | ||
97 | { | ||
98 | outb(addr, todc_info->nvram_as0); | ||
99 | outb(addr>>todc_info->as0_bits, todc_info->nvram_as1); | ||
100 | outb(val, todc_info->nvram_data); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | /* Access routines for accessing mc146818 type chips via addr/data regs */ | ||
105 | u_char | ||
106 | todc_mc146818_read_val(int addr) | ||
107 | { | ||
108 | outb_p(addr, todc_info->nvram_as0); | ||
109 | return inb_p(todc_info->nvram_data); | ||
110 | } | ||
111 | |||
112 | void | ||
113 | todc_mc146818_write_val(int addr, unsigned char val) | ||
114 | { | ||
115 | outb_p(addr, todc_info->nvram_as0); | ||
116 | outb_p(val, todc_info->nvram_data); | ||
117 | } | ||
118 | |||
119 | |||
120 | /* | ||
121 | * Routines to make RTC chips with NVRAM buried behind an addr/data pair | ||
122 | * have the NVRAM and clock regs appear at the same level. | ||
123 | * The NVRAM will appear to start at addr 0 and the clock regs will appear | ||
124 | * to start immediately after the NVRAM (actually, start at offset | ||
125 | * todc_info->nvram_size). | ||
126 | */ | ||
127 | static inline u_char | ||
128 | todc_read_val(int addr) | ||
129 | { | ||
130 | u_char val; | ||
131 | |||
132 | if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) { | ||
133 | if (addr < todc_info->nvram_size) { /* NVRAM */ | ||
134 | ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr); | ||
135 | val = ppc_md.rtc_read_val(todc_info->nvram_data_reg); | ||
136 | } else { /* Clock Reg */ | ||
137 | addr -= todc_info->nvram_size; | ||
138 | val = ppc_md.rtc_read_val(addr); | ||
139 | } | ||
140 | } else | ||
141 | val = ppc_md.rtc_read_val(addr); | ||
142 | |||
143 | return val; | ||
144 | } | ||
145 | |||
146 | static inline void | ||
147 | todc_write_val(int addr, u_char val) | ||
148 | { | ||
149 | if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) { | ||
150 | if (addr < todc_info->nvram_size) { /* NVRAM */ | ||
151 | ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr); | ||
152 | ppc_md.rtc_write_val(todc_info->nvram_data_reg, val); | ||
153 | } else { /* Clock Reg */ | ||
154 | addr -= todc_info->nvram_size; | ||
155 | ppc_md.rtc_write_val(addr, val); | ||
156 | } | ||
157 | } else | ||
158 | ppc_md.rtc_write_val(addr, val); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * TODC routines | ||
163 | * | ||
164 | * There is some ugly stuff in that there are assumptions for the mc146818. | ||
165 | * | ||
166 | * Assumptions: | ||
167 | * - todc_info->control_a has the offset as mc146818 Register B reg | ||
168 | * - todc_info->control_b has the offset as mc146818 Register A reg | ||
169 | * - m48txx control reg's write enable or 'W' bit is same as | ||
170 | * mc146818 Register B 'SET' bit (i.e., 0x80) | ||
171 | * | ||
172 | * These assumptions were made to make the code simpler. | ||
173 | */ | ||
174 | long __init | ||
175 | todc_time_init(void) | ||
176 | { | ||
177 | u_char cntl_b; | ||
178 | |||
179 | if (!ppc_md.rtc_read_val) | ||
180 | ppc_md.rtc_read_val = ppc_md.nvram_read_val; | ||
181 | if (!ppc_md.rtc_write_val) | ||
182 | ppc_md.rtc_write_val = ppc_md.nvram_write_val; | ||
183 | |||
184 | cntl_b = todc_read_val(todc_info->control_b); | ||
185 | |||
186 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
187 | if ((cntl_b & 0x70) != 0x20) { | ||
188 | printk(KERN_INFO "TODC real-time-clock was stopped." | ||
189 | " Now starting..."); | ||
190 | cntl_b &= ~0x70; | ||
191 | cntl_b |= 0x20; | ||
192 | } | ||
193 | |||
194 | todc_write_val(todc_info->control_b, cntl_b); | ||
195 | } else if (todc_info->rtc_type == TODC_TYPE_DS17285) { | ||
196 | u_char mode; | ||
197 | |||
198 | mode = todc_read_val(TODC_TYPE_DS17285_CNTL_A); | ||
199 | /* Make sure countdown clear is not set */ | ||
200 | mode &= ~0x40; | ||
201 | /* Enable oscillator, extended register set */ | ||
202 | mode |= 0x30; | ||
203 | todc_write_val(TODC_TYPE_DS17285_CNTL_A, mode); | ||
204 | |||
205 | } else if (todc_info->rtc_type == TODC_TYPE_DS1501) { | ||
206 | u_char month; | ||
207 | |||
208 | todc_info->enable_read = TODC_DS1501_CNTL_B_TE; | ||
209 | todc_info->enable_write = TODC_DS1501_CNTL_B_TE; | ||
210 | |||
211 | month = todc_read_val(todc_info->month); | ||
212 | |||
213 | if ((month & 0x80) == 0x80) { | ||
214 | printk(KERN_INFO "TODC %s %s\n", | ||
215 | "real-time-clock was stopped.", | ||
216 | "Now starting..."); | ||
217 | month &= ~0x80; | ||
218 | todc_write_val(todc_info->month, month); | ||
219 | } | ||
220 | |||
221 | cntl_b &= ~TODC_DS1501_CNTL_B_TE; | ||
222 | todc_write_val(todc_info->control_b, cntl_b); | ||
223 | } else { /* must be a m48txx type */ | ||
224 | u_char cntl_a; | ||
225 | |||
226 | todc_info->enable_read = TODC_MK48TXX_CNTL_A_R; | ||
227 | todc_info->enable_write = TODC_MK48TXX_CNTL_A_W; | ||
228 | |||
229 | cntl_a = todc_read_val(todc_info->control_a); | ||
230 | |||
231 | /* Check & clear STOP bit in control B register */ | ||
232 | if (cntl_b & TODC_MK48TXX_DAY_CB) { | ||
233 | printk(KERN_INFO "TODC %s %s\n", | ||
234 | "real-time-clock was stopped.", | ||
235 | "Now starting..."); | ||
236 | |||
237 | cntl_a |= todc_info->enable_write; | ||
238 | cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */ | ||
239 | |||
240 | todc_write_val(todc_info->control_a, cntl_a); | ||
241 | todc_write_val(todc_info->control_b, cntl_b); | ||
242 | } | ||
243 | |||
244 | /* Make sure READ & WRITE bits are cleared. */ | ||
245 | cntl_a &= ~(todc_info->enable_write | todc_info->enable_read); | ||
246 | todc_write_val(todc_info->control_a, cntl_a); | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * There is some ugly stuff in that there are assumptions that for a mc146818, | ||
254 | * the todc_info->control_a has the offset of the mc146818 Register B reg and | ||
255 | * that the register'ss 'SET' bit is the same as the m48txx's write enable | ||
256 | * bit in the control register of the m48txx (i.e., 0x80). | ||
257 | * | ||
258 | * It was done to make the code look simpler. | ||
259 | */ | ||
260 | void | ||
261 | todc_get_rtc_time(struct rtc_time *tm) | ||
262 | { | ||
263 | uint year = 0, mon = 0, mday = 0, hour = 0, min = 0, sec = 0; | ||
264 | uint limit, i; | ||
265 | u_char save_control, uip = 0; | ||
266 | extern void GregorianDay(struct rtc_time *); | ||
267 | |||
268 | spin_lock(&rtc_lock); | ||
269 | save_control = todc_read_val(todc_info->control_a); | ||
270 | |||
271 | if (todc_info->rtc_type != TODC_TYPE_MC146818) { | ||
272 | limit = 1; | ||
273 | |||
274 | switch (todc_info->rtc_type) { | ||
275 | case TODC_TYPE_DS1553: | ||
276 | case TODC_TYPE_DS1557: | ||
277 | case TODC_TYPE_DS1743: | ||
278 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
279 | case TODC_TYPE_DS1747: | ||
280 | case TODC_TYPE_DS17285: | ||
281 | break; | ||
282 | default: | ||
283 | todc_write_val(todc_info->control_a, | ||
284 | (save_control | todc_info->enable_read)); | ||
285 | } | ||
286 | } else | ||
287 | limit = 100000000; | ||
288 | |||
289 | for (i=0; i<limit; i++) { | ||
290 | if (todc_info->rtc_type == TODC_TYPE_MC146818) | ||
291 | uip = todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
292 | |||
293 | sec = todc_read_val(todc_info->seconds) & 0x7f; | ||
294 | min = todc_read_val(todc_info->minutes) & 0x7f; | ||
295 | hour = todc_read_val(todc_info->hours) & 0x3f; | ||
296 | mday = todc_read_val(todc_info->day_of_month) & 0x3f; | ||
297 | mon = todc_read_val(todc_info->month) & 0x1f; | ||
298 | year = todc_read_val(todc_info->year) & 0xff; | ||
299 | |||
300 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
301 | uip |= todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
302 | if ((uip & RTC_UIP) == 0) | ||
303 | break; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (todc_info->rtc_type != TODC_TYPE_MC146818) { | ||
308 | switch (todc_info->rtc_type) { | ||
309 | case TODC_TYPE_DS1553: | ||
310 | case TODC_TYPE_DS1557: | ||
311 | case TODC_TYPE_DS1743: | ||
312 | case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */ | ||
313 | case TODC_TYPE_DS1747: | ||
314 | case TODC_TYPE_DS17285: | ||
315 | break; | ||
316 | default: | ||
317 | save_control &= ~(todc_info->enable_read); | ||
318 | todc_write_val(todc_info->control_a, save_control); | ||
319 | } | ||
320 | } | ||
321 | spin_unlock(&rtc_lock); | ||
322 | |||
323 | if ((todc_info->rtc_type != TODC_TYPE_MC146818) | ||
324 | || ((save_control & RTC_DM_BINARY) == 0) | ||
325 | || RTC_ALWAYS_BCD) { | ||
326 | BCD_TO_BIN(sec); | ||
327 | BCD_TO_BIN(min); | ||
328 | BCD_TO_BIN(hour); | ||
329 | BCD_TO_BIN(mday); | ||
330 | BCD_TO_BIN(mon); | ||
331 | BCD_TO_BIN(year); | ||
332 | } | ||
333 | |||
334 | if ((year + 1900) < 1970) { | ||
335 | year += 100; | ||
336 | } | ||
337 | |||
338 | tm->tm_sec = sec; | ||
339 | tm->tm_min = min; | ||
340 | tm->tm_hour = hour; | ||
341 | tm->tm_mday = mday; | ||
342 | tm->tm_mon = mon; | ||
343 | tm->tm_year = year; | ||
344 | |||
345 | GregorianDay(tm); | ||
346 | } | ||
347 | |||
348 | int | ||
349 | todc_set_rtc_time(struct rtc_time *tm) | ||
350 | { | ||
351 | u_char save_control, save_freq_select = 0; | ||
352 | |||
353 | spin_lock(&rtc_lock); | ||
354 | save_control = todc_read_val(todc_info->control_a); | ||
355 | |||
356 | /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */ | ||
357 | todc_write_val(todc_info->control_a, | ||
358 | (save_control | todc_info->enable_write)); | ||
359 | save_control &= ~(todc_info->enable_write); /* in case it was set */ | ||
360 | |||
361 | if (todc_info->rtc_type == TODC_TYPE_MC146818) { | ||
362 | save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT); | ||
363 | todc_write_val(todc_info->RTC_FREQ_SELECT, | ||
364 | save_freq_select | RTC_DIV_RESET2); | ||
365 | } | ||
366 | |||
367 | if ((todc_info->rtc_type != TODC_TYPE_MC146818) | ||
368 | || ((save_control & RTC_DM_BINARY) == 0) | ||
369 | || RTC_ALWAYS_BCD) { | ||
370 | BIN_TO_BCD(tm->tm_sec); | ||
371 | BIN_TO_BCD(tm->tm_min); | ||
372 | BIN_TO_BCD(tm->tm_hour); | ||
373 | BIN_TO_BCD(tm->tm_mon); | ||
374 | BIN_TO_BCD(tm->tm_mday); | ||
375 | BIN_TO_BCD(tm->tm_year); | ||
376 | } | ||
377 | |||
378 | todc_write_val(todc_info->seconds, tm->tm_sec); | ||
379 | todc_write_val(todc_info->minutes, tm->tm_min); | ||
380 | todc_write_val(todc_info->hours, tm->tm_hour); | ||
381 | todc_write_val(todc_info->month, tm->tm_mon); | ||
382 | todc_write_val(todc_info->day_of_month, tm->tm_mday); | ||
383 | todc_write_val(todc_info->year, tm->tm_year); | ||
384 | |||
385 | todc_write_val(todc_info->control_a, save_control); | ||
386 | |||
387 | if (todc_info->rtc_type == TODC_TYPE_MC146818) | ||
388 | todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select); | ||
389 | |||
390 | spin_unlock(&rtc_lock); | ||
391 | return 0; | ||
392 | } | ||
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index f56ffef4defa..0689c0845777 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <asm/sstep.h> | 37 | #include <asm/sstep.h> |
38 | #include <asm/bug.h> | 38 | #include <asm/bug.h> |
39 | #include <asm/irq_regs.h> | 39 | #include <asm/irq_regs.h> |
40 | #include <asm/spu.h> | ||
41 | #include <asm/spu_priv1.h> | ||
40 | 42 | ||
41 | #ifdef CONFIG_PPC64 | 43 | #ifdef CONFIG_PPC64 |
42 | #include <asm/hvcall.h> | 44 | #include <asm/hvcall.h> |
@@ -147,6 +149,8 @@ static void xmon_print_symbol(unsigned long address, const char *mid, | |||
147 | const char *after); | 149 | const char *after); |
148 | static const char *getvecname(unsigned long vec); | 150 | static const char *getvecname(unsigned long vec); |
149 | 151 | ||
152 | static int do_spu_cmd(void); | ||
153 | |||
150 | int xmon_no_auto_backtrace; | 154 | int xmon_no_auto_backtrace; |
151 | 155 | ||
152 | extern int print_insn_powerpc(unsigned long, unsigned long, int); | 156 | extern int print_insn_powerpc(unsigned long, unsigned long, int); |
@@ -209,8 +213,13 @@ Commands:\n\ | |||
209 | mi show information about memory allocation\n\ | 213 | mi show information about memory allocation\n\ |
210 | p call a procedure\n\ | 214 | p call a procedure\n\ |
211 | r print registers\n\ | 215 | r print registers\n\ |
212 | s single step\n\ | 216 | s single step\n" |
213 | S print special registers\n\ | 217 | #ifdef CONFIG_PPC_CELL |
218 | " ss stop execution on all spus\n\ | ||
219 | sr restore execution on stopped spus\n\ | ||
220 | sf # dump spu fields for spu # (in hex)\n" | ||
221 | #endif | ||
222 | " S print special registers\n\ | ||
214 | t print backtrace\n\ | 223 | t print backtrace\n\ |
215 | x exit monitor and recover\n\ | 224 | x exit monitor and recover\n\ |
216 | X exit monitor and dont recover\n" | 225 | X exit monitor and dont recover\n" |
@@ -518,6 +527,7 @@ int xmon(struct pt_regs *excp) | |||
518 | xmon_save_regs(®s); | 527 | xmon_save_regs(®s); |
519 | excp = ®s; | 528 | excp = ®s; |
520 | } | 529 | } |
530 | |||
521 | return xmon_core(excp, 0); | 531 | return xmon_core(excp, 0); |
522 | } | 532 | } |
523 | EXPORT_SYMBOL(xmon); | 533 | EXPORT_SYMBOL(xmon); |
@@ -809,6 +819,8 @@ cmds(struct pt_regs *excp) | |||
809 | cacheflush(); | 819 | cacheflush(); |
810 | break; | 820 | break; |
811 | case 's': | 821 | case 's': |
822 | if (do_spu_cmd() == 0) | ||
823 | break; | ||
812 | if (do_step(excp)) | 824 | if (do_step(excp)) |
813 | return cmd; | 825 | return cmd; |
814 | break; | 826 | break; |
@@ -2630,3 +2642,194 @@ void __init xmon_setup(void) | |||
2630 | if (xmon_early) | 2642 | if (xmon_early) |
2631 | debugger(NULL); | 2643 | debugger(NULL); |
2632 | } | 2644 | } |
2645 | |||
2646 | #ifdef CONFIG_PPC_CELL | ||
2647 | |||
2648 | struct spu_info { | ||
2649 | struct spu *spu; | ||
2650 | u64 saved_mfc_sr1_RW; | ||
2651 | u32 saved_spu_runcntl_RW; | ||
2652 | u8 stopped_ok; | ||
2653 | }; | ||
2654 | |||
2655 | #define XMON_NUM_SPUS 16 /* Enough for current hardware */ | ||
2656 | |||
2657 | static struct spu_info spu_info[XMON_NUM_SPUS]; | ||
2658 | |||
2659 | void xmon_register_spus(struct list_head *list) | ||
2660 | { | ||
2661 | struct spu *spu; | ||
2662 | |||
2663 | list_for_each_entry(spu, list, full_list) { | ||
2664 | if (spu->number >= XMON_NUM_SPUS) { | ||
2665 | WARN_ON(1); | ||
2666 | continue; | ||
2667 | } | ||
2668 | |||
2669 | spu_info[spu->number].spu = spu; | ||
2670 | spu_info[spu->number].stopped_ok = 0; | ||
2671 | } | ||
2672 | } | ||
2673 | |||
2674 | static void stop_spus(void) | ||
2675 | { | ||
2676 | struct spu *spu; | ||
2677 | int i; | ||
2678 | u64 tmp; | ||
2679 | |||
2680 | for (i = 0; i < XMON_NUM_SPUS; i++) { | ||
2681 | if (!spu_info[i].spu) | ||
2682 | continue; | ||
2683 | |||
2684 | if (setjmp(bus_error_jmp) == 0) { | ||
2685 | catch_memory_errors = 1; | ||
2686 | sync(); | ||
2687 | |||
2688 | spu = spu_info[i].spu; | ||
2689 | |||
2690 | spu_info[i].saved_spu_runcntl_RW = | ||
2691 | in_be32(&spu->problem->spu_runcntl_RW); | ||
2692 | |||
2693 | tmp = spu_mfc_sr1_get(spu); | ||
2694 | spu_info[i].saved_mfc_sr1_RW = tmp; | ||
2695 | |||
2696 | tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK; | ||
2697 | spu_mfc_sr1_set(spu, tmp); | ||
2698 | |||
2699 | sync(); | ||
2700 | __delay(200); | ||
2701 | |||
2702 | spu_info[i].stopped_ok = 1; | ||
2703 | printf("Stopped spu %.2d\n", i); | ||
2704 | } else { | ||
2705 | catch_memory_errors = 0; | ||
2706 | printf("*** Error stopping spu %.2d\n", i); | ||
2707 | } | ||
2708 | catch_memory_errors = 0; | ||
2709 | } | ||
2710 | } | ||
2711 | |||
2712 | static void restart_spus(void) | ||
2713 | { | ||
2714 | struct spu *spu; | ||
2715 | int i; | ||
2716 | |||
2717 | for (i = 0; i < XMON_NUM_SPUS; i++) { | ||
2718 | if (!spu_info[i].spu) | ||
2719 | continue; | ||
2720 | |||
2721 | if (!spu_info[i].stopped_ok) { | ||
2722 | printf("*** Error, spu %d was not successfully stopped" | ||
2723 | ", not restarting\n", i); | ||
2724 | continue; | ||
2725 | } | ||
2726 | |||
2727 | if (setjmp(bus_error_jmp) == 0) { | ||
2728 | catch_memory_errors = 1; | ||
2729 | sync(); | ||
2730 | |||
2731 | spu = spu_info[i].spu; | ||
2732 | spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW); | ||
2733 | out_be32(&spu->problem->spu_runcntl_RW, | ||
2734 | spu_info[i].saved_spu_runcntl_RW); | ||
2735 | |||
2736 | sync(); | ||
2737 | __delay(200); | ||
2738 | |||
2739 | printf("Restarted spu %.2d\n", i); | ||
2740 | } else { | ||
2741 | catch_memory_errors = 0; | ||
2742 | printf("*** Error restarting spu %.2d\n", i); | ||
2743 | } | ||
2744 | catch_memory_errors = 0; | ||
2745 | } | ||
2746 | } | ||
2747 | |||
2748 | #define DUMP_WIDTH 23 | ||
2749 | #define DUMP_FIELD(obj, format, field) \ | ||
2750 | do { \ | ||
2751 | if (setjmp(bus_error_jmp) == 0) { \ | ||
2752 | catch_memory_errors = 1; \ | ||
2753 | sync(); \ | ||
2754 | printf(" %-*s = "format"\n", DUMP_WIDTH, \ | ||
2755 | #field, obj->field); \ | ||
2756 | sync(); \ | ||
2757 | __delay(200); \ | ||
2758 | } else { \ | ||
2759 | catch_memory_errors = 0; \ | ||
2760 | printf(" %-*s = *** Error reading field.\n", \ | ||
2761 | DUMP_WIDTH, #field); \ | ||
2762 | } \ | ||
2763 | catch_memory_errors = 0; \ | ||
2764 | } while (0) | ||
2765 | |||
2766 | static void dump_spu_fields(struct spu *spu) | ||
2767 | { | ||
2768 | printf("Dumping spu fields at address %p:\n", spu); | ||
2769 | |||
2770 | DUMP_FIELD(spu, "0x%x", number); | ||
2771 | DUMP_FIELD(spu, "%s", name); | ||
2772 | DUMP_FIELD(spu, "%s", devnode->full_name); | ||
2773 | DUMP_FIELD(spu, "0x%x", nid); | ||
2774 | DUMP_FIELD(spu, "0x%lx", local_store_phys); | ||
2775 | DUMP_FIELD(spu, "0x%p", local_store); | ||
2776 | DUMP_FIELD(spu, "0x%lx", ls_size); | ||
2777 | DUMP_FIELD(spu, "0x%x", node); | ||
2778 | DUMP_FIELD(spu, "0x%lx", flags); | ||
2779 | DUMP_FIELD(spu, "0x%lx", dar); | ||
2780 | DUMP_FIELD(spu, "0x%lx", dsisr); | ||
2781 | DUMP_FIELD(spu, "%d", class_0_pending); | ||
2782 | DUMP_FIELD(spu, "0x%lx", irqs[0]); | ||
2783 | DUMP_FIELD(spu, "0x%lx", irqs[1]); | ||
2784 | DUMP_FIELD(spu, "0x%lx", irqs[2]); | ||
2785 | DUMP_FIELD(spu, "0x%x", slb_replace); | ||
2786 | DUMP_FIELD(spu, "%d", pid); | ||
2787 | DUMP_FIELD(spu, "%d", prio); | ||
2788 | DUMP_FIELD(spu, "0x%p", mm); | ||
2789 | DUMP_FIELD(spu, "0x%p", ctx); | ||
2790 | DUMP_FIELD(spu, "0x%p", rq); | ||
2791 | DUMP_FIELD(spu, "0x%p", timestamp); | ||
2792 | DUMP_FIELD(spu, "0x%lx", problem_phys); | ||
2793 | DUMP_FIELD(spu, "0x%p", problem); | ||
2794 | DUMP_FIELD(spu, "0x%x", problem->spu_runcntl_RW); | ||
2795 | DUMP_FIELD(spu, "0x%x", problem->spu_status_R); | ||
2796 | DUMP_FIELD(spu, "0x%x", problem->spu_npc_RW); | ||
2797 | DUMP_FIELD(spu, "0x%p", priv1); | ||
2798 | |||
2799 | if (spu->priv1) | ||
2800 | DUMP_FIELD(spu, "0x%lx", priv1->mfc_sr1_RW); | ||
2801 | |||
2802 | DUMP_FIELD(spu, "0x%p", priv2); | ||
2803 | } | ||
2804 | |||
2805 | static int do_spu_cmd(void) | ||
2806 | { | ||
2807 | unsigned long num = 0; | ||
2808 | int cmd; | ||
2809 | |||
2810 | cmd = inchar(); | ||
2811 | switch (cmd) { | ||
2812 | case 's': | ||
2813 | stop_spus(); | ||
2814 | break; | ||
2815 | case 'r': | ||
2816 | restart_spus(); | ||
2817 | break; | ||
2818 | case 'f': | ||
2819 | if (scanhex(&num) && num < XMON_NUM_SPUS && spu_info[num].spu) | ||
2820 | dump_spu_fields(spu_info[num].spu); | ||
2821 | else | ||
2822 | printf("*** Error: invalid spu number\n"); | ||
2823 | break; | ||
2824 | default: | ||
2825 | return -1; | ||
2826 | } | ||
2827 | |||
2828 | return 0; | ||
2829 | } | ||
2830 | #else /* ! CONFIG_PPC_CELL */ | ||
2831 | static int do_spu_cmd(void) | ||
2832 | { | ||
2833 | return -1; | ||
2834 | } | ||
2835 | #endif | ||
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index 3397f0de1592..b84f8df325c4 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c | |||
@@ -121,8 +121,8 @@ mpc834x_sys_setup_arch(void) | |||
121 | 121 | ||
122 | mdata->irq[0] = MPC83xx_IRQ_EXT1; | 122 | mdata->irq[0] = MPC83xx_IRQ_EXT1; |
123 | mdata->irq[1] = MPC83xx_IRQ_EXT2; | 123 | mdata->irq[1] = MPC83xx_IRQ_EXT2; |
124 | mdata->irq[2] = -1; | 124 | mdata->irq[2] = PHY_POLL; |
125 | mdata->irq[31] = -1; | 125 | mdata->irq[31] = PHY_POLL; |
126 | 126 | ||
127 | /* setup the board related information for the enet controllers */ | 127 | /* setup the board related information for the enet controllers */ |
128 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); | 128 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index 4f839da6782f..00a3ba57063f 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c | |||
@@ -92,9 +92,9 @@ mpc8540ads_setup_arch(void) | |||
92 | 92 | ||
93 | mdata->irq[0] = MPC85xx_IRQ_EXT5; | 93 | mdata->irq[0] = MPC85xx_IRQ_EXT5; |
94 | mdata->irq[1] = MPC85xx_IRQ_EXT5; | 94 | mdata->irq[1] = MPC85xx_IRQ_EXT5; |
95 | mdata->irq[2] = -1; | 95 | mdata->irq[2] = PHY_POLL; |
96 | mdata->irq[3] = MPC85xx_IRQ_EXT5; | 96 | mdata->irq[3] = MPC85xx_IRQ_EXT5; |
97 | mdata->irq[31] = -1; | 97 | mdata->irq[31] = PHY_POLL; |
98 | 98 | ||
99 | /* setup the board related information for the enet controllers */ | 99 | /* setup the board related information for the enet controllers */ |
100 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 100 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c index 14ecec7bbed7..3a060468dd95 100644 --- a/arch/ppc/platforms/85xx/mpc8560_ads.c +++ b/arch/ppc/platforms/85xx/mpc8560_ads.c | |||
@@ -156,9 +156,9 @@ mpc8560ads_setup_arch(void) | |||
156 | 156 | ||
157 | mdata->irq[0] = MPC85xx_IRQ_EXT5; | 157 | mdata->irq[0] = MPC85xx_IRQ_EXT5; |
158 | mdata->irq[1] = MPC85xx_IRQ_EXT5; | 158 | mdata->irq[1] = MPC85xx_IRQ_EXT5; |
159 | mdata->irq[2] = -1; | 159 | mdata->irq[2] = PHY_POLL; |
160 | mdata->irq[3] = MPC85xx_IRQ_EXT5; | 160 | mdata->irq[3] = MPC85xx_IRQ_EXT5; |
161 | mdata->irq[31] = -1; | 161 | mdata->irq[31] = PHY_POLL; |
162 | 162 | ||
163 | /* setup the board related information for the enet controllers */ | 163 | /* setup the board related information for the enet controllers */ |
164 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 164 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 5ce0f69c1db6..2d59eb776c95 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c | |||
@@ -451,9 +451,9 @@ mpc85xx_cds_setup_arch(void) | |||
451 | 451 | ||
452 | mdata->irq[0] = MPC85xx_IRQ_EXT5; | 452 | mdata->irq[0] = MPC85xx_IRQ_EXT5; |
453 | mdata->irq[1] = MPC85xx_IRQ_EXT5; | 453 | mdata->irq[1] = MPC85xx_IRQ_EXT5; |
454 | mdata->irq[2] = -1; | 454 | mdata->irq[2] = PHY_POLL; |
455 | mdata->irq[3] = -1; | 455 | mdata->irq[3] = PHY_POLL; |
456 | mdata->irq[31] = -1; | 456 | mdata->irq[31] = PHY_POLL; |
457 | 457 | ||
458 | /* setup the board related information for the enet controllers */ | 458 | /* setup the board related information for the enet controllers */ |
459 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 459 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 764d580ff535..1d10ab98f66d 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c | |||
@@ -129,7 +129,7 @@ sbc8560_setup_arch(void) | |||
129 | 129 | ||
130 | mdata->irq[25] = MPC85xx_IRQ_EXT6; | 130 | mdata->irq[25] = MPC85xx_IRQ_EXT6; |
131 | mdata->irq[26] = MPC85xx_IRQ_EXT7; | 131 | mdata->irq[26] = MPC85xx_IRQ_EXT7; |
132 | mdata->irq[31] = -1; | 132 | mdata->irq[31] = PHY_POLL; |
133 | 133 | ||
134 | /* setup the board related information for the enet controllers */ | 134 | /* setup the board related information for the enet controllers */ |
135 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 135 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 4bb18ab27672..b1f5b737c70d 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c | |||
@@ -123,7 +123,7 @@ gp3_setup_arch(void) | |||
123 | 123 | ||
124 | mdata->irq[2] = MPC85xx_IRQ_EXT5; | 124 | mdata->irq[2] = MPC85xx_IRQ_EXT5; |
125 | mdata->irq[4] = MPC85xx_IRQ_EXT5; | 125 | mdata->irq[4] = MPC85xx_IRQ_EXT5; |
126 | mdata->irq[31] = -1; | 126 | mdata->irq[31] = PHY_POLL; |
127 | 127 | ||
128 | /* setup the board related information for the enet controllers */ | 128 | /* setup the board related information for the enet controllers */ |
129 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 129 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c index dd45f2e18449..4ee2bd156dc5 100644 --- a/arch/ppc/platforms/85xx/tqm85xx.c +++ b/arch/ppc/platforms/85xx/tqm85xx.c | |||
@@ -137,9 +137,9 @@ tqm85xx_setup_arch(void) | |||
137 | 137 | ||
138 | mdata->irq[0] = MPC85xx_IRQ_EXT8; | 138 | mdata->irq[0] = MPC85xx_IRQ_EXT8; |
139 | mdata->irq[1] = MPC85xx_IRQ_EXT8; | 139 | mdata->irq[1] = MPC85xx_IRQ_EXT8; |
140 | mdata->irq[2] = -1; | 140 | mdata->irq[2] = PHY_POLL; |
141 | mdata->irq[3] = MPC85xx_IRQ_EXT8; | 141 | mdata->irq[3] = MPC85xx_IRQ_EXT8; |
142 | mdata->irq[31] = -1; | 142 | mdata->irq[31] = PHY_POLL; |
143 | 143 | ||
144 | /* setup the board related information for the enet controllers */ | 144 | /* setup the board related information for the enet controllers */ |
145 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); | 145 | pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1); |
diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c index 1f9ea36837b1..0bc06768cf24 100644 --- a/arch/ppc/platforms/mpc8272ads_setup.c +++ b/arch/ppc/platforms/mpc8272ads_setup.c | |||
@@ -266,10 +266,10 @@ static void __init mpc8272ads_fixup_mdio_pdata(struct platform_device *pdev, | |||
266 | int idx) | 266 | int idx) |
267 | { | 267 | { |
268 | m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT; | 268 | m82xx_mii_bb_pdata.irq[0] = PHY_INTERRUPT; |
269 | m82xx_mii_bb_pdata.irq[1] = -1; | 269 | m82xx_mii_bb_pdata.irq[1] = PHY_POLL; |
270 | m82xx_mii_bb_pdata.irq[2] = -1; | 270 | m82xx_mii_bb_pdata.irq[2] = PHY_POLL; |
271 | m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT; | 271 | m82xx_mii_bb_pdata.irq[3] = PHY_INTERRUPT; |
272 | m82xx_mii_bb_pdata.irq[31] = -1; | 272 | m82xx_mii_bb_pdata.irq[31] = PHY_POLL; |
273 | 273 | ||
274 | 274 | ||
275 | m82xx_mii_bb_pdata.mdio_dat.offset = | 275 | m82xx_mii_bb_pdata.mdio_dat.offset = |
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c index e95d2c111747..8a0c07eb4449 100644 --- a/arch/ppc/platforms/mpc866ads_setup.c +++ b/arch/ppc/platforms/mpc866ads_setup.c | |||
@@ -361,7 +361,7 @@ int __init mpc866ads_init(void) | |||
361 | 361 | ||
362 | fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; | 362 | fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; |
363 | /* No PHY interrupt line here */ | 363 | /* No PHY interrupt line here */ |
364 | fmpi->irq[0xf] = -1; | 364 | fmpi->irq[0xf] = PHY_POLL; |
365 | 365 | ||
366 | /* Since either of the uarts could be used as console, they need to ready */ | 366 | /* Since either of the uarts could be used as console, they need to ready */ |
367 | #ifdef CONFIG_SERIAL_CPM_SMC1 | 367 | #ifdef CONFIG_SERIAL_CPM_SMC1 |
@@ -380,7 +380,7 @@ int __init mpc866ads_init(void) | |||
380 | 380 | ||
381 | fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; | 381 | fmpi->mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) & 0x3F) << 1; |
382 | /* No PHY interrupt line here */ | 382 | /* No PHY interrupt line here */ |
383 | fmpi->irq[0xf] = -1; | 383 | fmpi->irq[0xf] = PHY_POLL; |
384 | 384 | ||
385 | return 0; | 385 | return 0; |
386 | } | 386 | } |
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index 2af634d7acf4..eb7ab112c050 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include <linux/ide.h> | 35 | #include <linux/ide.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | 37 | ||
38 | #ifdef CONFIG_PPC_MULTIPLATFORM | 38 | #ifdef CONFIG_PPC_CHRP |
39 | #include <asm/processor.h> | 39 | #include <asm/processor.h> |
40 | #endif | 40 | #endif |
41 | 41 | ||
@@ -442,7 +442,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) | |||
442 | hwif->speedproc = &via_set_drive; | 442 | hwif->speedproc = &via_set_drive; |
443 | 443 | ||
444 | 444 | ||
445 | #if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32) | 445 | #ifdef CONFIG_PPC_CHRP |
446 | if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) { | 446 | if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) { |
447 | hwif->irq = hwif->channel ? 15 : 14; | 447 | hwif->irq = hwif->channel ? 15 : 14; |
448 | } | 448 | } |
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index f14e99276dba..096d4a100bf2 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c | |||
@@ -254,7 +254,7 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) | |||
254 | goto device_create_fail; | 254 | goto device_create_fail; |
255 | } | 255 | } |
256 | 256 | ||
257 | phydev->irq = -1; | 257 | phydev->irq = PHY_IGNORE_INTERRUPT; |
258 | phydev->dev.bus = &mdio_bus_type; | 258 | phydev->dev.bus = &mdio_bus_type; |
259 | 259 | ||
260 | if(number) | 260 | if(number) |
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 3f4b6408b755..4b3cd3d8b62a 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c | |||
@@ -473,9 +473,9 @@ | |||
473 | #include <asm/byteorder.h> | 473 | #include <asm/byteorder.h> |
474 | #include <asm/unaligned.h> | 474 | #include <asm/unaligned.h> |
475 | #include <asm/uaccess.h> | 475 | #include <asm/uaccess.h> |
476 | #ifdef CONFIG_PPC_MULTIPLATFORM | 476 | #ifdef CONFIG_PPC_PMAC |
477 | #include <asm/machdep.h> | 477 | #include <asm/machdep.h> |
478 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 478 | #endif /* CONFIG_PPC_PMAC */ |
479 | 479 | ||
480 | #include "de4x5.h" | 480 | #include "de4x5.h" |
481 | 481 | ||
@@ -4151,7 +4151,7 @@ get_hw_addr(struct net_device *dev) | |||
4151 | /* If possible, try to fix a broken card - SMC only so far */ | 4151 | /* If possible, try to fix a broken card - SMC only so far */ |
4152 | srom_repair(dev, broken); | 4152 | srom_repair(dev, broken); |
4153 | 4153 | ||
4154 | #ifdef CONFIG_PPC_MULTIPLATFORM | 4154 | #ifdef CONFIG_PPC_PMAC |
4155 | /* | 4155 | /* |
4156 | ** If the address starts with 00 a0, we have to bit-reverse | 4156 | ** If the address starts with 00 a0, we have to bit-reverse |
4157 | ** each byte of the address. | 4157 | ** each byte of the address. |
@@ -4168,7 +4168,7 @@ get_hw_addr(struct net_device *dev) | |||
4168 | dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1); | 4168 | dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1); |
4169 | } | 4169 | } |
4170 | } | 4170 | } |
4171 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 4171 | #endif /* CONFIG_PPC_PMAC */ |
4172 | 4172 | ||
4173 | /* Test for a bad enet address */ | 4173 | /* Test for a bad enet address */ |
4174 | status = test_bad_enet(dev, status); | 4174 | status = test_bad_enet(dev, status); |
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h index d40359204aba..c4a1ab608f6f 100644 --- a/include/asm-powerpc/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h | |||
@@ -7,16 +7,30 @@ | |||
7 | #ifdef __KERNEL__ | 7 | #ifdef __KERNEL__ |
8 | 8 | ||
9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
10 | #include <linux/compiler.h> | ||
10 | #include <asm/ptrace.h> | 11 | #include <asm/ptrace.h> |
11 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
12 | 13 | ||
13 | extern void timer_interrupt(struct pt_regs *); | 14 | extern void timer_interrupt(struct pt_regs *); |
14 | 15 | ||
15 | #ifdef CONFIG_PPC_ISERIES | 16 | #ifdef CONFIG_PPC64 |
17 | #include <asm/paca.h> | ||
18 | |||
19 | static inline unsigned long local_get_flags(void) | ||
20 | { | ||
21 | return get_paca()->soft_enabled; | ||
22 | } | ||
23 | |||
24 | static inline unsigned long local_irq_disable(void) | ||
25 | { | ||
26 | unsigned long flag = get_paca()->soft_enabled; | ||
27 | get_paca()->soft_enabled = 0; | ||
28 | barrier(); | ||
29 | return flag; | ||
30 | } | ||
16 | 31 | ||
17 | extern unsigned long local_get_flags(void); | ||
18 | extern unsigned long local_irq_disable(void); | ||
19 | extern void local_irq_restore(unsigned long); | 32 | extern void local_irq_restore(unsigned long); |
33 | extern void iseries_handle_interrupts(void); | ||
20 | 34 | ||
21 | #define local_irq_enable() local_irq_restore(1) | 35 | #define local_irq_enable() local_irq_restore(1) |
22 | #define local_save_flags(flags) ((flags) = local_get_flags()) | 36 | #define local_save_flags(flags) ((flags) = local_get_flags()) |
@@ -24,17 +38,14 @@ extern void local_irq_restore(unsigned long); | |||
24 | 38 | ||
25 | #define irqs_disabled() (local_get_flags() == 0) | 39 | #define irqs_disabled() (local_get_flags() == 0) |
26 | 40 | ||
41 | #define hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) | ||
42 | #define hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) | ||
43 | |||
27 | #else | 44 | #else |
28 | 45 | ||
29 | #if defined(CONFIG_BOOKE) | 46 | #if defined(CONFIG_BOOKE) |
30 | #define SET_MSR_EE(x) mtmsr(x) | 47 | #define SET_MSR_EE(x) mtmsr(x) |
31 | #define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") | 48 | #define local_irq_restore(flags) __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory") |
32 | #elif defined(__powerpc64__) | ||
33 | #define SET_MSR_EE(x) __mtmsrd(x, 1) | ||
34 | #define local_irq_restore(flags) do { \ | ||
35 | __asm__ __volatile__("": : :"memory"); \ | ||
36 | __mtmsrd((flags), 1); \ | ||
37 | } while(0) | ||
38 | #else | 49 | #else |
39 | #define SET_MSR_EE(x) mtmsr(x) | 50 | #define SET_MSR_EE(x) mtmsr(x) |
40 | #define local_irq_restore(flags) mtmsr(flags) | 51 | #define local_irq_restore(flags) mtmsr(flags) |
@@ -81,7 +92,7 @@ static inline void local_irq_save_ptr(unsigned long *flags) | |||
81 | #define local_irq_save(flags) local_irq_save_ptr(&flags) | 92 | #define local_irq_save(flags) local_irq_save_ptr(&flags) |
82 | #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) | 93 | #define irqs_disabled() ((mfmsr() & MSR_EE) == 0) |
83 | 94 | ||
84 | #endif /* CONFIG_PPC_ISERIES */ | 95 | #endif /* CONFIG_PPC64 */ |
85 | 96 | ||
86 | #define mask_irq(irq) \ | 97 | #define mask_irq(irq) \ |
87 | ({ \ | 98 | ({ \ |
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h index ce12f85fff9b..9fdd0491f6a3 100644 --- a/include/asm-powerpc/immap_qe.h +++ b/include/asm-powerpc/immap_qe.h | |||
@@ -136,22 +136,7 @@ struct qe_timers { | |||
136 | 136 | ||
137 | /* BRG */ | 137 | /* BRG */ |
138 | struct qe_brg { | 138 | struct qe_brg { |
139 | __be32 brgc1; /* BRG1 configuration register */ | 139 | __be32 brgc[16]; /* BRG configuration registers */ |
140 | __be32 brgc2; /* BRG2 configuration register */ | ||
141 | __be32 brgc3; /* BRG3 configuration register */ | ||
142 | __be32 brgc4; /* BRG4 configuration register */ | ||
143 | __be32 brgc5; /* BRG5 configuration register */ | ||
144 | __be32 brgc6; /* BRG6 configuration register */ | ||
145 | __be32 brgc7; /* BRG7 configuration register */ | ||
146 | __be32 brgc8; /* BRG8 configuration register */ | ||
147 | __be32 brgc9; /* BRG9 configuration register */ | ||
148 | __be32 brgc10; /* BRG10 configuration register */ | ||
149 | __be32 brgc11; /* BRG11 configuration register */ | ||
150 | __be32 brgc12; /* BRG12 configuration register */ | ||
151 | __be32 brgc13; /* BRG13 configuration register */ | ||
152 | __be32 brgc14; /* BRG14 configuration register */ | ||
153 | __be32 brgc15; /* BRG15 configuration register */ | ||
154 | __be32 brgc16; /* BRG16 configuration register */ | ||
155 | u8 res0[0x40]; | 140 | u8 res0[0x40]; |
156 | } __attribute__ ((packed)); | 141 | } __attribute__ ((packed)); |
157 | 142 | ||
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h index 39fad685ffab..19e6f7e0a607 100644 --- a/include/asm-powerpc/iommu.h +++ b/include/asm-powerpc/iommu.h | |||
@@ -70,17 +70,9 @@ struct iommu_table { | |||
70 | struct scatterlist; | 70 | struct scatterlist; |
71 | struct device_node; | 71 | struct device_node; |
72 | 72 | ||
73 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
74 | |||
75 | /* Walks all buses and creates iommu tables */ | ||
76 | extern void iommu_setup_pSeries(void); | ||
77 | extern void iommu_setup_dart(void); | ||
78 | |||
79 | /* Frees table for an individual device node */ | 73 | /* Frees table for an individual device node */ |
80 | extern void iommu_free_table(struct device_node *dn); | 74 | extern void iommu_free_table(struct device_node *dn); |
81 | 75 | ||
82 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
83 | |||
84 | /* Initializes an iommu_table based in values set in the passed-in | 76 | /* Initializes an iommu_table based in values set in the passed-in |
85 | * structure | 77 | * structure |
86 | */ | 78 | */ |
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h index c3fc7a28e3cd..41c8c9c5a254 100644 --- a/include/asm-powerpc/mmu.h +++ b/include/asm-powerpc/mmu.h | |||
@@ -248,21 +248,6 @@ extern void hpte_init_native(void); | |||
248 | extern void hpte_init_lpar(void); | 248 | extern void hpte_init_lpar(void); |
249 | extern void hpte_init_iSeries(void); | 249 | extern void hpte_init_iSeries(void); |
250 | 250 | ||
251 | extern long pSeries_lpar_hpte_insert(unsigned long hpte_group, | ||
252 | unsigned long va, unsigned long prpn, | ||
253 | unsigned long rflags, | ||
254 | unsigned long vflags, int psize); | ||
255 | |||
256 | extern long native_hpte_insert(unsigned long hpte_group, | ||
257 | unsigned long va, unsigned long prpn, | ||
258 | unsigned long rflags, | ||
259 | unsigned long vflags, int psize); | ||
260 | |||
261 | extern long iSeries_hpte_insert(unsigned long hpte_group, | ||
262 | unsigned long va, unsigned long prpn, | ||
263 | unsigned long rflags, | ||
264 | unsigned long vflags, int psize); | ||
265 | |||
266 | extern void stabs_alloc(void); | 251 | extern void stabs_alloc(void); |
267 | extern void slb_initialize(void); | 252 | extern void slb_initialize(void); |
268 | extern void slb_flush_and_rebolt(void); | 253 | extern void slb_flush_and_rebolt(void); |
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h new file mode 100644 index 000000000000..e9aa622f19f6 --- /dev/null +++ b/include/asm-powerpc/mpc52xx.h | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips | ||
3 | * May need to be cleaned as the port goes on ... | ||
4 | * | ||
5 | * Copyright (C) 2004-2005 Sylvain Munaut <tnt@246tNt.com> | ||
6 | * Copyright (C) 2003 MontaVista, Software, Inc. | ||
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 | #ifndef __ASM_POWERPC_MPC52xx_H__ | ||
14 | #define __ASM_POWERPC_MPC52xx_H__ | ||
15 | |||
16 | #ifndef __ASSEMBLY__ | ||
17 | #include <asm/types.h> | ||
18 | #include <asm/prom.h> | ||
19 | #endif /* __ASSEMBLY__ */ | ||
20 | |||
21 | |||
22 | /* ======================================================================== */ | ||
23 | /* HW IRQ mapping */ | ||
24 | /* ======================================================================== */ | ||
25 | |||
26 | #define MPC52xx_IRQ_L1_CRIT (0) | ||
27 | #define MPC52xx_IRQ_L1_MAIN (1) | ||
28 | #define MPC52xx_IRQ_L1_PERP (2) | ||
29 | #define MPC52xx_IRQ_L1_SDMA (3) | ||
30 | |||
31 | #define MPC52xx_IRQ_L1_OFFSET (6) | ||
32 | #define MPC52xx_IRQ_L1_MASK (0xc0) | ||
33 | |||
34 | #define MPC52xx_IRQ_L2_OFFSET (0) | ||
35 | #define MPC52xx_IRQ_L2_MASK (0x3f) | ||
36 | |||
37 | #define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0) | ||
38 | |||
39 | |||
40 | /* ======================================================================== */ | ||
41 | /* Structures mapping of some unit register set */ | ||
42 | /* ======================================================================== */ | ||
43 | |||
44 | #ifndef __ASSEMBLY__ | ||
45 | |||
46 | /* Interrupt controller Register set */ | ||
47 | struct mpc52xx_intr { | ||
48 | u32 per_mask; /* INTR + 0x00 */ | ||
49 | u32 per_pri1; /* INTR + 0x04 */ | ||
50 | u32 per_pri2; /* INTR + 0x08 */ | ||
51 | u32 per_pri3; /* INTR + 0x0c */ | ||
52 | u32 ctrl; /* INTR + 0x10 */ | ||
53 | u32 main_mask; /* INTR + 0x14 */ | ||
54 | u32 main_pri1; /* INTR + 0x18 */ | ||
55 | u32 main_pri2; /* INTR + 0x1c */ | ||
56 | u32 reserved1; /* INTR + 0x20 */ | ||
57 | u32 enc_status; /* INTR + 0x24 */ | ||
58 | u32 crit_status; /* INTR + 0x28 */ | ||
59 | u32 main_status; /* INTR + 0x2c */ | ||
60 | u32 per_status; /* INTR + 0x30 */ | ||
61 | u32 reserved2; /* INTR + 0x34 */ | ||
62 | u32 per_error; /* INTR + 0x38 */ | ||
63 | }; | ||
64 | |||
65 | /* Memory Mapping Control */ | ||
66 | struct mpc52xx_mmap_ctl { | ||
67 | u32 mbar; /* MMAP_CTRL + 0x00 */ | ||
68 | |||
69 | u32 cs0_start; /* MMAP_CTRL + 0x04 */ | ||
70 | u32 cs0_stop; /* MMAP_CTRL + 0x08 */ | ||
71 | u32 cs1_start; /* MMAP_CTRL + 0x0c */ | ||
72 | u32 cs1_stop; /* MMAP_CTRL + 0x10 */ | ||
73 | u32 cs2_start; /* MMAP_CTRL + 0x14 */ | ||
74 | u32 cs2_stop; /* MMAP_CTRL + 0x18 */ | ||
75 | u32 cs3_start; /* MMAP_CTRL + 0x1c */ | ||
76 | u32 cs3_stop; /* MMAP_CTRL + 0x20 */ | ||
77 | u32 cs4_start; /* MMAP_CTRL + 0x24 */ | ||
78 | u32 cs4_stop; /* MMAP_CTRL + 0x28 */ | ||
79 | u32 cs5_start; /* MMAP_CTRL + 0x2c */ | ||
80 | u32 cs5_stop; /* MMAP_CTRL + 0x30 */ | ||
81 | |||
82 | u32 sdram0; /* MMAP_CTRL + 0x34 */ | ||
83 | u32 sdram1; /* MMAP_CTRL + 0X38 */ | ||
84 | |||
85 | u32 reserved[4]; /* MMAP_CTRL + 0x3c .. 0x48 */ | ||
86 | |||
87 | u32 boot_start; /* MMAP_CTRL + 0x4c */ | ||
88 | u32 boot_stop; /* MMAP_CTRL + 0x50 */ | ||
89 | |||
90 | u32 ipbi_ws_ctrl; /* MMAP_CTRL + 0x54 */ | ||
91 | |||
92 | u32 cs6_start; /* MMAP_CTRL + 0x58 */ | ||
93 | u32 cs6_stop; /* MMAP_CTRL + 0x5c */ | ||
94 | u32 cs7_start; /* MMAP_CTRL + 0x60 */ | ||
95 | u32 cs7_stop; /* MMAP_CTRL + 0x64 */ | ||
96 | }; | ||
97 | |||
98 | /* SDRAM control */ | ||
99 | struct mpc52xx_sdram { | ||
100 | u32 mode; /* SDRAM + 0x00 */ | ||
101 | u32 ctrl; /* SDRAM + 0x04 */ | ||
102 | u32 config1; /* SDRAM + 0x08 */ | ||
103 | u32 config2; /* SDRAM + 0x0c */ | ||
104 | }; | ||
105 | |||
106 | /* SDMA */ | ||
107 | struct mpc52xx_sdma { | ||
108 | u32 taskBar; /* SDMA + 0x00 */ | ||
109 | u32 currentPointer; /* SDMA + 0x04 */ | ||
110 | u32 endPointer; /* SDMA + 0x08 */ | ||
111 | u32 variablePointer; /* SDMA + 0x0c */ | ||
112 | |||
113 | u8 IntVect1; /* SDMA + 0x10 */ | ||
114 | u8 IntVect2; /* SDMA + 0x11 */ | ||
115 | u16 PtdCntrl; /* SDMA + 0x12 */ | ||
116 | |||
117 | u32 IntPend; /* SDMA + 0x14 */ | ||
118 | u32 IntMask; /* SDMA + 0x18 */ | ||
119 | |||
120 | u16 tcr[16]; /* SDMA + 0x1c .. 0x3a */ | ||
121 | |||
122 | u8 ipr[32]; /* SDMA + 0x3c .. 0x5b */ | ||
123 | |||
124 | u32 cReqSelect; /* SDMA + 0x5c */ | ||
125 | u32 task_size0; /* SDMA + 0x60 */ | ||
126 | u32 task_size1; /* SDMA + 0x64 */ | ||
127 | u32 MDEDebug; /* SDMA + 0x68 */ | ||
128 | u32 ADSDebug; /* SDMA + 0x6c */ | ||
129 | u32 Value1; /* SDMA + 0x70 */ | ||
130 | u32 Value2; /* SDMA + 0x74 */ | ||
131 | u32 Control; /* SDMA + 0x78 */ | ||
132 | u32 Status; /* SDMA + 0x7c */ | ||
133 | u32 PTDDebug; /* SDMA + 0x80 */ | ||
134 | }; | ||
135 | |||
136 | /* GPT */ | ||
137 | struct mpc52xx_gpt { | ||
138 | u32 mode; /* GPTx + 0x00 */ | ||
139 | u32 count; /* GPTx + 0x04 */ | ||
140 | u32 pwm; /* GPTx + 0x08 */ | ||
141 | u32 status; /* GPTx + 0X0c */ | ||
142 | }; | ||
143 | |||
144 | /* GPIO */ | ||
145 | struct mpc52xx_gpio { | ||
146 | u32 port_config; /* GPIO + 0x00 */ | ||
147 | u32 simple_gpioe; /* GPIO + 0x04 */ | ||
148 | u32 simple_ode; /* GPIO + 0x08 */ | ||
149 | u32 simple_ddr; /* GPIO + 0x0c */ | ||
150 | u32 simple_dvo; /* GPIO + 0x10 */ | ||
151 | u32 simple_ival; /* GPIO + 0x14 */ | ||
152 | u8 outo_gpioe; /* GPIO + 0x18 */ | ||
153 | u8 reserved1[3]; /* GPIO + 0x19 */ | ||
154 | u8 outo_dvo; /* GPIO + 0x1c */ | ||
155 | u8 reserved2[3]; /* GPIO + 0x1d */ | ||
156 | u8 sint_gpioe; /* GPIO + 0x20 */ | ||
157 | u8 reserved3[3]; /* GPIO + 0x21 */ | ||
158 | u8 sint_ode; /* GPIO + 0x24 */ | ||
159 | u8 reserved4[3]; /* GPIO + 0x25 */ | ||
160 | u8 sint_ddr; /* GPIO + 0x28 */ | ||
161 | u8 reserved5[3]; /* GPIO + 0x29 */ | ||
162 | u8 sint_dvo; /* GPIO + 0x2c */ | ||
163 | u8 reserved6[3]; /* GPIO + 0x2d */ | ||
164 | u8 sint_inten; /* GPIO + 0x30 */ | ||
165 | u8 reserved7[3]; /* GPIO + 0x31 */ | ||
166 | u16 sint_itype; /* GPIO + 0x34 */ | ||
167 | u16 reserved8; /* GPIO + 0x36 */ | ||
168 | u8 gpio_control; /* GPIO + 0x38 */ | ||
169 | u8 reserved9[3]; /* GPIO + 0x39 */ | ||
170 | u8 sint_istat; /* GPIO + 0x3c */ | ||
171 | u8 sint_ival; /* GPIO + 0x3d */ | ||
172 | u8 bus_errs; /* GPIO + 0x3e */ | ||
173 | u8 reserved10; /* GPIO + 0x3f */ | ||
174 | }; | ||
175 | |||
176 | #define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD 4 | ||
177 | #define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD 5 | ||
178 | #define MPC52xx_GPIO_PCI_DIS (1<<15) | ||
179 | |||
180 | /* GPIO with WakeUp*/ | ||
181 | struct mpc52xx_gpio_wkup { | ||
182 | u8 wkup_gpioe; /* GPIO_WKUP + 0x00 */ | ||
183 | u8 reserved1[3]; /* GPIO_WKUP + 0x03 */ | ||
184 | u8 wkup_ode; /* GPIO_WKUP + 0x04 */ | ||
185 | u8 reserved2[3]; /* GPIO_WKUP + 0x05 */ | ||
186 | u8 wkup_ddr; /* GPIO_WKUP + 0x08 */ | ||
187 | u8 reserved3[3]; /* GPIO_WKUP + 0x09 */ | ||
188 | u8 wkup_dvo; /* GPIO_WKUP + 0x0C */ | ||
189 | u8 reserved4[3]; /* GPIO_WKUP + 0x0D */ | ||
190 | u8 wkup_inten; /* GPIO_WKUP + 0x10 */ | ||
191 | u8 reserved5[3]; /* GPIO_WKUP + 0x11 */ | ||
192 | u8 wkup_iinten; /* GPIO_WKUP + 0x14 */ | ||
193 | u8 reserved6[3]; /* GPIO_WKUP + 0x15 */ | ||
194 | u16 wkup_itype; /* GPIO_WKUP + 0x18 */ | ||
195 | u8 reserved7[2]; /* GPIO_WKUP + 0x1A */ | ||
196 | u8 wkup_maste; /* GPIO_WKUP + 0x1C */ | ||
197 | u8 reserved8[3]; /* GPIO_WKUP + 0x1D */ | ||
198 | u8 wkup_ival; /* GPIO_WKUP + 0x20 */ | ||
199 | u8 reserved9[3]; /* GPIO_WKUP + 0x21 */ | ||
200 | u8 wkup_istat; /* GPIO_WKUP + 0x24 */ | ||
201 | u8 reserved10[3]; /* GPIO_WKUP + 0x25 */ | ||
202 | }; | ||
203 | |||
204 | /* XLB Bus control */ | ||
205 | struct mpc52xx_xlb { | ||
206 | u8 reserved[0x40]; | ||
207 | u32 config; /* XLB + 0x40 */ | ||
208 | u32 version; /* XLB + 0x44 */ | ||
209 | u32 status; /* XLB + 0x48 */ | ||
210 | u32 int_enable; /* XLB + 0x4c */ | ||
211 | u32 addr_capture; /* XLB + 0x50 */ | ||
212 | u32 bus_sig_capture; /* XLB + 0x54 */ | ||
213 | u32 addr_timeout; /* XLB + 0x58 */ | ||
214 | u32 data_timeout; /* XLB + 0x5c */ | ||
215 | u32 bus_act_timeout; /* XLB + 0x60 */ | ||
216 | u32 master_pri_enable; /* XLB + 0x64 */ | ||
217 | u32 master_priority; /* XLB + 0x68 */ | ||
218 | u32 base_address; /* XLB + 0x6c */ | ||
219 | u32 snoop_window; /* XLB + 0x70 */ | ||
220 | }; | ||
221 | |||
222 | #define MPC52xx_XLB_CFG_PLDIS (1 << 31) | ||
223 | #define MPC52xx_XLB_CFG_SNOOP (1 << 15) | ||
224 | |||
225 | /* Clock Distribution control */ | ||
226 | struct mpc52xx_cdm { | ||
227 | u32 jtag_id; /* CDM + 0x00 reg0 read only */ | ||
228 | u32 rstcfg; /* CDM + 0x04 reg1 read only */ | ||
229 | u32 breadcrumb; /* CDM + 0x08 reg2 */ | ||
230 | |||
231 | u8 mem_clk_sel; /* CDM + 0x0c reg3 byte0 */ | ||
232 | u8 xlb_clk_sel; /* CDM + 0x0d reg3 byte1 read only */ | ||
233 | u8 ipb_clk_sel; /* CDM + 0x0e reg3 byte2 */ | ||
234 | u8 pci_clk_sel; /* CDM + 0x0f reg3 byte3 */ | ||
235 | |||
236 | u8 ext_48mhz_en; /* CDM + 0x10 reg4 byte0 */ | ||
237 | u8 fd_enable; /* CDM + 0x11 reg4 byte1 */ | ||
238 | u16 fd_counters; /* CDM + 0x12 reg4 byte2,3 */ | ||
239 | |||
240 | u32 clk_enables; /* CDM + 0x14 reg5 */ | ||
241 | |||
242 | u8 osc_disable; /* CDM + 0x18 reg6 byte0 */ | ||
243 | u8 reserved0[3]; /* CDM + 0x19 reg6 byte1,2,3 */ | ||
244 | |||
245 | u8 ccs_sleep_enable; /* CDM + 0x1c reg7 byte0 */ | ||
246 | u8 osc_sleep_enable; /* CDM + 0x1d reg7 byte1 */ | ||
247 | u8 reserved1; /* CDM + 0x1e reg7 byte2 */ | ||
248 | u8 ccs_qreq_test; /* CDM + 0x1f reg7 byte3 */ | ||
249 | |||
250 | u8 soft_reset; /* CDM + 0x20 u8 byte0 */ | ||
251 | u8 no_ckstp; /* CDM + 0x21 u8 byte0 */ | ||
252 | u8 reserved2[2]; /* CDM + 0x22 u8 byte1,2,3 */ | ||
253 | |||
254 | u8 pll_lock; /* CDM + 0x24 reg9 byte0 */ | ||
255 | u8 pll_looselock; /* CDM + 0x25 reg9 byte1 */ | ||
256 | u8 pll_sm_lockwin; /* CDM + 0x26 reg9 byte2 */ | ||
257 | u8 reserved3; /* CDM + 0x27 reg9 byte3 */ | ||
258 | |||
259 | u16 reserved4; /* CDM + 0x28 reg10 byte0,1 */ | ||
260 | u16 mclken_div_psc1; /* CDM + 0x2a reg10 byte2,3 */ | ||
261 | |||
262 | u16 reserved5; /* CDM + 0x2c reg11 byte0,1 */ | ||
263 | u16 mclken_div_psc2; /* CDM + 0x2e reg11 byte2,3 */ | ||
264 | |||
265 | u16 reserved6; /* CDM + 0x30 reg12 byte0,1 */ | ||
266 | u16 mclken_div_psc3; /* CDM + 0x32 reg12 byte2,3 */ | ||
267 | |||
268 | u16 reserved7; /* CDM + 0x34 reg13 byte0,1 */ | ||
269 | u16 mclken_div_psc6; /* CDM + 0x36 reg13 byte2,3 */ | ||
270 | }; | ||
271 | |||
272 | #endif /* __ASSEMBLY__ */ | ||
273 | |||
274 | |||
275 | /* ========================================================================= */ | ||
276 | /* Prototypes for MPC52xx sysdev */ | ||
277 | /* ========================================================================= */ | ||
278 | |||
279 | #ifndef __ASSEMBLY__ | ||
280 | |||
281 | extern void mpc52xx_init_irq(void); | ||
282 | extern unsigned int mpc52xx_get_irq(void); | ||
283 | |||
284 | #endif /* __ASSEMBLY__ */ | ||
285 | |||
286 | #endif /* __ASM_POWERPC_MPC52xx_H__ */ | ||
287 | |||
diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/mpc85xx.h index ccdb8a21138f..54142997a584 100644 --- a/include/asm-powerpc/mpc85xx.h +++ b/include/asm-powerpc/mpc85xx.h | |||
@@ -31,14 +31,6 @@ | |||
31 | #include <platforms/85xx/mpc85xx_cds.h> | 31 | #include <platforms/85xx/mpc85xx_cds.h> |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | #define _IO_BASE isa_io_base | ||
35 | #define _ISA_MEM_BASE isa_mem_base | ||
36 | #ifdef CONFIG_PCI | ||
37 | #define PCI_DRAM_OFFSET pci_dram_offset | ||
38 | #else | ||
39 | #define PCI_DRAM_OFFSET 0 | ||
40 | #endif | ||
41 | |||
42 | /* Let modules/drivers get at CCSRBAR */ | 34 | /* Let modules/drivers get at CCSRBAR */ |
43 | extern phys_addr_t get_ccsrbar(void); | 35 | extern phys_addr_t get_ccsrbar(void); |
44 | 36 | ||
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 0a4e5c93e8e6..0d3adc09c847 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h | |||
@@ -93,7 +93,8 @@ struct paca_struct { | |||
93 | u64 stab_rr; /* stab/slb round-robin counter */ | 93 | u64 stab_rr; /* stab/slb round-robin counter */ |
94 | u64 saved_r1; /* r1 save for RTAS calls */ | 94 | u64 saved_r1; /* r1 save for RTAS calls */ |
95 | u64 saved_msr; /* MSR saved here by enter_rtas */ | 95 | u64 saved_msr; /* MSR saved here by enter_rtas */ |
96 | u8 proc_enabled; /* irq soft-enable flag */ | 96 | u8 soft_enabled; /* irq soft-enable flag */ |
97 | u8 hard_enabled; /* set if irqs are enabled in MSR */ | ||
97 | u8 io_sync; /* writel() needs spin_unlock sync */ | 98 | u8 io_sync; /* writel() needs spin_unlock sync */ |
98 | 99 | ||
99 | /* Stuff for accurate time accounting */ | 100 | /* Stuff for accurate time accounting */ |
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h index 721c97f09b20..c77286051496 100644 --- a/include/asm-powerpc/pci.h +++ b/include/asm-powerpc/pci.h | |||
@@ -232,12 +232,10 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, | |||
232 | unsigned long size, | 232 | unsigned long size, |
233 | pgprot_t prot); | 233 | pgprot_t prot); |
234 | 234 | ||
235 | #if defined(CONFIG_PPC_MULTIPLATFORM) || defined(CONFIG_PPC32) | ||
236 | #define HAVE_ARCH_PCI_RESOURCE_TO_USER | 235 | #define HAVE_ARCH_PCI_RESOURCE_TO_USER |
237 | extern void pci_resource_to_user(const struct pci_dev *dev, int bar, | 236 | extern void pci_resource_to_user(const struct pci_dev *dev, int bar, |
238 | const struct resource *rsrc, | 237 | const struct resource *rsrc, |
239 | resource_size_t *start, resource_size_t *end); | 238 | resource_size_t *start, resource_size_t *end); |
240 | #endif /* CONFIG_PPC_MULTIPLATFORM || CONFIG_PPC32 */ | ||
241 | 239 | ||
242 | #endif /* __KERNEL__ */ | 240 | #endif /* __KERNEL__ */ |
243 | #endif /* __ASM_POWERPC_PCI_H */ | 241 | #endif /* __ASM_POWERPC_PCI_H */ |
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h index 6cb6fb19e57f..a26c32ee5527 100644 --- a/include/asm-powerpc/processor.h +++ b/include/asm-powerpc/processor.h | |||
@@ -53,10 +53,6 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin; | |||
53 | 53 | ||
54 | #endif /* CONFIG_PPC_PREP */ | 54 | #endif /* CONFIG_PPC_PREP */ |
55 | 55 | ||
56 | #ifndef CONFIG_PPC_MULTIPLATFORM | ||
57 | #define _machine 0 | ||
58 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
59 | |||
60 | #endif /* defined(__KERNEL__) && defined(CONFIG_PPC32) */ | 56 | #endif /* defined(__KERNEL__) && defined(CONFIG_PPC32) */ |
61 | 57 | ||
62 | /* | 58 | /* |
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index ec11d44eaeb5..0afee17f33b4 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/platform_device.h> | ||
20 | #include <asm/atomic.h> | 21 | #include <asm/atomic.h> |
21 | 22 | ||
22 | /* Definitions used by the flattened device tree */ | 23 | /* Definitions used by the flattened device tree */ |
@@ -333,6 +334,20 @@ extern int of_irq_map_one(struct device_node *device, int index, | |||
333 | struct pci_dev; | 334 | struct pci_dev; |
334 | extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); | 335 | extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); |
335 | 336 | ||
337 | static inline int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) | ||
338 | { | ||
339 | int irq = irq_of_parse_and_map(dev, index); | ||
340 | |||
341 | /* Only dereference the resource if both the | ||
342 | * resource and the irq are valid. */ | ||
343 | if (r && irq != NO_IRQ) { | ||
344 | r->start = r->end = irq; | ||
345 | r->flags = IORESOURCE_IRQ; | ||
346 | } | ||
347 | |||
348 | return irq; | ||
349 | } | ||
350 | |||
336 | 351 | ||
337 | #endif /* __KERNEL__ */ | 352 | #endif /* __KERNEL__ */ |
338 | #endif /* _POWERPC_PROM_H */ | 353 | #endif /* _POWERPC_PROM_H */ |
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index e73ea00efd8b..ffa4df083609 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
@@ -115,10 +115,10 @@ struct spu { | |||
115 | struct spu_priv2 __iomem *priv2; | 115 | struct spu_priv2 __iomem *priv2; |
116 | struct list_head list; | 116 | struct list_head list; |
117 | struct list_head sched_list; | 117 | struct list_head sched_list; |
118 | struct list_head full_list; | ||
118 | int number; | 119 | int number; |
119 | int nid; | 120 | int nid; |
120 | unsigned int irqs[3]; | 121 | unsigned int irqs[3]; |
121 | u32 isrc; | ||
122 | u32 node; | 122 | u32 node; |
123 | u64 flags; | 123 | u64 flags; |
124 | u64 dar; | 124 | u64 dar; |
@@ -144,6 +144,8 @@ struct spu { | |||
144 | char irq_c1[8]; | 144 | char irq_c1[8]; |
145 | char irq_c2[8]; | 145 | char irq_c2[8]; |
146 | 146 | ||
147 | struct device_node *devnode; | ||
148 | |||
147 | struct sys_device sysdev; | 149 | struct sys_device sysdev; |
148 | }; | 150 | }; |
149 | 151 | ||
@@ -182,8 +184,10 @@ extern struct spufs_calls { | |||
182 | */ | 184 | */ |
183 | #define SPU_CREATE_EVENTS_ENABLED 0x0001 | 185 | #define SPU_CREATE_EVENTS_ENABLED 0x0001 |
184 | #define SPU_CREATE_GANG 0x0002 | 186 | #define SPU_CREATE_GANG 0x0002 |
187 | #define SPU_CREATE_NOSCHED 0x0004 | ||
188 | #define SPU_CREATE_ISOLATE 0x0008 | ||
185 | 189 | ||
186 | #define SPU_CREATE_FLAG_ALL 0x0003 /* mask of all valid flags */ | 190 | #define SPU_CREATE_FLAG_ALL 0x000f /* mask of all valid flags */ |
187 | 191 | ||
188 | 192 | ||
189 | #ifdef CONFIG_SPU_FS_MODULE | 193 | #ifdef CONFIG_SPU_FS_MODULE |
@@ -199,6 +203,12 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) | |||
199 | } | 203 | } |
200 | #endif /* MODULE */ | 204 | #endif /* MODULE */ |
201 | 205 | ||
206 | int spu_add_sysdev_attr(struct sysdev_attribute *attr); | ||
207 | void spu_remove_sysdev_attr(struct sysdev_attribute *attr); | ||
208 | |||
209 | int spu_add_sysdev_attr_group(struct attribute_group *attrs); | ||
210 | void spu_remove_sysdev_attr_group(struct attribute_group *attrs); | ||
211 | |||
202 | 212 | ||
203 | /* | 213 | /* |
204 | * Notifier blocks: | 214 | * Notifier blocks: |
@@ -277,6 +287,7 @@ struct spu_problem { | |||
277 | u32 spu_runcntl_RW; /* 0x401c */ | 287 | u32 spu_runcntl_RW; /* 0x401c */ |
278 | #define SPU_RUNCNTL_STOP 0L | 288 | #define SPU_RUNCNTL_STOP 0L |
279 | #define SPU_RUNCNTL_RUNNABLE 1L | 289 | #define SPU_RUNCNTL_RUNNABLE 1L |
290 | #define SPU_RUNCNTL_ISOLATE 2L | ||
280 | u8 pad_0x4020_0x4024[0x4]; /* 0x4020 */ | 291 | u8 pad_0x4020_0x4024[0x4]; /* 0x4020 */ |
281 | u32 spu_status_R; /* 0x4024 */ | 292 | u32 spu_status_R; /* 0x4024 */ |
282 | #define SPU_STOP_STATUS_SHIFT 16 | 293 | #define SPU_STOP_STATUS_SHIFT 16 |
@@ -289,8 +300,8 @@ struct spu_problem { | |||
289 | #define SPU_STATUS_INVALID_INSTR 0x20 | 300 | #define SPU_STATUS_INVALID_INSTR 0x20 |
290 | #define SPU_STATUS_INVALID_CH 0x40 | 301 | #define SPU_STATUS_INVALID_CH 0x40 |
291 | #define SPU_STATUS_ISOLATED_STATE 0x80 | 302 | #define SPU_STATUS_ISOLATED_STATE 0x80 |
292 | #define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200 | 303 | #define SPU_STATUS_ISOLATED_LOAD_STATUS 0x200 |
293 | #define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400 | 304 | #define SPU_STATUS_ISOLATED_EXIT_STATUS 0x400 |
294 | u8 pad_0x4028_0x402c[0x4]; /* 0x4028 */ | 305 | u8 pad_0x4028_0x402c[0x4]; /* 0x4028 */ |
295 | u32 spu_spe_R; /* 0x402c */ | 306 | u32 spu_spe_R; /* 0x402c */ |
296 | u8 pad_0x4030_0x4034[0x4]; /* 0x4030 */ | 307 | u8 pad_0x4030_0x4034[0x4]; /* 0x4030 */ |
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h index 964c2d38ccb7..bdbf906a767f 100644 --- a/include/asm-powerpc/spu_csa.h +++ b/include/asm-powerpc/spu_csa.h | |||
@@ -151,7 +151,6 @@ struct spu_priv1_collapsed { | |||
151 | u64 mfc_fir_chkstp_enable_RW; | 151 | u64 mfc_fir_chkstp_enable_RW; |
152 | u64 smf_sbi_signal_sel; | 152 | u64 smf_sbi_signal_sel; |
153 | u64 smf_ato_signal_sel; | 153 | u64 smf_ato_signal_sel; |
154 | u64 mfc_sdr_RW; | ||
155 | u64 tlb_index_hint_RO; | 154 | u64 tlb_index_hint_RO; |
156 | u64 tlb_index_W; | 155 | u64 tlb_index_W; |
157 | u64 tlb_vpn_RW; | 156 | u64 tlb_vpn_RW; |
diff --git a/include/asm-powerpc/spu_priv1.h b/include/asm-powerpc/spu_priv1.h index 300c458b6d06..4f9a04db99f7 100644 --- a/include/asm-powerpc/spu_priv1.h +++ b/include/asm-powerpc/spu_priv1.h | |||
@@ -37,7 +37,7 @@ struct spu_priv1_ops | |||
37 | u64 (*mfc_dar_get) (struct spu *spu); | 37 | u64 (*mfc_dar_get) (struct spu *spu); |
38 | u64 (*mfc_dsisr_get) (struct spu *spu); | 38 | u64 (*mfc_dsisr_get) (struct spu *spu); |
39 | void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr); | 39 | void (*mfc_dsisr_set) (struct spu *spu, u64 dsisr); |
40 | void (*mfc_sdr_set) (struct spu *spu, u64 sdr); | 40 | void (*mfc_sdr_setup) (struct spu *spu); |
41 | void (*mfc_sr1_set) (struct spu *spu, u64 sr1); | 41 | void (*mfc_sr1_set) (struct spu *spu, u64 sr1); |
42 | u64 (*mfc_sr1_get) (struct spu *spu); | 42 | u64 (*mfc_sr1_get) (struct spu *spu); |
43 | void (*mfc_tclass_id_set) (struct spu *spu, u64 tclass_id); | 43 | void (*mfc_tclass_id_set) (struct spu *spu, u64 tclass_id); |
@@ -112,9 +112,9 @@ spu_mfc_dsisr_set (struct spu *spu, u64 dsisr) | |||
112 | } | 112 | } |
113 | 113 | ||
114 | static inline void | 114 | static inline void |
115 | spu_mfc_sdr_set (struct spu *spu, u64 sdr) | 115 | spu_mfc_sdr_setup (struct spu *spu) |
116 | { | 116 | { |
117 | spu_priv1_ops->mfc_sdr_set(spu, sdr); | 117 | spu_priv1_ops->mfc_sdr_setup(spu); |
118 | } | 118 | } |
119 | 119 | ||
120 | static inline void | 120 | static inline void |
diff --git a/include/asm-powerpc/todc.h b/include/asm-powerpc/todc.h deleted file mode 100644 index 60a8c39b8c11..000000000000 --- a/include/asm-powerpc/todc.h +++ /dev/null | |||
@@ -1,487 +0,0 @@ | |||
1 | /* | ||
2 | * Definitions for the M48Txx and mc146818 series of Time of day/Real Time | ||
3 | * Clock chips. | ||
4 | * | ||
5 | * Author: Mark A. Greer <mgreer@mvista.com> | ||
6 | * | ||
7 | * 2001 (c) MontaVista, Software, Inc. This file is licensed under | ||
8 | * the terms of the GNU General Public License version 2. This program | ||
9 | * is licensed "as is" without any warranty of any kind, whether express | ||
10 | * or implied. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Support for the M48T37/M48T59/.../mc146818 Real Time Clock chips. | ||
15 | * Purpose is to make one generic file that handles all of these chips instead | ||
16 | * of every platform implementing the same code over & over again. | ||
17 | */ | ||
18 | |||
19 | #ifndef __PPC_KERNEL_TODC_H | ||
20 | #define __PPC_KERNEL_TODC_H | ||
21 | |||
22 | typedef struct { | ||
23 | uint rtc_type; /* your particular chip */ | ||
24 | |||
25 | /* | ||
26 | * Following are the addresses of the AS0, AS1, and DATA registers | ||
27 | * of these chips. Note that these are board-specific. | ||
28 | */ | ||
29 | unsigned int nvram_as0; | ||
30 | unsigned int nvram_as1; | ||
31 | unsigned int nvram_data; | ||
32 | |||
33 | /* | ||
34 | * Define bits to stop external set of regs from changing so | ||
35 | * the chip can be read/written reliably. | ||
36 | */ | ||
37 | unsigned char enable_read; | ||
38 | unsigned char enable_write; | ||
39 | |||
40 | /* | ||
41 | * Following is the number of AS0 address bits. This is normally | ||
42 | * 8 but some bad hardware routes address lines incorrectly. | ||
43 | */ | ||
44 | int as0_bits; | ||
45 | |||
46 | int nvram_size; /* Size of NVRAM on chip */ | ||
47 | int sw_flags; /* Software control flags */ | ||
48 | |||
49 | /* Following are the register offsets for the particular chip */ | ||
50 | int year; | ||
51 | int month; | ||
52 | int day_of_month; | ||
53 | int day_of_week; | ||
54 | int hours; | ||
55 | int minutes; | ||
56 | int seconds; | ||
57 | int control_b; | ||
58 | int control_a; | ||
59 | int watchdog; | ||
60 | int interrupts; | ||
61 | int alarm_date; | ||
62 | int alarm_hour; | ||
63 | int alarm_minutes; | ||
64 | int alarm_seconds; | ||
65 | int century; | ||
66 | int flags; | ||
67 | |||
68 | /* | ||
69 | * Some RTC chips have their NVRAM buried behind a addr/data pair of | ||
70 | * regs on the first level/clock registers. The following fields | ||
71 | * are the addresses for those addr/data regs. | ||
72 | */ | ||
73 | int nvram_addr_reg; | ||
74 | int nvram_data_reg; | ||
75 | } todc_info_t; | ||
76 | |||
77 | /* | ||
78 | * Define the types of TODC/RTC variants that are supported in | ||
79 | * arch/ppc/kernel/todc_time.c | ||
80 | * Make a new one of these for any chip somehow differs from what's already | ||
81 | * defined. That way, if you ever need to put in code to touch those | ||
82 | * bits/registers in todc_time.c, you can put it inside an | ||
83 | * 'if (todc_info->rtc_type == TODC_TYPE_XXX)' so you won't break | ||
84 | * anyone else. | ||
85 | */ | ||
86 | #define TODC_TYPE_MK48T35 1 | ||
87 | #define TODC_TYPE_MK48T37 2 | ||
88 | #define TODC_TYPE_MK48T59 3 | ||
89 | #define TODC_TYPE_DS1693 4 /* Dallas DS1693 RTC */ | ||
90 | #define TODC_TYPE_DS1743 5 /* Dallas DS1743 RTC */ | ||
91 | #define TODC_TYPE_DS1746 6 /* Dallas DS1746 RTC */ | ||
92 | #define TODC_TYPE_DS1747 7 /* Dallas DS1747 RTC */ | ||
93 | #define TODC_TYPE_DS1501 8 /* Dallas DS1501 RTC */ | ||
94 | #define TODC_TYPE_DS1643 9 /* Dallas DS1643 RTC */ | ||
95 | #define TODC_TYPE_PC97307 10 /* PC97307 internal RTC */ | ||
96 | #define TODC_TYPE_DS1557 11 /* Dallas DS1557 RTC */ | ||
97 | #define TODC_TYPE_DS17285 12 /* Dallas DS17285 RTC */ | ||
98 | #define TODC_TYPE_DS1553 13 /* Dallas DS1553 RTC */ | ||
99 | #define TODC_TYPE_MC146818 100 /* Leave room for m48txx's */ | ||
100 | |||
101 | /* | ||
102 | * Bit to clear/set to enable reads/writes to the chip | ||
103 | */ | ||
104 | #define TODC_MK48TXX_CNTL_A_R 0x40 | ||
105 | #define TODC_MK48TXX_CNTL_A_W 0x80 | ||
106 | #define TODC_MK48TXX_DAY_CB 0x80 | ||
107 | |||
108 | #define TODC_DS1501_CNTL_B_TE 0x80 | ||
109 | |||
110 | /* | ||
111 | * Define flag bits used by todc routines. | ||
112 | */ | ||
113 | #define TODC_FLAG_2_LEVEL_NVRAM 0x00000001 | ||
114 | |||
115 | /* | ||
116 | * Define the values for the various RTC's that should to into the todc_info | ||
117 | * table. | ||
118 | * Note: The XXX_NVRAM_SIZE, XXX_NVRAM_ADDR_REG, and XXX_NVRAM_DATA_REG only | ||
119 | * matter if XXX_SW_FLAGS has TODC_FLAG_2_LEVEL_NVRAM set. | ||
120 | */ | ||
121 | #define TODC_TYPE_MK48T35_NVRAM_SIZE 0x7ff8 | ||
122 | #define TODC_TYPE_MK48T35_SW_FLAGS 0 | ||
123 | #define TODC_TYPE_MK48T35_YEAR 0x7fff | ||
124 | #define TODC_TYPE_MK48T35_MONTH 0x7ffe | ||
125 | #define TODC_TYPE_MK48T35_DOM 0x7ffd /* Day of Month */ | ||
126 | #define TODC_TYPE_MK48T35_DOW 0x7ffc /* Day of Week */ | ||
127 | #define TODC_TYPE_MK48T35_HOURS 0x7ffb | ||
128 | #define TODC_TYPE_MK48T35_MINUTES 0x7ffa | ||
129 | #define TODC_TYPE_MK48T35_SECONDS 0x7ff9 | ||
130 | #define TODC_TYPE_MK48T35_CNTL_B 0x7ff9 | ||
131 | #define TODC_TYPE_MK48T35_CNTL_A 0x7ff8 | ||
132 | #define TODC_TYPE_MK48T35_WATCHDOG 0x0000 | ||
133 | #define TODC_TYPE_MK48T35_INTERRUPTS 0x0000 | ||
134 | #define TODC_TYPE_MK48T35_ALARM_DATE 0x0000 | ||
135 | #define TODC_TYPE_MK48T35_ALARM_HOUR 0x0000 | ||
136 | #define TODC_TYPE_MK48T35_ALARM_MINUTES 0x0000 | ||
137 | #define TODC_TYPE_MK48T35_ALARM_SECONDS 0x0000 | ||
138 | #define TODC_TYPE_MK48T35_CENTURY 0x0000 | ||
139 | #define TODC_TYPE_MK48T35_FLAGS 0x0000 | ||
140 | #define TODC_TYPE_MK48T35_NVRAM_ADDR_REG 0 | ||
141 | #define TODC_TYPE_MK48T35_NVRAM_DATA_REG 0 | ||
142 | |||
143 | #define TODC_TYPE_MK48T37_NVRAM_SIZE 0x7ff0 | ||
144 | #define TODC_TYPE_MK48T37_SW_FLAGS 0 | ||
145 | #define TODC_TYPE_MK48T37_YEAR 0x7fff | ||
146 | #define TODC_TYPE_MK48T37_MONTH 0x7ffe | ||
147 | #define TODC_TYPE_MK48T37_DOM 0x7ffd /* Day of Month */ | ||
148 | #define TODC_TYPE_MK48T37_DOW 0x7ffc /* Day of Week */ | ||
149 | #define TODC_TYPE_MK48T37_HOURS 0x7ffb | ||
150 | #define TODC_TYPE_MK48T37_MINUTES 0x7ffa | ||
151 | #define TODC_TYPE_MK48T37_SECONDS 0x7ff9 | ||
152 | #define TODC_TYPE_MK48T37_CNTL_B 0x7ff9 | ||
153 | #define TODC_TYPE_MK48T37_CNTL_A 0x7ff8 | ||
154 | #define TODC_TYPE_MK48T37_WATCHDOG 0x7ff7 | ||
155 | #define TODC_TYPE_MK48T37_INTERRUPTS 0x7ff6 | ||
156 | #define TODC_TYPE_MK48T37_ALARM_DATE 0x7ff5 | ||
157 | #define TODC_TYPE_MK48T37_ALARM_HOUR 0x7ff4 | ||
158 | #define TODC_TYPE_MK48T37_ALARM_MINUTES 0x7ff3 | ||
159 | #define TODC_TYPE_MK48T37_ALARM_SECONDS 0x7ff2 | ||
160 | #define TODC_TYPE_MK48T37_CENTURY 0x7ff1 | ||
161 | #define TODC_TYPE_MK48T37_FLAGS 0x7ff0 | ||
162 | #define TODC_TYPE_MK48T37_NVRAM_ADDR_REG 0 | ||
163 | #define TODC_TYPE_MK48T37_NVRAM_DATA_REG 0 | ||
164 | |||
165 | #define TODC_TYPE_MK48T59_NVRAM_SIZE 0x1ff0 | ||
166 | #define TODC_TYPE_MK48T59_SW_FLAGS 0 | ||
167 | #define TODC_TYPE_MK48T59_YEAR 0x1fff | ||
168 | #define TODC_TYPE_MK48T59_MONTH 0x1ffe | ||
169 | #define TODC_TYPE_MK48T59_DOM 0x1ffd /* Day of Month */ | ||
170 | #define TODC_TYPE_MK48T59_DOW 0x1ffc /* Day of Week */ | ||
171 | #define TODC_TYPE_MK48T59_HOURS 0x1ffb | ||
172 | #define TODC_TYPE_MK48T59_MINUTES 0x1ffa | ||
173 | #define TODC_TYPE_MK48T59_SECONDS 0x1ff9 | ||
174 | #define TODC_TYPE_MK48T59_CNTL_B 0x1ff9 | ||
175 | #define TODC_TYPE_MK48T59_CNTL_A 0x1ff8 | ||
176 | #define TODC_TYPE_MK48T59_WATCHDOG 0x1fff | ||
177 | #define TODC_TYPE_MK48T59_INTERRUPTS 0x1fff | ||
178 | #define TODC_TYPE_MK48T59_ALARM_DATE 0x1fff | ||
179 | #define TODC_TYPE_MK48T59_ALARM_HOUR 0x1fff | ||
180 | #define TODC_TYPE_MK48T59_ALARM_MINUTES 0x1fff | ||
181 | #define TODC_TYPE_MK48T59_ALARM_SECONDS 0x1fff | ||
182 | #define TODC_TYPE_MK48T59_CENTURY 0x1fff | ||
183 | #define TODC_TYPE_MK48T59_FLAGS 0x1fff | ||
184 | #define TODC_TYPE_MK48T59_NVRAM_ADDR_REG 0 | ||
185 | #define TODC_TYPE_MK48T59_NVRAM_DATA_REG 0 | ||
186 | |||
187 | #define TODC_TYPE_DS1501_NVRAM_SIZE 0x100 | ||
188 | #define TODC_TYPE_DS1501_SW_FLAGS TODC_FLAG_2_LEVEL_NVRAM | ||
189 | #define TODC_TYPE_DS1501_YEAR (TODC_TYPE_DS1501_NVRAM_SIZE + 0x06) | ||
190 | #define TODC_TYPE_DS1501_MONTH (TODC_TYPE_DS1501_NVRAM_SIZE + 0x05) | ||
191 | #define TODC_TYPE_DS1501_DOM (TODC_TYPE_DS1501_NVRAM_SIZE + 0x04) | ||
192 | #define TODC_TYPE_DS1501_DOW (TODC_TYPE_DS1501_NVRAM_SIZE + 0x03) | ||
193 | #define TODC_TYPE_DS1501_HOURS (TODC_TYPE_DS1501_NVRAM_SIZE + 0x02) | ||
194 | #define TODC_TYPE_DS1501_MINUTES (TODC_TYPE_DS1501_NVRAM_SIZE + 0x01) | ||
195 | #define TODC_TYPE_DS1501_SECONDS (TODC_TYPE_DS1501_NVRAM_SIZE + 0x00) | ||
196 | #define TODC_TYPE_DS1501_CNTL_B (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f) | ||
197 | #define TODC_TYPE_DS1501_CNTL_A (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f) | ||
198 | #define TODC_TYPE_DS1501_WATCHDOG (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff) | ||
199 | #define TODC_TYPE_DS1501_INTERRUPTS (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff) | ||
200 | #define TODC_TYPE_DS1501_ALARM_DATE (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0b) | ||
201 | #define TODC_TYPE_DS1501_ALARM_HOUR (TODC_TYPE_DS1501_NVRAM_SIZE + 0x0a) | ||
202 | #define TODC_TYPE_DS1501_ALARM_MINUTES (TODC_TYPE_DS1501_NVRAM_SIZE + 0x09) | ||
203 | #define TODC_TYPE_DS1501_ALARM_SECONDS (TODC_TYPE_DS1501_NVRAM_SIZE + 0x08) | ||
204 | #define TODC_TYPE_DS1501_CENTURY (TODC_TYPE_DS1501_NVRAM_SIZE + 0x07) | ||
205 | #define TODC_TYPE_DS1501_FLAGS (TODC_TYPE_DS1501_NVRAM_SIZE + 0xff) | ||
206 | #define TODC_TYPE_DS1501_NVRAM_ADDR_REG 0x10 | ||
207 | #define TODC_TYPE_DS1501_NVRAM_DATA_REG 0x13 | ||
208 | |||
209 | #define TODC_TYPE_DS1553_NVRAM_SIZE 0x1ff0 | ||
210 | #define TODC_TYPE_DS1553_SW_FLAGS 0 | ||
211 | #define TODC_TYPE_DS1553_YEAR 0x1fff | ||
212 | #define TODC_TYPE_DS1553_MONTH 0x1ffe | ||
213 | #define TODC_TYPE_DS1553_DOM 0x1ffd /* Day of Month */ | ||
214 | #define TODC_TYPE_DS1553_DOW 0x1ffc /* Day of Week */ | ||
215 | #define TODC_TYPE_DS1553_HOURS 0x1ffb | ||
216 | #define TODC_TYPE_DS1553_MINUTES 0x1ffa | ||
217 | #define TODC_TYPE_DS1553_SECONDS 0x1ff9 | ||
218 | #define TODC_TYPE_DS1553_CNTL_B 0x1ff9 | ||
219 | #define TODC_TYPE_DS1553_CNTL_A 0x1ff8 /* control_a R/W regs */ | ||
220 | #define TODC_TYPE_DS1553_WATCHDOG 0x1ff7 | ||
221 | #define TODC_TYPE_DS1553_INTERRUPTS 0x1ff6 | ||
222 | #define TODC_TYPE_DS1553_ALARM_DATE 0x1ff5 | ||
223 | #define TODC_TYPE_DS1553_ALARM_HOUR 0x1ff4 | ||
224 | #define TODC_TYPE_DS1553_ALARM_MINUTES 0x1ff3 | ||
225 | #define TODC_TYPE_DS1553_ALARM_SECONDS 0x1ff2 | ||
226 | #define TODC_TYPE_DS1553_CENTURY 0x1ff8 | ||
227 | #define TODC_TYPE_DS1553_FLAGS 0x1ff0 | ||
228 | #define TODC_TYPE_DS1553_NVRAM_ADDR_REG 0 | ||
229 | #define TODC_TYPE_DS1553_NVRAM_DATA_REG 0 | ||
230 | |||
231 | #define TODC_TYPE_DS1557_NVRAM_SIZE 0x7fff0 | ||
232 | #define TODC_TYPE_DS1557_SW_FLAGS 0 | ||
233 | #define TODC_TYPE_DS1557_YEAR 0x7ffff | ||
234 | #define TODC_TYPE_DS1557_MONTH 0x7fffe | ||
235 | #define TODC_TYPE_DS1557_DOM 0x7fffd /* Day of Month */ | ||
236 | #define TODC_TYPE_DS1557_DOW 0x7fffc /* Day of Week */ | ||
237 | #define TODC_TYPE_DS1557_HOURS 0x7fffb | ||
238 | #define TODC_TYPE_DS1557_MINUTES 0x7fffa | ||
239 | #define TODC_TYPE_DS1557_SECONDS 0x7fff9 | ||
240 | #define TODC_TYPE_DS1557_CNTL_B 0x7fff9 | ||
241 | #define TODC_TYPE_DS1557_CNTL_A 0x7fff8 /* control_a R/W regs */ | ||
242 | #define TODC_TYPE_DS1557_WATCHDOG 0x7fff7 | ||
243 | #define TODC_TYPE_DS1557_INTERRUPTS 0x7fff6 | ||
244 | #define TODC_TYPE_DS1557_ALARM_DATE 0x7fff5 | ||
245 | #define TODC_TYPE_DS1557_ALARM_HOUR 0x7fff4 | ||
246 | #define TODC_TYPE_DS1557_ALARM_MINUTES 0x7fff3 | ||
247 | #define TODC_TYPE_DS1557_ALARM_SECONDS 0x7fff2 | ||
248 | #define TODC_TYPE_DS1557_CENTURY 0x7fff8 | ||
249 | #define TODC_TYPE_DS1557_FLAGS 0x7fff0 | ||
250 | #define TODC_TYPE_DS1557_NVRAM_ADDR_REG 0 | ||
251 | #define TODC_TYPE_DS1557_NVRAM_DATA_REG 0 | ||
252 | |||
253 | #define TODC_TYPE_DS1643_NVRAM_SIZE 0x1ff8 | ||
254 | #define TODC_TYPE_DS1643_SW_FLAGS 0 | ||
255 | #define TODC_TYPE_DS1643_YEAR 0x1fff | ||
256 | #define TODC_TYPE_DS1643_MONTH 0x1ffe | ||
257 | #define TODC_TYPE_DS1643_DOM 0x1ffd /* Day of Month */ | ||
258 | #define TODC_TYPE_DS1643_DOW 0x1ffc /* Day of Week */ | ||
259 | #define TODC_TYPE_DS1643_HOURS 0x1ffb | ||
260 | #define TODC_TYPE_DS1643_MINUTES 0x1ffa | ||
261 | #define TODC_TYPE_DS1643_SECONDS 0x1ff9 | ||
262 | #define TODC_TYPE_DS1643_CNTL_B 0x1ff9 | ||
263 | #define TODC_TYPE_DS1643_CNTL_A 0x1ff8 /* control_a R/W regs */ | ||
264 | #define TODC_TYPE_DS1643_WATCHDOG 0x1fff | ||
265 | #define TODC_TYPE_DS1643_INTERRUPTS 0x1fff | ||
266 | #define TODC_TYPE_DS1643_ALARM_DATE 0x1fff | ||
267 | #define TODC_TYPE_DS1643_ALARM_HOUR 0x1fff | ||
268 | #define TODC_TYPE_DS1643_ALARM_MINUTES 0x1fff | ||
269 | #define TODC_TYPE_DS1643_ALARM_SECONDS 0x1fff | ||
270 | #define TODC_TYPE_DS1643_CENTURY 0x1ff8 | ||
271 | #define TODC_TYPE_DS1643_FLAGS 0x1fff | ||
272 | #define TODC_TYPE_DS1643_NVRAM_ADDR_REG 0 | ||
273 | #define TODC_TYPE_DS1643_NVRAM_DATA_REG 0 | ||
274 | |||
275 | #define TODC_TYPE_DS1693_NVRAM_SIZE 0 /* Not handled yet */ | ||
276 | #define TODC_TYPE_DS1693_SW_FLAGS 0 | ||
277 | #define TODC_TYPE_DS1693_YEAR 0x09 | ||
278 | #define TODC_TYPE_DS1693_MONTH 0x08 | ||
279 | #define TODC_TYPE_DS1693_DOM 0x07 /* Day of Month */ | ||
280 | #define TODC_TYPE_DS1693_DOW 0x06 /* Day of Week */ | ||
281 | #define TODC_TYPE_DS1693_HOURS 0x04 | ||
282 | #define TODC_TYPE_DS1693_MINUTES 0x02 | ||
283 | #define TODC_TYPE_DS1693_SECONDS 0x00 | ||
284 | #define TODC_TYPE_DS1693_CNTL_B 0x0b | ||
285 | #define TODC_TYPE_DS1693_CNTL_A 0x0a | ||
286 | #define TODC_TYPE_DS1693_WATCHDOG 0xff | ||
287 | #define TODC_TYPE_DS1693_INTERRUPTS 0xff | ||
288 | #define TODC_TYPE_DS1693_ALARM_DATE 0x49 | ||
289 | #define TODC_TYPE_DS1693_ALARM_HOUR 0x05 | ||
290 | #define TODC_TYPE_DS1693_ALARM_MINUTES 0x03 | ||
291 | #define TODC_TYPE_DS1693_ALARM_SECONDS 0x01 | ||
292 | #define TODC_TYPE_DS1693_CENTURY 0x48 | ||
293 | #define TODC_TYPE_DS1693_FLAGS 0xff | ||
294 | #define TODC_TYPE_DS1693_NVRAM_ADDR_REG 0 | ||
295 | #define TODC_TYPE_DS1693_NVRAM_DATA_REG 0 | ||
296 | |||
297 | #define TODC_TYPE_DS1743_NVRAM_SIZE 0x1ff8 | ||
298 | #define TODC_TYPE_DS1743_SW_FLAGS 0 | ||
299 | #define TODC_TYPE_DS1743_YEAR 0x1fff | ||
300 | #define TODC_TYPE_DS1743_MONTH 0x1ffe | ||
301 | #define TODC_TYPE_DS1743_DOM 0x1ffd /* Day of Month */ | ||
302 | #define TODC_TYPE_DS1743_DOW 0x1ffc /* Day of Week */ | ||
303 | #define TODC_TYPE_DS1743_HOURS 0x1ffb | ||
304 | #define TODC_TYPE_DS1743_MINUTES 0x1ffa | ||
305 | #define TODC_TYPE_DS1743_SECONDS 0x1ff9 | ||
306 | #define TODC_TYPE_DS1743_CNTL_B 0x1ff9 | ||
307 | #define TODC_TYPE_DS1743_CNTL_A 0x1ff8 /* control_a R/W regs */ | ||
308 | #define TODC_TYPE_DS1743_WATCHDOG 0x1fff | ||
309 | #define TODC_TYPE_DS1743_INTERRUPTS 0x1fff | ||
310 | #define TODC_TYPE_DS1743_ALARM_DATE 0x1fff | ||
311 | #define TODC_TYPE_DS1743_ALARM_HOUR 0x1fff | ||
312 | #define TODC_TYPE_DS1743_ALARM_MINUTES 0x1fff | ||
313 | #define TODC_TYPE_DS1743_ALARM_SECONDS 0x1fff | ||
314 | #define TODC_TYPE_DS1743_CENTURY 0x1ff8 | ||
315 | #define TODC_TYPE_DS1743_FLAGS 0x1fff | ||
316 | #define TODC_TYPE_DS1743_NVRAM_ADDR_REG 0 | ||
317 | #define TODC_TYPE_DS1743_NVRAM_DATA_REG 0 | ||
318 | |||
319 | #define TODC_TYPE_DS1746_NVRAM_SIZE 0x1fff8 | ||
320 | #define TODC_TYPE_DS1746_SW_FLAGS 0 | ||
321 | #define TODC_TYPE_DS1746_YEAR 0x1ffff | ||
322 | #define TODC_TYPE_DS1746_MONTH 0x1fffe | ||
323 | #define TODC_TYPE_DS1746_DOM 0x1fffd /* Day of Month */ | ||
324 | #define TODC_TYPE_DS1746_DOW 0x1fffc /* Day of Week */ | ||
325 | #define TODC_TYPE_DS1746_HOURS 0x1fffb | ||
326 | #define TODC_TYPE_DS1746_MINUTES 0x1fffa | ||
327 | #define TODC_TYPE_DS1746_SECONDS 0x1fff9 | ||
328 | #define TODC_TYPE_DS1746_CNTL_B 0x1fff9 | ||
329 | #define TODC_TYPE_DS1746_CNTL_A 0x1fff8 /* control_a R/W regs */ | ||
330 | #define TODC_TYPE_DS1746_WATCHDOG 0x00000 | ||
331 | #define TODC_TYPE_DS1746_INTERRUPTS 0x00000 | ||
332 | #define TODC_TYPE_DS1746_ALARM_DATE 0x00000 | ||
333 | #define TODC_TYPE_DS1746_ALARM_HOUR 0x00000 | ||
334 | #define TODC_TYPE_DS1746_ALARM_MINUTES 0x00000 | ||
335 | #define TODC_TYPE_DS1746_ALARM_SECONDS 0x00000 | ||
336 | #define TODC_TYPE_DS1746_CENTURY 0x00000 | ||
337 | #define TODC_TYPE_DS1746_FLAGS 0x00000 | ||
338 | #define TODC_TYPE_DS1746_NVRAM_ADDR_REG 0 | ||
339 | #define TODC_TYPE_DS1746_NVRAM_DATA_REG 0 | ||
340 | |||
341 | #define TODC_TYPE_DS1747_NVRAM_SIZE 0x7fff8 | ||
342 | #define TODC_TYPE_DS1747_SW_FLAGS 0 | ||
343 | #define TODC_TYPE_DS1747_YEAR 0x7ffff | ||
344 | #define TODC_TYPE_DS1747_MONTH 0x7fffe | ||
345 | #define TODC_TYPE_DS1747_DOM 0x7fffd /* Day of Month */ | ||
346 | #define TODC_TYPE_DS1747_DOW 0x7fffc /* Day of Week */ | ||
347 | #define TODC_TYPE_DS1747_HOURS 0x7fffb | ||
348 | #define TODC_TYPE_DS1747_MINUTES 0x7fffa | ||
349 | #define TODC_TYPE_DS1747_SECONDS 0x7fff9 | ||
350 | #define TODC_TYPE_DS1747_CNTL_B 0x7fff9 | ||
351 | #define TODC_TYPE_DS1747_CNTL_A 0x7fff8 /* control_a R/W regs */ | ||
352 | #define TODC_TYPE_DS1747_WATCHDOG 0x00000 | ||
353 | #define TODC_TYPE_DS1747_INTERRUPTS 0x00000 | ||
354 | #define TODC_TYPE_DS1747_ALARM_DATE 0x00000 | ||
355 | #define TODC_TYPE_DS1747_ALARM_HOUR 0x00000 | ||
356 | #define TODC_TYPE_DS1747_ALARM_MINUTES 0x00000 | ||
357 | #define TODC_TYPE_DS1747_ALARM_SECONDS 0x00000 | ||
358 | #define TODC_TYPE_DS1747_CENTURY 0x00000 | ||
359 | #define TODC_TYPE_DS1747_FLAGS 0x00000 | ||
360 | #define TODC_TYPE_DS1747_NVRAM_ADDR_REG 0 | ||
361 | #define TODC_TYPE_DS1747_NVRAM_DATA_REG 0 | ||
362 | |||
363 | #define TODC_TYPE_DS17285_NVRAM_SIZE (0x1000-0x80) /* 4Kx8 NVRAM (minus RTC regs) */ | ||
364 | #define TODC_TYPE_DS17285_SW_FLAGS TODC_FLAG_2_LEVEL_NVRAM | ||
365 | #define TODC_TYPE_DS17285_SECONDS (TODC_TYPE_DS17285_NVRAM_SIZE + 0x00) | ||
366 | #define TODC_TYPE_DS17285_ALARM_SECONDS (TODC_TYPE_DS17285_NVRAM_SIZE + 0x01) | ||
367 | #define TODC_TYPE_DS17285_MINUTES (TODC_TYPE_DS17285_NVRAM_SIZE + 0x02) | ||
368 | #define TODC_TYPE_DS17285_ALARM_MINUTES (TODC_TYPE_DS17285_NVRAM_SIZE + 0x03) | ||
369 | #define TODC_TYPE_DS17285_HOURS (TODC_TYPE_DS17285_NVRAM_SIZE + 0x04) | ||
370 | #define TODC_TYPE_DS17285_ALARM_HOUR (TODC_TYPE_DS17285_NVRAM_SIZE + 0x05) | ||
371 | #define TODC_TYPE_DS17285_DOW (TODC_TYPE_DS17285_NVRAM_SIZE + 0x06) | ||
372 | #define TODC_TYPE_DS17285_DOM (TODC_TYPE_DS17285_NVRAM_SIZE + 0x07) | ||
373 | #define TODC_TYPE_DS17285_MONTH (TODC_TYPE_DS17285_NVRAM_SIZE + 0x08) | ||
374 | #define TODC_TYPE_DS17285_YEAR (TODC_TYPE_DS17285_NVRAM_SIZE + 0x09) | ||
375 | #define TODC_TYPE_DS17285_CNTL_A (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0A) | ||
376 | #define TODC_TYPE_DS17285_CNTL_B (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0B) | ||
377 | #define TODC_TYPE_DS17285_CNTL_C (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0C) | ||
378 | #define TODC_TYPE_DS17285_CNTL_D (TODC_TYPE_DS17285_NVRAM_SIZE + 0x0D) | ||
379 | #define TODC_TYPE_DS17285_WATCHDOG 0 | ||
380 | #define TODC_TYPE_DS17285_INTERRUPTS 0 | ||
381 | #define TODC_TYPE_DS17285_ALARM_DATE 0 | ||
382 | #define TODC_TYPE_DS17285_CENTURY 0 | ||
383 | #define TODC_TYPE_DS17285_FLAGS 0 | ||
384 | #define TODC_TYPE_DS17285_NVRAM_ADDR_REG 0x50 | ||
385 | #define TODC_TYPE_DS17285_NVRAM_DATA_REG 0x53 | ||
386 | |||
387 | #define TODC_TYPE_MC146818_NVRAM_SIZE 0 /* XXXX */ | ||
388 | #define TODC_TYPE_MC146818_SW_FLAGS 0 | ||
389 | #define TODC_TYPE_MC146818_YEAR 0x09 | ||
390 | #define TODC_TYPE_MC146818_MONTH 0x08 | ||
391 | #define TODC_TYPE_MC146818_DOM 0x07 /* Day of Month */ | ||
392 | #define TODC_TYPE_MC146818_DOW 0x06 /* Day of Week */ | ||
393 | #define TODC_TYPE_MC146818_HOURS 0x04 | ||
394 | #define TODC_TYPE_MC146818_MINUTES 0x02 | ||
395 | #define TODC_TYPE_MC146818_SECONDS 0x00 | ||
396 | #define TODC_TYPE_MC146818_CNTL_B 0x0a | ||
397 | #define TODC_TYPE_MC146818_CNTL_A 0x0b /* control_a R/W regs */ | ||
398 | #define TODC_TYPE_MC146818_WATCHDOG 0 | ||
399 | #define TODC_TYPE_MC146818_INTERRUPTS 0x0c | ||
400 | #define TODC_TYPE_MC146818_ALARM_DATE 0xff | ||
401 | #define TODC_TYPE_MC146818_ALARM_HOUR 0x05 | ||
402 | #define TODC_TYPE_MC146818_ALARM_MINUTES 0x03 | ||
403 | #define TODC_TYPE_MC146818_ALARM_SECONDS 0x01 | ||
404 | #define TODC_TYPE_MC146818_CENTURY 0xff | ||
405 | #define TODC_TYPE_MC146818_FLAGS 0xff | ||
406 | #define TODC_TYPE_MC146818_NVRAM_ADDR_REG 0 | ||
407 | #define TODC_TYPE_MC146818_NVRAM_DATA_REG 0 | ||
408 | |||
409 | #define TODC_TYPE_PC97307_NVRAM_SIZE 0 /* No NVRAM? */ | ||
410 | #define TODC_TYPE_PC97307_SW_FLAGS 0 | ||
411 | #define TODC_TYPE_PC97307_YEAR 0x09 | ||
412 | #define TODC_TYPE_PC97307_MONTH 0x08 | ||
413 | #define TODC_TYPE_PC97307_DOM 0x07 /* Day of Month */ | ||
414 | #define TODC_TYPE_PC97307_DOW 0x06 /* Day of Week */ | ||
415 | #define TODC_TYPE_PC97307_HOURS 0x04 | ||
416 | #define TODC_TYPE_PC97307_MINUTES 0x02 | ||
417 | #define TODC_TYPE_PC97307_SECONDS 0x00 | ||
418 | #define TODC_TYPE_PC97307_CNTL_B 0x0a | ||
419 | #define TODC_TYPE_PC97307_CNTL_A 0x0b /* control_a R/W regs */ | ||
420 | #define TODC_TYPE_PC97307_WATCHDOG 0x0c | ||
421 | #define TODC_TYPE_PC97307_INTERRUPTS 0x0d | ||
422 | #define TODC_TYPE_PC97307_ALARM_DATE 0xff | ||
423 | #define TODC_TYPE_PC97307_ALARM_HOUR 0x05 | ||
424 | #define TODC_TYPE_PC97307_ALARM_MINUTES 0x03 | ||
425 | #define TODC_TYPE_PC97307_ALARM_SECONDS 0x01 | ||
426 | #define TODC_TYPE_PC97307_CENTURY 0xff | ||
427 | #define TODC_TYPE_PC97307_FLAGS 0xff | ||
428 | #define TODC_TYPE_PC97307_NVRAM_ADDR_REG 0 | ||
429 | #define TODC_TYPE_PC97307_NVRAM_DATA_REG 0 | ||
430 | |||
431 | /* | ||
432 | * Define macros to allocate and init the todc_info_t table that will | ||
433 | * be used by the todc_time.c routines. | ||
434 | */ | ||
435 | #define TODC_ALLOC() \ | ||
436 | static todc_info_t todc_info_alloc; \ | ||
437 | todc_info_t *todc_info = &todc_info_alloc; | ||
438 | |||
439 | #define TODC_INIT(clock_type, as0, as1, data, bits) { \ | ||
440 | todc_info->rtc_type = clock_type; \ | ||
441 | \ | ||
442 | todc_info->nvram_as0 = (unsigned int)(as0); \ | ||
443 | todc_info->nvram_as1 = (unsigned int)(as1); \ | ||
444 | todc_info->nvram_data = (unsigned int)(data); \ | ||
445 | \ | ||
446 | todc_info->as0_bits = (bits); \ | ||
447 | \ | ||
448 | todc_info->nvram_size = clock_type ##_NVRAM_SIZE; \ | ||
449 | todc_info->sw_flags = clock_type ##_SW_FLAGS; \ | ||
450 | \ | ||
451 | todc_info->year = clock_type ##_YEAR; \ | ||
452 | todc_info->month = clock_type ##_MONTH; \ | ||
453 | todc_info->day_of_month = clock_type ##_DOM; \ | ||
454 | todc_info->day_of_week = clock_type ##_DOW; \ | ||
455 | todc_info->hours = clock_type ##_HOURS; \ | ||
456 | todc_info->minutes = clock_type ##_MINUTES; \ | ||
457 | todc_info->seconds = clock_type ##_SECONDS; \ | ||
458 | todc_info->control_b = clock_type ##_CNTL_B; \ | ||
459 | todc_info->control_a = clock_type ##_CNTL_A; \ | ||
460 | todc_info->watchdog = clock_type ##_WATCHDOG; \ | ||
461 | todc_info->interrupts = clock_type ##_INTERRUPTS; \ | ||
462 | todc_info->alarm_date = clock_type ##_ALARM_DATE; \ | ||
463 | todc_info->alarm_hour = clock_type ##_ALARM_HOUR; \ | ||
464 | todc_info->alarm_minutes = clock_type ##_ALARM_MINUTES; \ | ||
465 | todc_info->alarm_seconds = clock_type ##_ALARM_SECONDS; \ | ||
466 | todc_info->century = clock_type ##_CENTURY; \ | ||
467 | todc_info->flags = clock_type ##_FLAGS; \ | ||
468 | \ | ||
469 | todc_info->nvram_addr_reg = clock_type ##_NVRAM_ADDR_REG; \ | ||
470 | todc_info->nvram_data_reg = clock_type ##_NVRAM_DATA_REG; \ | ||
471 | } | ||
472 | |||
473 | extern todc_info_t *todc_info; | ||
474 | |||
475 | unsigned char todc_direct_read_val(int addr); | ||
476 | void todc_direct_write_val(int addr, unsigned char val); | ||
477 | unsigned char todc_m48txx_read_val(int addr); | ||
478 | void todc_m48txx_write_val(int addr, unsigned char val); | ||
479 | unsigned char todc_mc146818_read_val(int addr); | ||
480 | void todc_mc146818_write_val(int addr, unsigned char val); | ||
481 | |||
482 | long todc_time_init(void); | ||
483 | void todc_get_rtc_time(struct rtc_time *); | ||
484 | int todc_set_rtc_time(struct rtc_time *); | ||
485 | void todc_calibrate_decr(void); | ||
486 | |||
487 | #endif /* __PPC_KERNEL_TODC_H */ | ||
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index f1d337ed68d5..88320a05f0a8 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h | |||
@@ -14,8 +14,10 @@ | |||
14 | 14 | ||
15 | #ifdef CONFIG_XMON | 15 | #ifdef CONFIG_XMON |
16 | extern void xmon_setup(void); | 16 | extern void xmon_setup(void); |
17 | extern void xmon_register_spus(struct list_head *list); | ||
17 | #else | 18 | #else |
18 | static inline void xmon_setup(void) { }; | 19 | static inline void xmon_setup(void) { }; |
20 | static inline void xmon_register_spus(struct list_head *list) { }; | ||
19 | #endif | 21 | #endif |
20 | 22 | ||
21 | #endif /* __KERNEL __ */ | 23 | #endif /* __KERNEL __ */ |
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index a4c411b753ef..b744baf9e206 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h | |||
@@ -26,17 +26,11 @@ | |||
26 | 26 | ||
27 | #if defined(CONFIG_4xx) | 27 | #if defined(CONFIG_4xx) |
28 | #include <asm/ibm4xx.h> | 28 | #include <asm/ibm4xx.h> |
29 | #elif defined(CONFIG_PPC_MPC52xx) | ||
30 | #include <asm/mpc52xx.h> | ||
31 | #elif defined(CONFIG_8xx) | 29 | #elif defined(CONFIG_8xx) |
32 | #include <asm/mpc8xx.h> | 30 | #include <asm/mpc8xx.h> |
33 | #elif defined(CONFIG_8260) | 31 | #elif defined(CONFIG_8260) |
34 | #include <asm/mpc8260.h> | 32 | #include <asm/mpc8260.h> |
35 | #elif defined(CONFIG_83xx) | 33 | #elif defined(CONFIG_APUS) || !defined(CONFIG_PCI) |
36 | #include <asm/mpc83xx.h> | ||
37 | #elif defined(CONFIG_85xx) | ||
38 | #include <asm/mpc85xx.h> | ||
39 | #elif defined(CONFIG_APUS) | ||
40 | #define _IO_BASE 0 | 34 | #define _IO_BASE 0 |
41 | #define _ISA_MEM_BASE 0 | 35 | #define _ISA_MEM_BASE 0 |
42 | #define PCI_DRAM_OFFSET 0 | 36 | #define PCI_DRAM_OFFSET 0 |
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h index 64c8874618dc..d9d21aa68ba3 100644 --- a/include/asm-ppc/mpc52xx.h +++ b/include/asm-ppc/mpc52xx.h | |||
@@ -29,17 +29,6 @@ struct pt_regs; | |||
29 | #endif /* __ASSEMBLY__ */ | 29 | #endif /* __ASSEMBLY__ */ |
30 | 30 | ||
31 | 31 | ||
32 | #ifdef CONFIG_PCI | ||
33 | #define _IO_BASE isa_io_base | ||
34 | #define _ISA_MEM_BASE isa_mem_base | ||
35 | #define PCI_DRAM_OFFSET pci_dram_offset | ||
36 | #else | ||
37 | #define _IO_BASE 0 | ||
38 | #define _ISA_MEM_BASE 0 | ||
39 | #define PCI_DRAM_OFFSET 0 | ||
40 | #endif | ||
41 | |||
42 | |||
43 | /* ======================================================================== */ | 32 | /* ======================================================================== */ |
44 | /* PPC Sys devices definition */ | 33 | /* PPC Sys devices definition */ |
45 | /* ======================================================================== */ | 34 | /* ======================================================================== */ |
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h index 02ed2c325714..c3061972309b 100644 --- a/include/asm-ppc/mpc83xx.h +++ b/include/asm-ppc/mpc83xx.h | |||
@@ -25,14 +25,6 @@ | |||
25 | #include <platforms/83xx/mpc834x_sys.h> | 25 | #include <platforms/83xx/mpc834x_sys.h> |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #define _IO_BASE isa_io_base | ||
29 | #define _ISA_MEM_BASE isa_mem_base | ||
30 | #ifdef CONFIG_PCI | ||
31 | #define PCI_DRAM_OFFSET pci_dram_offset | ||
32 | #else | ||
33 | #define PCI_DRAM_OFFSET 0 | ||
34 | #endif | ||
35 | |||
36 | /* | 28 | /* |
37 | * The "residual" board information structure the boot loader passes | 29 | * The "residual" board information structure the boot loader passes |
38 | * into the kernel. | 30 | * into the kernel. |
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h index 9b4851199c76..d7e4a79d77fb 100644 --- a/include/asm-ppc/mpc85xx.h +++ b/include/asm-ppc/mpc85xx.h | |||
@@ -44,14 +44,6 @@ | |||
44 | #include <platforms/85xx/tqm85xx.h> | 44 | #include <platforms/85xx/tqm85xx.h> |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | #define _IO_BASE isa_io_base | ||
48 | #define _ISA_MEM_BASE isa_mem_base | ||
49 | #ifdef CONFIG_PCI | ||
50 | #define PCI_DRAM_OFFSET pci_dram_offset | ||
51 | #else | ||
52 | #define PCI_DRAM_OFFSET 0 | ||
53 | #endif | ||
54 | |||
55 | /* | 47 | /* |
56 | * The "residual" board information structure the boot loader passes | 48 | * The "residual" board information structure the boot loader passes |
57 | * into the kernel. | 49 | * into the kernel. |
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 3fef7d67aedc..f02d71bf6894 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h | |||
@@ -33,6 +33,14 @@ struct cpu { | |||
33 | 33 | ||
34 | extern int register_cpu(struct cpu *cpu, int num); | 34 | extern int register_cpu(struct cpu *cpu, int num); |
35 | extern struct sys_device *get_cpu_sysdev(unsigned cpu); | 35 | extern struct sys_device *get_cpu_sysdev(unsigned cpu); |
36 | |||
37 | extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr); | ||
38 | extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr); | ||
39 | |||
40 | extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs); | ||
41 | extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs); | ||
42 | |||
43 | |||
36 | #ifdef CONFIG_HOTPLUG_CPU | 44 | #ifdef CONFIG_HOTPLUG_CPU |
37 | extern void unregister_cpu(struct cpu *cpu); | 45 | extern void unregister_cpu(struct cpu *cpu); |
38 | #endif | 46 | #endif |