aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/prom
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-11-30 01:16:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:17 -0500
commit5de18cde3b748aafc6d187d7655ba42f2260501d (patch)
treefa4805081e6663b10be678c924a0adc3c7a95107 /arch/sparc/prom
parent708d4f09647106d549c646dc459c7ccf2c237cc8 (diff)
sparc,sparc64: unify prom/
- all files with identical names copied and renamed to *_64.c - the remaning files copied as is - added sparc64 specific files to sparc/prom/Makefile - teach sparc64 Makefile to look into sparc/prom/ - delete unused Makefile from sparc64/prom/ linking order was not kept for sparc64 with this change. It was not possible to keep linking order for both sparc and sparc64 and as sparc64 see more testing than sparc it was natural to break linking order on sparc64. Should it have any effect it would be detected sooner this way. printf_32.c and printf_64.c are obvious candidates to be merged but they are not 100% equal so that was left for later Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/prom')
-rw-r--r--arch/sparc/prom/Makefile4
-rw-r--r--arch/sparc/prom/bootstr_64.c40
-rw-r--r--arch/sparc/prom/cif.S48
-rw-r--r--arch/sparc/prom/console_64.c74
-rw-r--r--arch/sparc/prom/devops_64.c41
-rw-r--r--arch/sparc/prom/init_64.c57
-rw-r--r--arch/sparc/prom/misc_64.c335
-rw-r--r--arch/sparc/prom/p1275.c151
-rw-r--r--arch/sparc/prom/printf_64.c47
-rw-r--r--arch/sparc/prom/tree_64.c299
10 files changed, 1096 insertions, 0 deletions
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
index 74ca9cceaeea..f8e0278b8b4f 100644
--- a/arch/sparc/prom/Makefile
+++ b/arch/sparc/prom/Makefile
@@ -1,6 +1,8 @@
1# Makefile for the Sun Boot PROM interface library under 1# Makefile for the Sun Boot PROM interface library under
2# Linux. 2# Linux.
3# 3#
4asflags := -ansi
5ccflags := -Werror
4 6
5lib-y := bootstr_$(BITS).o 7lib-y := bootstr_$(BITS).o
6lib-$(CONFIG_SPARC32) += devmap.o 8lib-$(CONFIG_SPARC32) += devmap.o
@@ -15,3 +17,5 @@ lib-$(CONFIG_SPARC32) += segment.o
15lib-y += console_$(BITS).o 17lib-y += console_$(BITS).o
16lib-y += printf_$(BITS).o 18lib-y += printf_$(BITS).o
17lib-y += tree_$(BITS).o 19lib-y += tree_$(BITS).o
20lib-$(CONFIG_SPARC64) += p1275.o
21lib-$(CONFIG_SPARC64) += cif.o
diff --git a/arch/sparc/prom/bootstr_64.c b/arch/sparc/prom/bootstr_64.c
new file mode 100644
index 000000000000..ab9ccc63b388
--- /dev/null
+++ b/arch/sparc/prom/bootstr_64.c
@@ -0,0 +1,40 @@
1/*
2 * bootstr.c: Boot string/argument acquisition from the PROM.
3 *
4 * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright(C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 */
7
8#include <linux/string.h>
9#include <linux/init.h>
10#include <asm/oplib.h>
11
12/* WARNING: The boot loader knows that these next three variables come one right
13 * after another in the .data section. Do not move this stuff into
14 * the .bss section or it will break things.
15 */
16
17#define BARG_LEN 256
18struct {
19 int bootstr_len;
20 int bootstr_valid;
21 char bootstr_buf[BARG_LEN];
22} bootstr_info = {
23 .bootstr_len = BARG_LEN,
24#ifdef CONFIG_CMDLINE
25 .bootstr_valid = 1,
26 .bootstr_buf = CONFIG_CMDLINE,
27#endif
28};
29
30char * __init
31prom_getbootargs(void)
32{
33 /* This check saves us from a panic when bootfd patches args. */
34 if (bootstr_info.bootstr_valid)
35 return bootstr_info.bootstr_buf;
36 prom_getstring(prom_chosen_node, "bootargs",
37 bootstr_info.bootstr_buf, BARG_LEN);
38 bootstr_info.bootstr_valid = 1;
39 return bootstr_info.bootstr_buf;
40}
diff --git a/arch/sparc/prom/cif.S b/arch/sparc/prom/cif.S
new file mode 100644
index 000000000000..5f27ad779c0c
--- /dev/null
+++ b/arch/sparc/prom/cif.S
@@ -0,0 +1,48 @@
1/* cif.S: PROM entry/exit assembler trampolines.
2 *
3 * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
4 * Copyright (C) 2005, 2006 David S. Miller <davem@davemloft.net>
5 */
6
7#include <asm/pstate.h>
8#include <asm/cpudata.h>
9#include <asm/thread_info.h>
10
11 .text
12 .globl prom_cif_interface
13prom_cif_interface:
14 sethi %hi(p1275buf), %o0
15 or %o0, %lo(p1275buf), %o0
16 ldx [%o0 + 0x010], %o1 ! prom_cif_stack
17 save %o1, -192, %sp
18 ldx [%i0 + 0x008], %l2 ! prom_cif_handler
19 mov %g4, %l0
20 mov %g5, %l1
21 mov %g6, %l3
22 call %l2
23 add %i0, 0x018, %o0 ! prom_args
24 mov %l0, %g4
25 mov %l1, %g5
26 mov %l3, %g6
27 ret
28 restore
29
30 .globl prom_cif_callback
31prom_cif_callback:
32 sethi %hi(p1275buf), %o1
33 or %o1, %lo(p1275buf), %o1
34 save %sp, -192, %sp
35 TRAP_LOAD_THREAD_REG(%g6, %g1)
36 LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %o0)
37 ldx [%g6 + TI_TASK], %g4
38 call prom_world
39 mov 0, %o0
40 ldx [%i1 + 0x000], %l2
41 call %l2
42 mov %i0, %o0
43 mov %o0, %l1
44 call prom_world
45 mov 1, %o0
46 ret
47 restore %l1, 0, %o0
48
diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c
new file mode 100644
index 000000000000..e1c3fc87484d
--- /dev/null
+++ b/arch/sparc/prom/console_64.c
@@ -0,0 +1,74 @@
1/* console.c: Routines that deal with sending and receiving IO
2 * to/from the current console device using the PROM.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
5 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 */
7
8#include <linux/types.h>
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <asm/openprom.h>
12#include <asm/oplib.h>
13#include <asm/system.h>
14#include <linux/string.h>
15
16extern int prom_stdin, prom_stdout;
17
18/* Non blocking get character from console input device, returns -1
19 * if no input was taken. This can be used for polling.
20 */
21inline int
22prom_nbgetchar(void)
23{
24 char inc;
25
26 if (p1275_cmd("read", P1275_ARG(1,P1275_ARG_OUT_BUF)|
27 P1275_INOUT(3,1),
28 prom_stdin, &inc, P1275_SIZE(1)) == 1)
29 return inc;
30 else
31 return -1;
32}
33
34/* Non blocking put character to console device, returns -1 if
35 * unsuccessful.
36 */
37inline int
38prom_nbputchar(char c)
39{
40 char outc;
41
42 outc = c;
43 if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
44 P1275_INOUT(3,1),
45 prom_stdout, &outc, P1275_SIZE(1)) == 1)
46 return 0;
47 else
48 return -1;
49}
50
51/* Blocking version of get character routine above. */
52char
53prom_getchar(void)
54{
55 int character;
56 while((character = prom_nbgetchar()) == -1) ;
57 return (char) character;
58}
59
60/* Blocking version of put character routine above. */
61void
62prom_putchar(char c)
63{
64 prom_nbputchar(c);
65 return;
66}
67
68void
69prom_puts(const char *s, int len)
70{
71 p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
72 P1275_INOUT(3,1),
73 prom_stdout, s, P1275_SIZE(len));
74}
diff --git a/arch/sparc/prom/devops_64.c b/arch/sparc/prom/devops_64.c
new file mode 100644
index 000000000000..9dbd803e46e1
--- /dev/null
+++ b/arch/sparc/prom/devops_64.c
@@ -0,0 +1,41 @@
1/*
2 * devops.c: Device operations using the PROM.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 */
7#include <linux/types.h>
8#include <linux/kernel.h>
9#include <linux/sched.h>
10
11#include <asm/openprom.h>
12#include <asm/oplib.h>
13
14/* Open the device described by the string 'dstr'. Returns the handle
15 * to that device used for subsequent operations on that device.
16 * Returns 0 on failure.
17 */
18int
19prom_devopen(const char *dstr)
20{
21 return p1275_cmd ("open", P1275_ARG(0,P1275_ARG_IN_STRING)|
22 P1275_INOUT(1,1),
23 dstr);
24}
25
26/* Close the device described by device handle 'dhandle'. */
27int
28prom_devclose(int dhandle)
29{
30 p1275_cmd ("close", P1275_INOUT(1,0), dhandle);
31 return 0;
32}
33
34/* Seek to specified location described by 'seekhi' and 'seeklo'
35 * for device 'dhandle'.
36 */
37void
38prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
39{
40 p1275_cmd ("seek", P1275_INOUT(3,1), dhandle, seekhi, seeklo);
41}
diff --git a/arch/sparc/prom/init_64.c b/arch/sparc/prom/init_64.c
new file mode 100644
index 000000000000..7b00f89490a4
--- /dev/null
+++ b/arch/sparc/prom/init_64.c
@@ -0,0 +1,57 @@
1/*
2 * init.c: Initialize internal variables used by the PROM
3 * library functions.
4 *
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/string.h>
12#include <linux/ctype.h>
13
14#include <asm/openprom.h>
15#include <asm/oplib.h>
16
17/* OBP version string. */
18char prom_version[80];
19
20/* The root node of the prom device tree. */
21int prom_stdin, prom_stdout;
22int prom_chosen_node;
23
24/* You must call prom_init() before you attempt to use any of the
25 * routines in the prom library. It returns 0 on success, 1 on
26 * failure. It gets passed the pointer to the PROM vector.
27 */
28
29extern void prom_cif_init(void *, void *);
30
31void __init prom_init(void *cif_handler, void *cif_stack)
32{
33 int node;
34
35 prom_cif_init(cif_handler, cif_stack);
36
37 prom_chosen_node = prom_finddevice(prom_chosen_path);
38 if (!prom_chosen_node || prom_chosen_node == -1)
39 prom_halt();
40
41 prom_stdin = prom_getint(prom_chosen_node, "stdin");
42 prom_stdout = prom_getint(prom_chosen_node, "stdout");
43
44 node = prom_finddevice("/openprom");
45 if (!node || node == -1)
46 prom_halt();
47
48 prom_getstring(node, "version", prom_version, sizeof(prom_version));
49
50 prom_printf("\n");
51}
52
53void __init prom_init_report(void)
54{
55 printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version);
56 printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible);
57}
diff --git a/arch/sparc/prom/misc_64.c b/arch/sparc/prom/misc_64.c
new file mode 100644
index 000000000000..9b0c0760901e
--- /dev/null
+++ b/arch/sparc/prom/misc_64.c
@@ -0,0 +1,335 @@
1/*
2 * misc.c: Miscellaneous prom functions that don't belong
3 * anywhere else.
4 *
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 */
8
9#include <linux/types.h>
10#include <linux/kernel.h>
11#include <linux/sched.h>
12#include <linux/interrupt.h>
13#include <linux/delay.h>
14#include <asm/openprom.h>
15#include <asm/oplib.h>
16#include <asm/system.h>
17#include <asm/ldc.h>
18
19int prom_service_exists(const char *service_name)
20{
21 int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) |
22 P1275_INOUT(1, 1), service_name);
23
24 if (err)
25 return 0;
26 return 1;
27}
28
29void prom_sun4v_guest_soft_state(void)
30{
31 const char *svc = "SUNW,soft-state-supported";
32
33 if (!prom_service_exists(svc))
34 return;
35 p1275_cmd(svc, P1275_INOUT(0, 0));
36}
37
38/* Reset and reboot the machine with the command 'bcommand'. */
39void prom_reboot(const char *bcommand)
40{
41#ifdef CONFIG_SUN_LDOMS
42 if (ldom_domaining_enabled)
43 ldom_reboot(bcommand);
44#endif
45 p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
46 P1275_INOUT(1, 0), bcommand);
47}
48
49/* Forth evaluate the expression contained in 'fstring'. */
50void prom_feval(const char *fstring)
51{
52 if (!fstring || fstring[0] == 0)
53 return;
54 p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
55 P1275_INOUT(1, 1), fstring);
56}
57
58#ifdef CONFIG_SMP
59extern void smp_capture(void);
60extern void smp_release(void);
61#endif
62
63/* Drop into the prom, with the chance to continue with the 'go'
64 * prom command.
65 */
66void prom_cmdline(void)
67{
68 unsigned long flags;
69
70 local_irq_save(flags);
71
72#ifdef CONFIG_SMP
73 smp_capture();
74#endif
75
76 p1275_cmd("enter", P1275_INOUT(0, 0));
77
78#ifdef CONFIG_SMP
79 smp_release();
80#endif
81
82 local_irq_restore(flags);
83}
84
85/* Drop into the prom, but completely terminate the program.
86 * No chance of continuing.
87 */
88void prom_halt(void)
89{
90#ifdef CONFIG_SUN_LDOMS
91 if (ldom_domaining_enabled)
92 ldom_power_off();
93#endif
94again:
95 p1275_cmd("exit", P1275_INOUT(0, 0));
96 goto again; /* PROM is out to get me -DaveM */
97}
98
99void prom_halt_power_off(void)
100{
101#ifdef CONFIG_SUN_LDOMS
102 if (ldom_domaining_enabled)
103 ldom_power_off();
104#endif
105 p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
106
107 /* if nothing else helps, we just halt */
108 prom_halt();
109}
110
111/* Set prom sync handler to call function 'funcp'. */
112void prom_setcallback(callback_func_t funcp)
113{
114 if (!funcp)
115 return;
116 p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
117 P1275_INOUT(1, 1), funcp);
118}
119
120/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
121 * format type. 'num_bytes' is the number of bytes that your idbuf
122 * has space for. Returns 0xff on error.
123 */
124unsigned char prom_get_idprom(char *idbuf, int num_bytes)
125{
126 int len;
127
128 len = prom_getproplen(prom_root_node, "idprom");
129 if ((len >num_bytes) || (len == -1))
130 return 0xff;
131 if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
132 return idbuf[0];
133
134 return 0xff;
135}
136
137int prom_get_mmu_ihandle(void)
138{
139 int node, ret;
140
141 if (prom_mmu_ihandle_cache != 0)
142 return prom_mmu_ihandle_cache;
143
144 node = prom_finddevice(prom_chosen_path);
145 ret = prom_getint(node, prom_mmu_name);
146 if (ret == -1 || ret == 0)
147 prom_mmu_ihandle_cache = -1;
148 else
149 prom_mmu_ihandle_cache = ret;
150
151 return ret;
152}
153
154static int prom_get_memory_ihandle(void)
155{
156 static int memory_ihandle_cache;
157 int node, ret;
158
159 if (memory_ihandle_cache != 0)
160 return memory_ihandle_cache;
161
162 node = prom_finddevice("/chosen");
163 ret = prom_getint(node, "memory");
164 if (ret == -1 || ret == 0)
165 memory_ihandle_cache = -1;
166 else
167 memory_ihandle_cache = ret;
168
169 return ret;
170}
171
172/* Load explicit I/D TLB entries. */
173long prom_itlb_load(unsigned long index,
174 unsigned long tte_data,
175 unsigned long vaddr)
176{
177 return p1275_cmd(prom_callmethod_name,
178 (P1275_ARG(0, P1275_ARG_IN_STRING) |
179 P1275_ARG(2, P1275_ARG_IN_64B) |
180 P1275_ARG(3, P1275_ARG_IN_64B) |
181 P1275_INOUT(5, 1)),
182 "SUNW,itlb-load",
183 prom_get_mmu_ihandle(),
184 /* And then our actual args are pushed backwards. */
185 vaddr,
186 tte_data,
187 index);
188}
189
190long prom_dtlb_load(unsigned long index,
191 unsigned long tte_data,
192 unsigned long vaddr)
193{
194 return p1275_cmd(prom_callmethod_name,
195 (P1275_ARG(0, P1275_ARG_IN_STRING) |
196 P1275_ARG(2, P1275_ARG_IN_64B) |
197 P1275_ARG(3, P1275_ARG_IN_64B) |
198 P1275_INOUT(5, 1)),
199 "SUNW,dtlb-load",
200 prom_get_mmu_ihandle(),
201 /* And then our actual args are pushed backwards. */
202 vaddr,
203 tte_data,
204 index);
205}
206
207int prom_map(int mode, unsigned long size,
208 unsigned long vaddr, unsigned long paddr)
209{
210 int ret = p1275_cmd(prom_callmethod_name,
211 (P1275_ARG(0, P1275_ARG_IN_STRING) |
212 P1275_ARG(3, P1275_ARG_IN_64B) |
213 P1275_ARG(4, P1275_ARG_IN_64B) |
214 P1275_ARG(6, P1275_ARG_IN_64B) |
215 P1275_INOUT(7, 1)),
216 prom_map_name,
217 prom_get_mmu_ihandle(),
218 mode,
219 size,
220 vaddr,
221 0,
222 paddr);
223
224 if (ret == 0)
225 ret = -1;
226 return ret;
227}
228
229void prom_unmap(unsigned long size, unsigned long vaddr)
230{
231 p1275_cmd(prom_callmethod_name,
232 (P1275_ARG(0, P1275_ARG_IN_STRING) |
233 P1275_ARG(2, P1275_ARG_IN_64B) |
234 P1275_ARG(3, P1275_ARG_IN_64B) |
235 P1275_INOUT(4, 0)),
236 prom_unmap_name,
237 prom_get_mmu_ihandle(),
238 size,
239 vaddr);
240}
241
242/* Set aside physical memory which is not touched or modified
243 * across soft resets.
244 */
245unsigned long prom_retain(const char *name,
246 unsigned long pa_low, unsigned long pa_high,
247 long size, long align)
248{
249 /* XXX I don't think we return multiple values correctly.
250 * XXX OBP supposedly returns pa_low/pa_high here, how does
251 * XXX it work?
252 */
253
254 /* If align is zero, the pa_low/pa_high args are passed,
255 * else they are not.
256 */
257 if (align == 0)
258 return p1275_cmd("SUNW,retain",
259 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
260 name, pa_low, pa_high, size, align);
261 else
262 return p1275_cmd("SUNW,retain",
263 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
264 name, size, align);
265}
266
267/* Get "Unumber" string for the SIMM at the given
268 * memory address. Usually this will be of the form
269 * "Uxxxx" where xxxx is a decimal number which is
270 * etched into the motherboard next to the SIMM slot
271 * in question.
272 */
273int prom_getunumber(int syndrome_code,
274 unsigned long phys_addr,
275 char *buf, int buflen)
276{
277 return p1275_cmd(prom_callmethod_name,
278 (P1275_ARG(0, P1275_ARG_IN_STRING) |
279 P1275_ARG(3, P1275_ARG_OUT_BUF) |
280 P1275_ARG(6, P1275_ARG_IN_64B) |
281 P1275_INOUT(8, 2)),
282 "SUNW,get-unumber", prom_get_memory_ihandle(),
283 buflen, buf, P1275_SIZE(buflen),
284 0, phys_addr, syndrome_code);
285}
286
287/* Power management extensions. */
288void prom_sleepself(void)
289{
290 p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
291}
292
293int prom_sleepsystem(void)
294{
295 return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
296}
297
298int prom_wakeupsystem(void)
299{
300 return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
301}
302
303#ifdef CONFIG_SMP
304void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
305{
306 p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
307}
308
309void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
310{
311 p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
312 cpuid, pc, arg);
313}
314
315void prom_stopcpu_cpuid(int cpuid)
316{
317 p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
318 cpuid);
319}
320
321void prom_stopself(void)
322{
323 p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
324}
325
326void prom_idleself(void)
327{
328 p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
329}
330
331void prom_resumecpu(int cpunode)
332{
333 p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
334}
335#endif
diff --git a/arch/sparc/prom/p1275.c b/arch/sparc/prom/p1275.c
new file mode 100644
index 000000000000..4b7c937bba61
--- /dev/null
+++ b/arch/sparc/prom/p1275.c
@@ -0,0 +1,151 @@
1/*
2 * p1275.c: Sun IEEE 1275 PROM low level interface routines
3 *
4 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
5 */
6
7#include <linux/kernel.h>
8#include <linux/init.h>
9#include <linux/sched.h>
10#include <linux/smp.h>
11#include <linux/string.h>
12#include <linux/spinlock.h>
13
14#include <asm/openprom.h>
15#include <asm/oplib.h>
16#include <asm/system.h>
17#include <asm/spitfire.h>
18#include <asm/pstate.h>
19#include <asm/ldc.h>
20
21struct {
22 long prom_callback; /* 0x00 */
23 void (*prom_cif_handler)(long *); /* 0x08 */
24 unsigned long prom_cif_stack; /* 0x10 */
25 unsigned long prom_args [23]; /* 0x18 */
26 char prom_buffer [3000];
27} p1275buf;
28
29extern void prom_world(int);
30
31extern void prom_cif_interface(void);
32extern void prom_cif_callback(void);
33
34/*
35 * This provides SMP safety on the p1275buf. prom_callback() drops this lock
36 * to allow recursuve acquisition.
37 */
38DEFINE_SPINLOCK(prom_entry_lock);
39
40long p1275_cmd(const char *service, long fmt, ...)
41{
42 char *p, *q;
43 unsigned long flags;
44 int nargs, nrets, i;
45 va_list list;
46 long attrs, x;
47
48 p = p1275buf.prom_buffer;
49
50 spin_lock_irqsave(&prom_entry_lock, flags);
51
52 p1275buf.prom_args[0] = (unsigned long)p; /* service */
53 strcpy (p, service);
54 p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
55 p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */
56 p1275buf.prom_args[2] = nrets = ((fmt & 0xf0) >> 4); /* nrets */
57 attrs = fmt >> 8;
58 va_start(list, fmt);
59 for (i = 0; i < nargs; i++, attrs >>= 3) {
60 switch (attrs & 0x7) {
61 case P1275_ARG_NUMBER:
62 p1275buf.prom_args[i + 3] =
63 (unsigned)va_arg(list, long);
64 break;
65 case P1275_ARG_IN_64B:
66 p1275buf.prom_args[i + 3] =
67 va_arg(list, unsigned long);
68 break;
69 case P1275_ARG_IN_STRING:
70 strcpy (p, va_arg(list, char *));
71 p1275buf.prom_args[i + 3] = (unsigned long)p;
72 p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
73 break;
74 case P1275_ARG_OUT_BUF:
75 (void) va_arg(list, char *);
76 p1275buf.prom_args[i + 3] = (unsigned long)p;
77 x = va_arg(list, long);
78 i++; attrs >>= 3;
79 p = (char *)(((long)(p + (int)x + 7)) & ~7);
80 p1275buf.prom_args[i + 3] = x;
81 break;
82 case P1275_ARG_IN_BUF:
83 q = va_arg(list, char *);
84 p1275buf.prom_args[i + 3] = (unsigned long)p;
85 x = va_arg(list, long);
86 i++; attrs >>= 3;
87 memcpy (p, q, (int)x);
88 p = (char *)(((long)(p + (int)x + 7)) & ~7);
89 p1275buf.prom_args[i + 3] = x;
90 break;
91 case P1275_ARG_OUT_32B:
92 (void) va_arg(list, char *);
93 p1275buf.prom_args[i + 3] = (unsigned long)p;
94 p += 32;
95 break;
96 case P1275_ARG_IN_FUNCTION:
97 p1275buf.prom_args[i + 3] =
98 (unsigned long)prom_cif_callback;
99 p1275buf.prom_callback = va_arg(list, long);
100 break;
101 }
102 }
103 va_end(list);
104
105 prom_world(1);
106 prom_cif_interface();
107 prom_world(0);
108
109 attrs = fmt >> 8;
110 va_start(list, fmt);
111 for (i = 0; i < nargs; i++, attrs >>= 3) {
112 switch (attrs & 0x7) {
113 case P1275_ARG_NUMBER:
114 (void) va_arg(list, long);
115 break;
116 case P1275_ARG_IN_STRING:
117 (void) va_arg(list, char *);
118 break;
119 case P1275_ARG_IN_FUNCTION:
120 (void) va_arg(list, long);
121 break;
122 case P1275_ARG_IN_BUF:
123 (void) va_arg(list, char *);
124 (void) va_arg(list, long);
125 i++; attrs >>= 3;
126 break;
127 case P1275_ARG_OUT_BUF:
128 p = va_arg(list, char *);
129 x = va_arg(list, long);
130 memcpy (p, (char *)(p1275buf.prom_args[i + 3]), (int)x);
131 i++; attrs >>= 3;
132 break;
133 case P1275_ARG_OUT_32B:
134 p = va_arg(list, char *);
135 memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
136 break;
137 }
138 }
139 va_end(list);
140 x = p1275buf.prom_args [nargs + 3];
141
142 spin_unlock_irqrestore(&prom_entry_lock, flags);
143
144 return x;
145}
146
147void prom_cif_init(void *cif_handler, void *cif_stack)
148{
149 p1275buf.prom_cif_handler = (void (*)(long *))cif_handler;
150 p1275buf.prom_cif_stack = (unsigned long)cif_stack;
151}
diff --git a/arch/sparc/prom/printf_64.c b/arch/sparc/prom/printf_64.c
new file mode 100644
index 000000000000..660943ee4c2a
--- /dev/null
+++ b/arch/sparc/prom/printf_64.c
@@ -0,0 +1,47 @@
1/*
2 * printf.c: Internal prom library printf facility.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
6 * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
7 *
8 * We used to warn all over the code: DO NOT USE prom_printf(),
9 * and yet people do. Anton's banking code was outputting banks
10 * with prom_printf for most of the 2.4 lifetime. Since an effective
11 * stick is not available, we deployed a carrot: an early printk
12 * through PROM by means of -p boot option. This ought to fix it.
13 * USE printk; if you need, deploy -p.
14 */
15
16#include <linux/kernel.h>
17
18#include <asm/openprom.h>
19#include <asm/oplib.h>
20
21static char ppbuf[1024];
22
23void
24prom_write(const char *buf, unsigned int n)
25{
26 char ch;
27
28 while (n != 0) {
29 --n;
30 if ((ch = *buf++) == '\n')
31 prom_putchar('\r');
32 prom_putchar(ch);
33 }
34}
35
36void
37prom_printf(const char *fmt, ...)
38{
39 va_list args;
40 int i;
41
42 va_start(args, fmt);
43 i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
44 va_end(args);
45
46 prom_write(ppbuf, i);
47}
diff --git a/arch/sparc/prom/tree_64.c b/arch/sparc/prom/tree_64.c
new file mode 100644
index 000000000000..281aea44790b
--- /dev/null
+++ b/arch/sparc/prom/tree_64.c
@@ -0,0 +1,299 @@
1/*
2 * tree.c: Basic device tree traversal/scanning for the Linux
3 * prom library.
4 *
5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7 */
8
9#include <linux/string.h>
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/sched.h>
13
14#include <asm/openprom.h>
15#include <asm/oplib.h>
16#include <asm/ldc.h>
17
18/* Return the child of node 'node' or zero if no this node has no
19 * direct descendent.
20 */
21inline int __prom_getchild(int node)
22{
23 return p1275_cmd ("child", P1275_INOUT(1, 1), node);
24}
25
26inline int prom_getchild(int node)
27{
28 int cnode;
29
30 if(node == -1) return 0;
31 cnode = __prom_getchild(node);
32 if(cnode == -1) return 0;
33 return (int)cnode;
34}
35
36inline int prom_getparent(int node)
37{
38 int cnode;
39
40 if(node == -1) return 0;
41 cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
42 if(cnode == -1) return 0;
43 return (int)cnode;
44}
45
46/* Return the next sibling of node 'node' or zero if no more siblings
47 * at this level of depth in the tree.
48 */
49inline int __prom_getsibling(int node)
50{
51 return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
52}
53
54inline int prom_getsibling(int node)
55{
56 int sibnode;
57
58 if (node == -1)
59 return 0;
60 sibnode = __prom_getsibling(node);
61 if (sibnode == -1)
62 return 0;
63
64 return sibnode;
65}
66
67/* Return the length in bytes of property 'prop' at node 'node'.
68 * Return -1 on error.
69 */
70inline int prom_getproplen(int node, const char *prop)
71{
72 if((!node) || (!prop)) return -1;
73 return p1275_cmd ("getproplen",
74 P1275_ARG(1,P1275_ARG_IN_STRING)|
75 P1275_INOUT(2, 1),
76 node, prop);
77}
78
79/* Acquire a property 'prop' at node 'node' and place it in
80 * 'buffer' which has a size of 'bufsize'. If the acquisition
81 * was successful the length will be returned, else -1 is returned.
82 */
83inline int prom_getproperty(int node, const char *prop,
84 char *buffer, int bufsize)
85{
86 int plen;
87
88 plen = prom_getproplen(node, prop);
89 if ((plen > bufsize) || (plen == 0) || (plen == -1)) {
90 return -1;
91 } else {
92 /* Ok, things seem all right. */
93 return p1275_cmd(prom_getprop_name,
94 P1275_ARG(1,P1275_ARG_IN_STRING)|
95 P1275_ARG(2,P1275_ARG_OUT_BUF)|
96 P1275_INOUT(4, 1),
97 node, prop, buffer, P1275_SIZE(plen));
98 }
99}
100
101/* Acquire an integer property and return its value. Returns -1
102 * on failure.
103 */
104inline int prom_getint(int node, const char *prop)
105{
106 int intprop;
107
108 if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
109 return intprop;
110
111 return -1;
112}
113
114/* Acquire an integer property, upon error return the passed default
115 * integer.
116 */
117
118int prom_getintdefault(int node, const char *property, int deflt)
119{
120 int retval;
121
122 retval = prom_getint(node, property);
123 if(retval == -1) return deflt;
124
125 return retval;
126}
127
128/* Acquire a boolean property, 1=TRUE 0=FALSE. */
129int prom_getbool(int node, const char *prop)
130{
131 int retval;
132
133 retval = prom_getproplen(node, prop);
134 if(retval == -1) return 0;
135 return 1;
136}
137
138/* Acquire a property whose value is a string, returns a null
139 * string on error. The char pointer is the user supplied string
140 * buffer.
141 */
142void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
143{
144 int len;
145
146 len = prom_getproperty(node, prop, user_buf, ubuf_size);
147 if(len != -1) return;
148 user_buf[0] = 0;
149 return;
150}
151
152
153/* Does the device at node 'node' have name 'name'?
154 * YES = 1 NO = 0
155 */
156int prom_nodematch(int node, const char *name)
157{
158 char namebuf[128];
159 prom_getproperty(node, "name", namebuf, sizeof(namebuf));
160 if(strcmp(namebuf, name) == 0) return 1;
161 return 0;
162}
163
164/* Search siblings at 'node_start' for a node with name
165 * 'nodename'. Return node if successful, zero if not.
166 */
167int prom_searchsiblings(int node_start, const char *nodename)
168{
169
170 int thisnode, error;
171 char promlib_buf[128];
172
173 for(thisnode = node_start; thisnode;
174 thisnode=prom_getsibling(thisnode)) {
175 error = prom_getproperty(thisnode, "name", promlib_buf,
176 sizeof(promlib_buf));
177 /* Should this ever happen? */
178 if(error == -1) continue;
179 if(strcmp(nodename, promlib_buf)==0) return thisnode;
180 }
181
182 return 0;
183}
184
185/* Return the first property type for node 'node'.
186 * buffer should be at least 32B in length
187 */
188inline char *prom_firstprop(int node, char *buffer)
189{
190 *buffer = 0;
191 if(node == -1) return buffer;
192 p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
193 P1275_INOUT(3, 0),
194 node, (char *) 0x0, buffer);
195 return buffer;
196}
197
198/* Return the property type string after property type 'oprop'
199 * at node 'node' . Returns NULL string if no more
200 * property types for this node.
201 */
202inline char *prom_nextprop(int node, const char *oprop, char *buffer)
203{
204 char buf[32];
205
206 if(node == -1) {
207 *buffer = 0;
208 return buffer;
209 }
210 if (oprop == buffer) {
211 strcpy (buf, oprop);
212 oprop = buf;
213 }
214 p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
215 P1275_ARG(2,P1275_ARG_OUT_32B)|
216 P1275_INOUT(3, 0),
217 node, oprop, buffer);
218 return buffer;
219}
220
221int
222prom_finddevice(const char *name)
223{
224 if (!name)
225 return 0;
226 return p1275_cmd(prom_finddev_name,
227 P1275_ARG(0,P1275_ARG_IN_STRING)|
228 P1275_INOUT(1, 1),
229 name);
230}
231
232int prom_node_has_property(int node, const char *prop)
233{
234 char buf [32];
235
236 *buf = 0;
237 do {
238 prom_nextprop(node, buf, buf);
239 if(!strcmp(buf, prop))
240 return 1;
241 } while (*buf);
242 return 0;
243}
244
245/* Set property 'pname' at node 'node' to value 'value' which has a length
246 * of 'size' bytes. Return the number of bytes the prom accepted.
247 */
248int
249prom_setprop(int node, const char *pname, char *value, int size)
250{
251 if (size == 0)
252 return 0;
253 if ((pname == 0) || (value == 0))
254 return 0;
255
256#ifdef CONFIG_SUN_LDOMS
257 if (ldom_domaining_enabled) {
258 ldom_set_var(pname, value);
259 return 0;
260 }
261#endif
262 return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
263 P1275_ARG(2,P1275_ARG_IN_BUF)|
264 P1275_INOUT(4, 1),
265 node, pname, value, P1275_SIZE(size));
266}
267
268inline int prom_inst2pkg(int inst)
269{
270 int node;
271
272 node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
273 if (node == -1) return 0;
274 return node;
275}
276
277/* Return 'node' assigned to a particular prom 'path'
278 * FIXME: Should work for v0 as well
279 */
280int
281prom_pathtoinode(const char *path)
282{
283 int node, inst;
284
285 inst = prom_devopen (path);
286 if (inst == 0) return 0;
287 node = prom_inst2pkg (inst);
288 prom_devclose (inst);
289 if (node == -1) return 0;
290 return node;
291}
292
293int prom_ihandle2path(int handle, char *buffer, int bufsize)
294{
295 return p1275_cmd("instance-to-path",
296 P1275_ARG(1,P1275_ARG_OUT_BUF)|
297 P1275_INOUT(3, 1),
298 handle, buffer, P1275_SIZE(bufsize));
299}