diff options
Diffstat (limited to 'arch/sparc/prom')
-rw-r--r-- | arch/sparc/prom/Makefile | 9 | ||||
-rw-r--r-- | arch/sparc/prom/bootstr.c | 63 | ||||
-rw-r--r-- | arch/sparc/prom/console.c | 220 | ||||
-rw-r--r-- | arch/sparc/prom/devmap.c | 54 | ||||
-rw-r--r-- | arch/sparc/prom/devops.c | 89 | ||||
-rw-r--r-- | arch/sparc/prom/init.c | 95 | ||||
-rw-r--r-- | arch/sparc/prom/memory.c | 216 | ||||
-rw-r--r-- | arch/sparc/prom/misc.c | 139 | ||||
-rw-r--r-- | arch/sparc/prom/mp.c | 121 | ||||
-rw-r--r-- | arch/sparc/prom/palloc.c | 44 | ||||
-rw-r--r-- | arch/sparc/prom/printf.c | 46 | ||||
-rw-r--r-- | arch/sparc/prom/ranges.c | 118 | ||||
-rw-r--r-- | arch/sparc/prom/segment.c | 29 | ||||
-rw-r--r-- | arch/sparc/prom/sun4prom.c | 161 | ||||
-rw-r--r-- | arch/sparc/prom/tree.c | 364 |
15 files changed, 1768 insertions, 0 deletions
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile new file mode 100644 index 000000000000..2b217ee40703 --- /dev/null +++ b/arch/sparc/prom/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # $Id: Makefile,v 1.8 2000/12/15 00:41:22 davem Exp $ | ||
2 | # Makefile for the Sun Boot PROM interface library under | ||
3 | # Linux. | ||
4 | # | ||
5 | |||
6 | lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \ | ||
7 | palloc.o ranges.o segment.o console.o printf.o tree.o | ||
8 | |||
9 | lib-$(CONFIG_SUN4) += sun4prom.o | ||
diff --git a/arch/sparc/prom/bootstr.c b/arch/sparc/prom/bootstr.c new file mode 100644 index 000000000000..cfdeac2788d1 --- /dev/null +++ b/arch/sparc/prom/bootstr.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* $Id: bootstr.c,v 1.20 2000/02/08 20:24:23 davem Exp $ | ||
2 | * bootstr.c: Boot string/argument acquisition from the PROM. | ||
3 | * | ||
4 | * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #include <linux/string.h> | ||
8 | #include <asm/oplib.h> | ||
9 | #include <asm/sun4prom.h> | ||
10 | #include <linux/init.h> | ||
11 | |||
12 | #define BARG_LEN 256 | ||
13 | static char barg_buf[BARG_LEN] = { 0 }; | ||
14 | static char fetched __initdata = 0; | ||
15 | |||
16 | extern linux_sun4_romvec *sun4_romvec; | ||
17 | |||
18 | char * __init | ||
19 | prom_getbootargs(void) | ||
20 | { | ||
21 | int iter; | ||
22 | char *cp, *arg; | ||
23 | |||
24 | /* This check saves us from a panic when bootfd patches args. */ | ||
25 | if (fetched) { | ||
26 | return barg_buf; | ||
27 | } | ||
28 | |||
29 | switch(prom_vers) { | ||
30 | case PROM_V0: | ||
31 | case PROM_SUN4: | ||
32 | cp = barg_buf; | ||
33 | /* Start from 1 and go over fd(0,0,0)kernel */ | ||
34 | for(iter = 1; iter < 8; iter++) { | ||
35 | arg = (*(romvec->pv_v0bootargs))->argv[iter]; | ||
36 | if(arg == 0) break; | ||
37 | while(*arg != 0) { | ||
38 | /* Leave place for space and null. */ | ||
39 | if(cp >= barg_buf + BARG_LEN-2){ | ||
40 | /* We might issue a warning here. */ | ||
41 | break; | ||
42 | } | ||
43 | *cp++ = *arg++; | ||
44 | } | ||
45 | *cp++ = ' '; | ||
46 | } | ||
47 | *cp = 0; | ||
48 | break; | ||
49 | case PROM_V2: | ||
50 | case PROM_V3: | ||
51 | /* | ||
52 | * V3 PROM cannot supply as with more than 128 bytes | ||
53 | * of an argument. But a smart bootstrap loader can. | ||
54 | */ | ||
55 | strlcpy(barg_buf, *romvec->pv_v2bootargs.bootargs, sizeof(barg_buf)); | ||
56 | break; | ||
57 | default: | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | fetched = 1; | ||
62 | return barg_buf; | ||
63 | } | ||
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c new file mode 100644 index 000000000000..4e6e41d3291d --- /dev/null +++ b/arch/sparc/prom/console.c | |||
@@ -0,0 +1,220 @@ | |||
1 | /* $Id: console.c,v 1.25 2001/10/30 04:54:22 davem Exp $ | ||
2 | * console.c: Routines that deal with sending and receiving IO | ||
3 | * to/from the current console device using the PROM. | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | * Copyright (C) 1998 Pete Zaitcev <zaitcev@yahoo.com> | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/sun4prom.h> | ||
14 | #include <asm/oplib.h> | ||
15 | #include <asm/system.h> | ||
16 | #include <linux/string.h> | ||
17 | |||
18 | extern void restore_current(void); | ||
19 | |||
20 | static char con_name_jmc[] = "/obio/su@"; /* "/obio/su@0,3002f8"; */ | ||
21 | #define CON_SIZE_JMC (sizeof(con_name_jmc)) | ||
22 | |||
23 | /* Non blocking get character from console input device, returns -1 | ||
24 | * if no input was taken. This can be used for polling. | ||
25 | */ | ||
26 | int | ||
27 | prom_nbgetchar(void) | ||
28 | { | ||
29 | static char inc; | ||
30 | int i = -1; | ||
31 | unsigned long flags; | ||
32 | |||
33 | spin_lock_irqsave(&prom_lock, flags); | ||
34 | switch(prom_vers) { | ||
35 | case PROM_V0: | ||
36 | case PROM_SUN4: | ||
37 | i = (*(romvec->pv_nbgetchar))(); | ||
38 | break; | ||
39 | case PROM_V2: | ||
40 | case PROM_V3: | ||
41 | if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1) { | ||
42 | i = inc; | ||
43 | } else { | ||
44 | i = -1; | ||
45 | } | ||
46 | break; | ||
47 | default: | ||
48 | i = -1; | ||
49 | break; | ||
50 | }; | ||
51 | restore_current(); | ||
52 | spin_unlock_irqrestore(&prom_lock, flags); | ||
53 | return i; /* Ugh, we could spin forever on unsupported proms ;( */ | ||
54 | } | ||
55 | |||
56 | /* Non blocking put character to console device, returns -1 if | ||
57 | * unsuccessful. | ||
58 | */ | ||
59 | int | ||
60 | prom_nbputchar(char c) | ||
61 | { | ||
62 | static char outc; | ||
63 | unsigned long flags; | ||
64 | int i = -1; | ||
65 | |||
66 | spin_lock_irqsave(&prom_lock, flags); | ||
67 | switch(prom_vers) { | ||
68 | case PROM_V0: | ||
69 | case PROM_SUN4: | ||
70 | i = (*(romvec->pv_nbputchar))(c); | ||
71 | break; | ||
72 | case PROM_V2: | ||
73 | case PROM_V3: | ||
74 | outc = c; | ||
75 | if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1) | ||
76 | i = 0; | ||
77 | else | ||
78 | i = -1; | ||
79 | break; | ||
80 | default: | ||
81 | i = -1; | ||
82 | break; | ||
83 | }; | ||
84 | restore_current(); | ||
85 | spin_unlock_irqrestore(&prom_lock, flags); | ||
86 | return i; /* Ugh, we could spin forever on unsupported proms ;( */ | ||
87 | } | ||
88 | |||
89 | /* Blocking version of get character routine above. */ | ||
90 | char | ||
91 | prom_getchar(void) | ||
92 | { | ||
93 | int character; | ||
94 | while((character = prom_nbgetchar()) == -1) ; | ||
95 | return (char) character; | ||
96 | } | ||
97 | |||
98 | /* Blocking version of put character routine above. */ | ||
99 | void | ||
100 | prom_putchar(char c) | ||
101 | { | ||
102 | while(prom_nbputchar(c) == -1) ; | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | /* Query for input device type */ | ||
107 | enum prom_input_device | ||
108 | prom_query_input_device(void) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | int st_p; | ||
112 | char propb[64]; | ||
113 | char *p; | ||
114 | int propl; | ||
115 | |||
116 | switch(prom_vers) { | ||
117 | case PROM_V0: | ||
118 | case PROM_V2: | ||
119 | case PROM_SUN4: | ||
120 | default: | ||
121 | switch(*romvec->pv_stdin) { | ||
122 | case PROMDEV_KBD: return PROMDEV_IKBD; | ||
123 | case PROMDEV_TTYA: return PROMDEV_ITTYA; | ||
124 | case PROMDEV_TTYB: return PROMDEV_ITTYB; | ||
125 | default: | ||
126 | return PROMDEV_I_UNK; | ||
127 | }; | ||
128 | case PROM_V3: | ||
129 | spin_lock_irqsave(&prom_lock, flags); | ||
130 | st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin); | ||
131 | restore_current(); | ||
132 | spin_unlock_irqrestore(&prom_lock, flags); | ||
133 | if(prom_node_has_property(st_p, "keyboard")) | ||
134 | return PROMDEV_IKBD; | ||
135 | if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) { | ||
136 | if(strncmp(propb, "keyboard", sizeof("serial")) == 0) | ||
137 | return PROMDEV_IKBD; | ||
138 | } | ||
139 | if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) { | ||
140 | if(strncmp(propb, "serial", sizeof("serial"))) | ||
141 | return PROMDEV_I_UNK; | ||
142 | } | ||
143 | propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb)); | ||
144 | if(propl > 2) { | ||
145 | p = propb; | ||
146 | while(*p) p++; p -= 2; | ||
147 | if(p[0] == ':') { | ||
148 | if(p[1] == 'a') | ||
149 | return PROMDEV_ITTYA; | ||
150 | else if(p[1] == 'b') | ||
151 | return PROMDEV_ITTYB; | ||
152 | } | ||
153 | } | ||
154 | return PROMDEV_I_UNK; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* Query for output device type */ | ||
159 | |||
160 | enum prom_output_device | ||
161 | prom_query_output_device(void) | ||
162 | { | ||
163 | unsigned long flags; | ||
164 | int st_p; | ||
165 | char propb[64]; | ||
166 | char *p; | ||
167 | int propl; | ||
168 | |||
169 | switch(prom_vers) { | ||
170 | case PROM_V0: | ||
171 | case PROM_SUN4: | ||
172 | switch(*romvec->pv_stdin) { | ||
173 | case PROMDEV_SCREEN: return PROMDEV_OSCREEN; | ||
174 | case PROMDEV_TTYA: return PROMDEV_OTTYA; | ||
175 | case PROMDEV_TTYB: return PROMDEV_OTTYB; | ||
176 | }; | ||
177 | break; | ||
178 | case PROM_V2: | ||
179 | case PROM_V3: | ||
180 | spin_lock_irqsave(&prom_lock, flags); | ||
181 | st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout); | ||
182 | restore_current(); | ||
183 | spin_unlock_irqrestore(&prom_lock, flags); | ||
184 | propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb)); | ||
185 | if (propl == sizeof("display") && | ||
186 | strncmp("display", propb, sizeof("display")) == 0) | ||
187 | { | ||
188 | return PROMDEV_OSCREEN; | ||
189 | } | ||
190 | if(prom_vers == PROM_V3) { | ||
191 | if(propl >= 0 && | ||
192 | strncmp("serial", propb, sizeof("serial")) != 0) | ||
193 | return PROMDEV_O_UNK; | ||
194 | propl = prom_getproperty(prom_root_node, "stdout-path", | ||
195 | propb, sizeof(propb)); | ||
196 | if(propl == CON_SIZE_JMC && | ||
197 | strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0) | ||
198 | return PROMDEV_OTTYA; | ||
199 | if(propl > 2) { | ||
200 | p = propb; | ||
201 | while(*p) p++; p-= 2; | ||
202 | if(p[0]==':') { | ||
203 | if(p[1] == 'a') | ||
204 | return PROMDEV_OTTYA; | ||
205 | else if(p[1] == 'b') | ||
206 | return PROMDEV_OTTYB; | ||
207 | } | ||
208 | } | ||
209 | } else { | ||
210 | switch(*romvec->pv_stdin) { | ||
211 | case PROMDEV_TTYA: return PROMDEV_OTTYA; | ||
212 | case PROMDEV_TTYB: return PROMDEV_OTTYB; | ||
213 | }; | ||
214 | } | ||
215 | break; | ||
216 | default: | ||
217 | ; | ||
218 | }; | ||
219 | return PROMDEV_O_UNK; | ||
220 | } | ||
diff --git a/arch/sparc/prom/devmap.c b/arch/sparc/prom/devmap.c new file mode 100644 index 000000000000..eb12073578ad --- /dev/null +++ b/arch/sparc/prom/devmap.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* $Id: devmap.c,v 1.7 2000/08/26 02:38:03 anton Exp $ | ||
2 | * promdevmap.c: Map device/IO areas to virtual addresses. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
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 | extern void restore_current(void); | ||
15 | |||
16 | /* Just like the routines in palloc.c, these should not be used | ||
17 | * by the kernel at all. Bootloader facility mainly. And again, | ||
18 | * this is only available on V2 proms and above. | ||
19 | */ | ||
20 | |||
21 | /* Map physical device address 'paddr' in IO space 'ios' of size | ||
22 | * 'num_bytes' to a virtual address, with 'vhint' being a hint to | ||
23 | * the prom as to where you would prefer the mapping. We return | ||
24 | * where the prom actually mapped it. | ||
25 | */ | ||
26 | char * | ||
27 | prom_mapio(char *vhint, int ios, unsigned int paddr, unsigned int num_bytes) | ||
28 | { | ||
29 | unsigned long flags; | ||
30 | char *ret; | ||
31 | |||
32 | spin_lock_irqsave(&prom_lock, flags); | ||
33 | if((num_bytes == 0) || (paddr == 0)) ret = (char *) 0x0; | ||
34 | else | ||
35 | ret = (*(romvec->pv_v2devops.v2_dumb_mmap))(vhint, ios, paddr, | ||
36 | num_bytes); | ||
37 | restore_current(); | ||
38 | spin_unlock_irqrestore(&prom_lock, flags); | ||
39 | return ret; | ||
40 | } | ||
41 | |||
42 | /* Unmap an IO/device area that was mapped using the above routine. */ | ||
43 | void | ||
44 | prom_unmapio(char *vaddr, unsigned int num_bytes) | ||
45 | { | ||
46 | unsigned long flags; | ||
47 | |||
48 | if(num_bytes == 0x0) return; | ||
49 | spin_lock_irqsave(&prom_lock, flags); | ||
50 | (*(romvec->pv_v2devops.v2_dumb_munmap))(vaddr, num_bytes); | ||
51 | restore_current(); | ||
52 | spin_unlock_irqrestore(&prom_lock, flags); | ||
53 | return; | ||
54 | } | ||
diff --git a/arch/sparc/prom/devops.c b/arch/sparc/prom/devops.c new file mode 100644 index 000000000000..61919b54f6cc --- /dev/null +++ b/arch/sparc/prom/devops.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* $Id: devops.c,v 1.13 2000/08/26 02:38:03 anton Exp $ | ||
2 | * devops.c: Device operations using the PROM. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | #include <linux/types.h> | ||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/sched.h> | ||
9 | |||
10 | #include <asm/openprom.h> | ||
11 | #include <asm/oplib.h> | ||
12 | |||
13 | extern void restore_current(void); | ||
14 | |||
15 | /* Open the device described by the string 'dstr'. Returns the handle | ||
16 | * to that device used for subsequent operations on that device. | ||
17 | * Returns -1 on failure. | ||
18 | */ | ||
19 | int | ||
20 | prom_devopen(char *dstr) | ||
21 | { | ||
22 | int handle; | ||
23 | unsigned long flags; | ||
24 | spin_lock_irqsave(&prom_lock, flags); | ||
25 | switch(prom_vers) { | ||
26 | case PROM_V0: | ||
27 | handle = (*(romvec->pv_v0devops.v0_devopen))(dstr); | ||
28 | if(handle == 0) handle = -1; | ||
29 | break; | ||
30 | case PROM_V2: | ||
31 | case PROM_V3: | ||
32 | handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr); | ||
33 | break; | ||
34 | default: | ||
35 | handle = -1; | ||
36 | break; | ||
37 | }; | ||
38 | restore_current(); | ||
39 | spin_unlock_irqrestore(&prom_lock, flags); | ||
40 | |||
41 | return handle; | ||
42 | } | ||
43 | |||
44 | /* Close the device described by device handle 'dhandle'. */ | ||
45 | int | ||
46 | prom_devclose(int dhandle) | ||
47 | { | ||
48 | unsigned long flags; | ||
49 | spin_lock_irqsave(&prom_lock, flags); | ||
50 | switch(prom_vers) { | ||
51 | case PROM_V0: | ||
52 | (*(romvec->pv_v0devops.v0_devclose))(dhandle); | ||
53 | break; | ||
54 | case PROM_V2: | ||
55 | case PROM_V3: | ||
56 | (*(romvec->pv_v2devops.v2_dev_close))(dhandle); | ||
57 | break; | ||
58 | default: | ||
59 | break; | ||
60 | }; | ||
61 | restore_current(); | ||
62 | spin_unlock_irqrestore(&prom_lock, flags); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* Seek to specified location described by 'seekhi' and 'seeklo' | ||
67 | * for device 'dhandle'. | ||
68 | */ | ||
69 | void | ||
70 | prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo) | ||
71 | { | ||
72 | unsigned long flags; | ||
73 | spin_lock_irqsave(&prom_lock, flags); | ||
74 | switch(prom_vers) { | ||
75 | case PROM_V0: | ||
76 | (*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo); | ||
77 | break; | ||
78 | case PROM_V2: | ||
79 | case PROM_V3: | ||
80 | (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo); | ||
81 | break; | ||
82 | default: | ||
83 | break; | ||
84 | }; | ||
85 | restore_current(); | ||
86 | spin_unlock_irqrestore(&prom_lock, flags); | ||
87 | |||
88 | return; | ||
89 | } | ||
diff --git a/arch/sparc/prom/init.c b/arch/sparc/prom/init.c new file mode 100644 index 000000000000..b83409c81916 --- /dev/null +++ b/arch/sparc/prom/init.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* $Id: init.c,v 1.14 2000/01/29 01:09:12 anton Exp $ | ||
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) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/openprom.h> | ||
14 | #include <asm/oplib.h> | ||
15 | #include <asm/sun4prom.h> | ||
16 | |||
17 | struct linux_romvec *romvec; | ||
18 | enum prom_major_version prom_vers; | ||
19 | unsigned int prom_rev, prom_prev; | ||
20 | linux_sun4_romvec *sun4_romvec; | ||
21 | |||
22 | /* The root node of the prom device tree. */ | ||
23 | int prom_root_node; | ||
24 | |||
25 | int prom_stdin, prom_stdout; | ||
26 | |||
27 | /* Pointer to the device tree operations structure. */ | ||
28 | struct linux_nodeops *prom_nodeops; | ||
29 | |||
30 | /* You must call prom_init() before you attempt to use any of the | ||
31 | * routines in the prom library. It returns 0 on success, 1 on | ||
32 | * failure. It gets passed the pointer to the PROM vector. | ||
33 | */ | ||
34 | |||
35 | extern void prom_meminit(void); | ||
36 | extern void prom_ranges_init(void); | ||
37 | |||
38 | void __init prom_init(struct linux_romvec *rp) | ||
39 | { | ||
40 | #ifdef CONFIG_SUN4 | ||
41 | extern struct linux_romvec *sun4_prom_init(void); | ||
42 | rp = sun4_prom_init(); | ||
43 | #endif | ||
44 | romvec = rp; | ||
45 | |||
46 | switch(romvec->pv_romvers) { | ||
47 | case 0: | ||
48 | prom_vers = PROM_V0; | ||
49 | break; | ||
50 | case 2: | ||
51 | prom_vers = PROM_V2; | ||
52 | break; | ||
53 | case 3: | ||
54 | prom_vers = PROM_V3; | ||
55 | break; | ||
56 | case 40: | ||
57 | prom_vers = PROM_SUN4; | ||
58 | break; | ||
59 | default: | ||
60 | prom_printf("PROMLIB: Bad PROM version %d\n", | ||
61 | romvec->pv_romvers); | ||
62 | prom_halt(); | ||
63 | break; | ||
64 | }; | ||
65 | |||
66 | prom_rev = romvec->pv_plugin_revision; | ||
67 | prom_prev = romvec->pv_printrev; | ||
68 | prom_nodeops = romvec->pv_nodeops; | ||
69 | |||
70 | prom_root_node = prom_getsibling(0); | ||
71 | if((prom_root_node == 0) || (prom_root_node == -1)) | ||
72 | prom_halt(); | ||
73 | |||
74 | if((((unsigned long) prom_nodeops) == 0) || | ||
75 | (((unsigned long) prom_nodeops) == -1)) | ||
76 | prom_halt(); | ||
77 | |||
78 | if(prom_vers == PROM_V2 || prom_vers == PROM_V3) { | ||
79 | prom_stdout = *romvec->pv_v2bootargs.fd_stdout; | ||
80 | prom_stdin = *romvec->pv_v2bootargs.fd_stdin; | ||
81 | } | ||
82 | |||
83 | prom_meminit(); | ||
84 | |||
85 | prom_ranges_init(); | ||
86 | |||
87 | #ifndef CONFIG_SUN4 | ||
88 | /* SUN4 prints this in sun4_prom_init */ | ||
89 | printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n", | ||
90 | romvec->pv_romvers, prom_rev); | ||
91 | #endif | ||
92 | |||
93 | /* Initialization successful. */ | ||
94 | return; | ||
95 | } | ||
diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c new file mode 100644 index 000000000000..46aa51afec14 --- /dev/null +++ b/arch/sparc/prom/memory.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $ | ||
2 | * memory.c: Prom routine for acquiring various bits of information | ||
3 | * about RAM on the machine, both virtual and physical. | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | |||
13 | #include <asm/openprom.h> | ||
14 | #include <asm/sun4prom.h> | ||
15 | #include <asm/oplib.h> | ||
16 | |||
17 | /* This routine, for consistency, returns the ram parameters in the | ||
18 | * V0 prom memory descriptor format. I choose this format because I | ||
19 | * think it was the easiest to work with. I feel the religious | ||
20 | * arguments now... ;) Also, I return the linked lists sorted to | ||
21 | * prevent paging_init() upset stomach as I have not yet written | ||
22 | * the pepto-bismol kernel module yet. | ||
23 | */ | ||
24 | |||
25 | struct linux_prom_registers prom_reg_memlist[64]; | ||
26 | struct linux_prom_registers prom_reg_tmp[64]; | ||
27 | |||
28 | struct linux_mlist_v0 prom_phys_total[64]; | ||
29 | struct linux_mlist_v0 prom_prom_taken[64]; | ||
30 | struct linux_mlist_v0 prom_phys_avail[64]; | ||
31 | |||
32 | struct linux_mlist_v0 *prom_ptot_ptr = prom_phys_total; | ||
33 | struct linux_mlist_v0 *prom_ptak_ptr = prom_prom_taken; | ||
34 | struct linux_mlist_v0 *prom_pavl_ptr = prom_phys_avail; | ||
35 | |||
36 | struct linux_mem_v0 prom_memlist; | ||
37 | |||
38 | |||
39 | /* Internal Prom library routine to sort a linux_mlist_v0 memory | ||
40 | * list. Used below in initialization. | ||
41 | */ | ||
42 | static void __init | ||
43 | prom_sortmemlist(struct linux_mlist_v0 *thislist) | ||
44 | { | ||
45 | int swapi = 0; | ||
46 | int i, mitr, tmpsize; | ||
47 | char *tmpaddr; | ||
48 | char *lowest; | ||
49 | |||
50 | for(i=0; thislist[i].theres_more != 0; i++) { | ||
51 | lowest = thislist[i].start_adr; | ||
52 | for(mitr = i+1; thislist[mitr-1].theres_more != 0; mitr++) | ||
53 | if(thislist[mitr].start_adr < lowest) { | ||
54 | lowest = thislist[mitr].start_adr; | ||
55 | swapi = mitr; | ||
56 | } | ||
57 | if(lowest == thislist[i].start_adr) continue; | ||
58 | tmpaddr = thislist[swapi].start_adr; | ||
59 | tmpsize = thislist[swapi].num_bytes; | ||
60 | for(mitr = swapi; mitr > i; mitr--) { | ||
61 | thislist[mitr].start_adr = thislist[mitr-1].start_adr; | ||
62 | thislist[mitr].num_bytes = thislist[mitr-1].num_bytes; | ||
63 | } | ||
64 | thislist[i].start_adr = tmpaddr; | ||
65 | thislist[i].num_bytes = tmpsize; | ||
66 | } | ||
67 | |||
68 | return; | ||
69 | } | ||
70 | |||
71 | /* Initialize the memory lists based upon the prom version. */ | ||
72 | void __init prom_meminit(void) | ||
73 | { | ||
74 | int node = 0; | ||
75 | unsigned int iter, num_regs; | ||
76 | struct linux_mlist_v0 *mptr; /* ptr for traversal */ | ||
77 | |||
78 | switch(prom_vers) { | ||
79 | case PROM_V0: | ||
80 | /* Nice, kind of easier to do in this case. */ | ||
81 | /* First, the total physical descriptors. */ | ||
82 | for(mptr = (*(romvec->pv_v0mem.v0_totphys)), iter=0; | ||
83 | mptr; mptr=mptr->theres_more, iter++) { | ||
84 | prom_phys_total[iter].start_adr = mptr->start_adr; | ||
85 | prom_phys_total[iter].num_bytes = mptr->num_bytes; | ||
86 | prom_phys_total[iter].theres_more = &prom_phys_total[iter+1]; | ||
87 | } | ||
88 | prom_phys_total[iter-1].theres_more = 0x0; | ||
89 | /* Second, the total prom taken descriptors. */ | ||
90 | for(mptr = (*(romvec->pv_v0mem.v0_prommap)), iter=0; | ||
91 | mptr; mptr=mptr->theres_more, iter++) { | ||
92 | prom_prom_taken[iter].start_adr = mptr->start_adr; | ||
93 | prom_prom_taken[iter].num_bytes = mptr->num_bytes; | ||
94 | prom_prom_taken[iter].theres_more = &prom_prom_taken[iter+1]; | ||
95 | } | ||
96 | prom_prom_taken[iter-1].theres_more = 0x0; | ||
97 | /* Last, the available physical descriptors. */ | ||
98 | for(mptr = (*(romvec->pv_v0mem.v0_available)), iter=0; | ||
99 | mptr; mptr=mptr->theres_more, iter++) { | ||
100 | prom_phys_avail[iter].start_adr = mptr->start_adr; | ||
101 | prom_phys_avail[iter].num_bytes = mptr->num_bytes; | ||
102 | prom_phys_avail[iter].theres_more = &prom_phys_avail[iter+1]; | ||
103 | } | ||
104 | prom_phys_avail[iter-1].theres_more = 0x0; | ||
105 | /* Sort all the lists. */ | ||
106 | prom_sortmemlist(prom_phys_total); | ||
107 | prom_sortmemlist(prom_prom_taken); | ||
108 | prom_sortmemlist(prom_phys_avail); | ||
109 | break; | ||
110 | case PROM_V2: | ||
111 | case PROM_V3: | ||
112 | /* Grrr, have to traverse the prom device tree ;( */ | ||
113 | node = prom_getchild(prom_root_node); | ||
114 | node = prom_searchsiblings(node, "memory"); | ||
115 | num_regs = prom_getproperty(node, "available", | ||
116 | (char *) prom_reg_memlist, | ||
117 | sizeof(prom_reg_memlist)); | ||
118 | num_regs = (num_regs/sizeof(struct linux_prom_registers)); | ||
119 | for(iter=0; iter<num_regs; iter++) { | ||
120 | prom_phys_avail[iter].start_adr = | ||
121 | (char *) prom_reg_memlist[iter].phys_addr; | ||
122 | prom_phys_avail[iter].num_bytes = | ||
123 | (unsigned long) prom_reg_memlist[iter].reg_size; | ||
124 | prom_phys_avail[iter].theres_more = | ||
125 | &prom_phys_avail[iter+1]; | ||
126 | } | ||
127 | prom_phys_avail[iter-1].theres_more = 0x0; | ||
128 | |||
129 | num_regs = prom_getproperty(node, "reg", | ||
130 | (char *) prom_reg_memlist, | ||
131 | sizeof(prom_reg_memlist)); | ||
132 | num_regs = (num_regs/sizeof(struct linux_prom_registers)); | ||
133 | for(iter=0; iter<num_regs; iter++) { | ||
134 | prom_phys_total[iter].start_adr = | ||
135 | (char *) prom_reg_memlist[iter].phys_addr; | ||
136 | prom_phys_total[iter].num_bytes = | ||
137 | (unsigned long) prom_reg_memlist[iter].reg_size; | ||
138 | prom_phys_total[iter].theres_more = | ||
139 | &prom_phys_total[iter+1]; | ||
140 | } | ||
141 | prom_phys_total[iter-1].theres_more = 0x0; | ||
142 | |||
143 | node = prom_getchild(prom_root_node); | ||
144 | node = prom_searchsiblings(node, "virtual-memory"); | ||
145 | num_regs = prom_getproperty(node, "available", | ||
146 | (char *) prom_reg_memlist, | ||
147 | sizeof(prom_reg_memlist)); | ||
148 | num_regs = (num_regs/sizeof(struct linux_prom_registers)); | ||
149 | |||
150 | /* Convert available virtual areas to taken virtual | ||
151 | * areas. First sort, then convert. | ||
152 | */ | ||
153 | for(iter=0; iter<num_regs; iter++) { | ||
154 | prom_prom_taken[iter].start_adr = | ||
155 | (char *) prom_reg_memlist[iter].phys_addr; | ||
156 | prom_prom_taken[iter].num_bytes = | ||
157 | (unsigned long) prom_reg_memlist[iter].reg_size; | ||
158 | prom_prom_taken[iter].theres_more = | ||
159 | &prom_prom_taken[iter+1]; | ||
160 | } | ||
161 | prom_prom_taken[iter-1].theres_more = 0x0; | ||
162 | |||
163 | prom_sortmemlist(prom_prom_taken); | ||
164 | |||
165 | /* Finally, convert. */ | ||
166 | for(iter=0; iter<num_regs; iter++) { | ||
167 | prom_prom_taken[iter].start_adr = | ||
168 | prom_prom_taken[iter].start_adr + | ||
169 | prom_prom_taken[iter].num_bytes; | ||
170 | prom_prom_taken[iter].num_bytes = | ||
171 | prom_prom_taken[iter+1].start_adr - | ||
172 | prom_prom_taken[iter].start_adr; | ||
173 | } | ||
174 | prom_prom_taken[iter-1].num_bytes = | ||
175 | 0xffffffff - (unsigned long) prom_prom_taken[iter-1].start_adr; | ||
176 | |||
177 | /* Sort the other two lists. */ | ||
178 | prom_sortmemlist(prom_phys_total); | ||
179 | prom_sortmemlist(prom_phys_avail); | ||
180 | break; | ||
181 | |||
182 | case PROM_SUN4: | ||
183 | #ifdef CONFIG_SUN4 | ||
184 | /* how simple :) */ | ||
185 | prom_phys_total[0].start_adr = 0x0; | ||
186 | prom_phys_total[0].num_bytes = *(sun4_romvec->memorysize); | ||
187 | prom_phys_total[0].theres_more = 0x0; | ||
188 | prom_prom_taken[0].start_adr = 0x0; | ||
189 | prom_prom_taken[0].num_bytes = 0x0; | ||
190 | prom_prom_taken[0].theres_more = 0x0; | ||
191 | prom_phys_avail[0].start_adr = 0x0; | ||
192 | prom_phys_avail[0].num_bytes = *(sun4_romvec->memoryavail); | ||
193 | prom_phys_avail[0].theres_more = 0x0; | ||
194 | #endif | ||
195 | break; | ||
196 | |||
197 | default: | ||
198 | break; | ||
199 | }; | ||
200 | |||
201 | /* Link all the lists into the top-level descriptor. */ | ||
202 | prom_memlist.v0_totphys=&prom_ptot_ptr; | ||
203 | prom_memlist.v0_prommap=&prom_ptak_ptr; | ||
204 | prom_memlist.v0_available=&prom_pavl_ptr; | ||
205 | |||
206 | return; | ||
207 | } | ||
208 | |||
209 | /* This returns a pointer to our libraries internal v0 format | ||
210 | * memory descriptor. | ||
211 | */ | ||
212 | struct linux_mem_v0 * | ||
213 | prom_meminfo(void) | ||
214 | { | ||
215 | return &prom_memlist; | ||
216 | } | ||
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c new file mode 100644 index 000000000000..c840c2062342 --- /dev/null +++ b/arch/sparc/prom/misc.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* $Id: misc.c,v 1.18 2000/08/26 02:38:03 anton Exp $ | ||
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 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | #include <asm/auxio.h> | ||
15 | #include <asm/system.h> | ||
16 | |||
17 | extern void restore_current(void); | ||
18 | |||
19 | DEFINE_SPINLOCK(prom_lock); | ||
20 | |||
21 | /* Reset and reboot the machine with the command 'bcommand'. */ | ||
22 | void | ||
23 | prom_reboot(char *bcommand) | ||
24 | { | ||
25 | unsigned long flags; | ||
26 | spin_lock_irqsave(&prom_lock, flags); | ||
27 | (*(romvec->pv_reboot))(bcommand); | ||
28 | /* Never get here. */ | ||
29 | restore_current(); | ||
30 | spin_unlock_irqrestore(&prom_lock, flags); | ||
31 | } | ||
32 | |||
33 | /* Forth evaluate the expression contained in 'fstring'. */ | ||
34 | void | ||
35 | prom_feval(char *fstring) | ||
36 | { | ||
37 | unsigned long flags; | ||
38 | if(!fstring || fstring[0] == 0) | ||
39 | return; | ||
40 | spin_lock_irqsave(&prom_lock, flags); | ||
41 | if(prom_vers == PROM_V0) | ||
42 | (*(romvec->pv_fortheval.v0_eval))(strlen(fstring), fstring); | ||
43 | else | ||
44 | (*(romvec->pv_fortheval.v2_eval))(fstring); | ||
45 | restore_current(); | ||
46 | spin_unlock_irqrestore(&prom_lock, flags); | ||
47 | } | ||
48 | |||
49 | /* We want to do this more nicely some day. */ | ||
50 | extern void (*prom_palette)(int); | ||
51 | |||
52 | /* Drop into the prom, with the chance to continue with the 'go' | ||
53 | * prom command. | ||
54 | */ | ||
55 | void | ||
56 | prom_cmdline(void) | ||
57 | { | ||
58 | extern void install_obp_ticker(void); | ||
59 | extern void install_linux_ticker(void); | ||
60 | unsigned long flags; | ||
61 | |||
62 | if(!serial_console && prom_palette) | ||
63 | prom_palette (1); | ||
64 | spin_lock_irqsave(&prom_lock, flags); | ||
65 | install_obp_ticker(); | ||
66 | (*(romvec->pv_abort))(); | ||
67 | restore_current(); | ||
68 | install_linux_ticker(); | ||
69 | spin_unlock_irqrestore(&prom_lock, flags); | ||
70 | #ifdef CONFIG_SUN_AUXIO | ||
71 | set_auxio(AUXIO_LED, 0); | ||
72 | #endif | ||
73 | if(!serial_console && prom_palette) | ||
74 | prom_palette (0); | ||
75 | } | ||
76 | |||
77 | /* Drop into the prom, but completely terminate the program. | ||
78 | * No chance of continuing. | ||
79 | */ | ||
80 | void | ||
81 | prom_halt(void) | ||
82 | { | ||
83 | unsigned long flags; | ||
84 | again: | ||
85 | spin_lock_irqsave(&prom_lock, flags); | ||
86 | (*(romvec->pv_halt))(); | ||
87 | /* Never get here. */ | ||
88 | restore_current(); | ||
89 | spin_unlock_irqrestore(&prom_lock, flags); | ||
90 | goto again; /* PROM is out to get me -DaveM */ | ||
91 | } | ||
92 | |||
93 | typedef void (*sfunc_t)(void); | ||
94 | |||
95 | /* Set prom sync handler to call function 'funcp'. */ | ||
96 | void | ||
97 | prom_setsync(sfunc_t funcp) | ||
98 | { | ||
99 | if(!funcp) return; | ||
100 | *romvec->pv_synchook = funcp; | ||
101 | } | ||
102 | |||
103 | /* Get the idprom and stuff it into buffer 'idbuf'. Returns the | ||
104 | * format type. 'num_bytes' is the number of bytes that your idbuf | ||
105 | * has space for. Returns 0xff on error. | ||
106 | */ | ||
107 | unsigned char | ||
108 | prom_get_idprom(char *idbuf, int num_bytes) | ||
109 | { | ||
110 | int len; | ||
111 | |||
112 | len = prom_getproplen(prom_root_node, "idprom"); | ||
113 | if((len>num_bytes) || (len==-1)) return 0xff; | ||
114 | if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) | ||
115 | return idbuf[0]; | ||
116 | |||
117 | return 0xff; | ||
118 | } | ||
119 | |||
120 | /* Get the major prom version number. */ | ||
121 | int | ||
122 | prom_version(void) | ||
123 | { | ||
124 | return romvec->pv_romvers; | ||
125 | } | ||
126 | |||
127 | /* Get the prom plugin-revision. */ | ||
128 | int | ||
129 | prom_getrev(void) | ||
130 | { | ||
131 | return prom_rev; | ||
132 | } | ||
133 | |||
134 | /* Get the prom firmware print revision. */ | ||
135 | int | ||
136 | prom_getprev(void) | ||
137 | { | ||
138 | return prom_prev; | ||
139 | } | ||
diff --git a/arch/sparc/prom/mp.c b/arch/sparc/prom/mp.c new file mode 100644 index 000000000000..92fe3739fdb8 --- /dev/null +++ b/arch/sparc/prom/mp.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* $Id: mp.c,v 1.12 2000/08/26 02:38:03 anton Exp $ | ||
2 | * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call | ||
3 | * these on a UP or else you will halt and catch fire. ;) | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | ||
7 | |||
8 | #include <linux/types.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/sched.h> | ||
11 | |||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | |||
15 | extern void restore_current(void); | ||
16 | |||
17 | /* Start cpu with prom-tree node 'cpunode' using context described | ||
18 | * by 'ctable_reg' in context 'ctx' at program counter 'pc'. | ||
19 | * | ||
20 | * XXX Have to look into what the return values mean. XXX | ||
21 | */ | ||
22 | int | ||
23 | prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, char *pc) | ||
24 | { | ||
25 | int ret; | ||
26 | unsigned long flags; | ||
27 | |||
28 | spin_lock_irqsave(&prom_lock, flags); | ||
29 | switch(prom_vers) { | ||
30 | case PROM_V0: | ||
31 | case PROM_V2: | ||
32 | default: | ||
33 | ret = -1; | ||
34 | break; | ||
35 | case PROM_V3: | ||
36 | ret = (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc); | ||
37 | break; | ||
38 | }; | ||
39 | restore_current(); | ||
40 | spin_unlock_irqrestore(&prom_lock, flags); | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | /* Stop CPU with device prom-tree node 'cpunode'. | ||
46 | * XXX Again, what does the return value really mean? XXX | ||
47 | */ | ||
48 | int | ||
49 | prom_stopcpu(int cpunode) | ||
50 | { | ||
51 | int ret; | ||
52 | unsigned long flags; | ||
53 | |||
54 | spin_lock_irqsave(&prom_lock, flags); | ||
55 | switch(prom_vers) { | ||
56 | case PROM_V0: | ||
57 | case PROM_V2: | ||
58 | default: | ||
59 | ret = -1; | ||
60 | break; | ||
61 | case PROM_V3: | ||
62 | ret = (*(romvec->v3_cpustop))(cpunode); | ||
63 | break; | ||
64 | }; | ||
65 | restore_current(); | ||
66 | spin_unlock_irqrestore(&prom_lock, flags); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | /* Make CPU with device prom-tree node 'cpunode' idle. | ||
72 | * XXX Return value, anyone? XXX | ||
73 | */ | ||
74 | int | ||
75 | prom_idlecpu(int cpunode) | ||
76 | { | ||
77 | int ret; | ||
78 | unsigned long flags; | ||
79 | |||
80 | spin_lock_irqsave(&prom_lock, flags); | ||
81 | switch(prom_vers) { | ||
82 | case PROM_V0: | ||
83 | case PROM_V2: | ||
84 | default: | ||
85 | ret = -1; | ||
86 | break; | ||
87 | case PROM_V3: | ||
88 | ret = (*(romvec->v3_cpuidle))(cpunode); | ||
89 | break; | ||
90 | }; | ||
91 | restore_current(); | ||
92 | spin_unlock_irqrestore(&prom_lock, flags); | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | /* Resume the execution of CPU with nodeid 'cpunode'. | ||
98 | * XXX Come on, somebody has to know... XXX | ||
99 | */ | ||
100 | int | ||
101 | prom_restartcpu(int cpunode) | ||
102 | { | ||
103 | int ret; | ||
104 | unsigned long flags; | ||
105 | |||
106 | spin_lock_irqsave(&prom_lock, flags); | ||
107 | switch(prom_vers) { | ||
108 | case PROM_V0: | ||
109 | case PROM_V2: | ||
110 | default: | ||
111 | ret = -1; | ||
112 | break; | ||
113 | case PROM_V3: | ||
114 | ret = (*(romvec->v3_cpuresume))(cpunode); | ||
115 | break; | ||
116 | }; | ||
117 | restore_current(); | ||
118 | spin_unlock_irqrestore(&prom_lock, flags); | ||
119 | |||
120 | return ret; | ||
121 | } | ||
diff --git a/arch/sparc/prom/palloc.c b/arch/sparc/prom/palloc.c new file mode 100644 index 000000000000..84ce8bc54473 --- /dev/null +++ b/arch/sparc/prom/palloc.c | |||
@@ -0,0 +1,44 @@ | |||
1 | /* $Id: palloc.c,v 1.4 1996/04/25 06:09:48 davem Exp $ | ||
2 | * palloc.c: Memory allocation from the Sun PROM. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #include <asm/openprom.h> | ||
8 | #include <asm/oplib.h> | ||
9 | |||
10 | /* You should not call these routines after memory management | ||
11 | * has been initialized in the kernel, if fact you should not | ||
12 | * use these if at all possible in the kernel. They are mainly | ||
13 | * to be used for a bootloader for temporary allocations which | ||
14 | * it will free before jumping into the kernel it has loaded. | ||
15 | * | ||
16 | * Also, these routines don't work on V0 proms, only V2 and later. | ||
17 | */ | ||
18 | |||
19 | /* Allocate a chunk of memory of size 'num_bytes' giving a suggestion | ||
20 | * of virtual_hint as the preferred virtual base address of this chunk. | ||
21 | * There are no guarantees that you will get the allocation, or that | ||
22 | * the prom will abide by your "hint". So check your return value. | ||
23 | */ | ||
24 | char * | ||
25 | prom_alloc(char *virtual_hint, unsigned int num_bytes) | ||
26 | { | ||
27 | if(prom_vers == PROM_V0) return (char *) 0x0; | ||
28 | if(num_bytes == 0x0) return (char *) 0x0; | ||
29 | return (*(romvec->pv_v2devops.v2_dumb_mem_alloc))(virtual_hint, num_bytes); | ||
30 | } | ||
31 | |||
32 | /* Free a previously allocated chunk back to the prom at virtual address | ||
33 | * 'vaddr' of size 'num_bytes'. NOTE: This vaddr is not the hint you | ||
34 | * used for the allocation, but the virtual address the prom actually | ||
35 | * returned to you. They may be have been the same, they may have not, | ||
36 | * doesn't matter. | ||
37 | */ | ||
38 | void | ||
39 | prom_free(char *vaddr, unsigned int num_bytes) | ||
40 | { | ||
41 | if((prom_vers == PROM_V0) || (num_bytes == 0x0)) return; | ||
42 | (*(romvec->pv_v2devops.v2_dumb_mem_free))(vaddr, num_bytes); | ||
43 | return; | ||
44 | } | ||
diff --git a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c new file mode 100644 index 000000000000..dc8b598bedbb --- /dev/null +++ b/arch/sparc/prom/printf.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * printf.c: Internal prom library printf facility. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com) | ||
6 | * | ||
7 | * We used to warn all over the code: DO NOT USE prom_printf(), | ||
8 | * and yet people do. Anton's banking code was outputing banks | ||
9 | * with prom_printf for most of the 2.4 lifetime. Since an effective | ||
10 | * stick is not available, we deployed a carrot: an early printk | ||
11 | * through PROM by means of -p boot option. This ought to fix it. | ||
12 | * USE printk; if you need, deploy -p. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | #include <asm/openprom.h> | ||
18 | #include <asm/oplib.h> | ||
19 | |||
20 | static char ppbuf[1024]; | ||
21 | |||
22 | void | ||
23 | prom_write(const char *buf, unsigned int n) | ||
24 | { | ||
25 | char ch; | ||
26 | |||
27 | while (n != 0) { | ||
28 | --n; | ||
29 | if ((ch = *buf++) == '\n') | ||
30 | prom_putchar('\r'); | ||
31 | prom_putchar(ch); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | void | ||
36 | prom_printf(char *fmt, ...) | ||
37 | { | ||
38 | va_list args; | ||
39 | int i; | ||
40 | |||
41 | va_start(args, fmt); | ||
42 | i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args); | ||
43 | va_end(args); | ||
44 | |||
45 | prom_write(ppbuf, i); | ||
46 | } | ||
diff --git a/arch/sparc/prom/ranges.c b/arch/sparc/prom/ranges.c new file mode 100644 index 000000000000..a2920323c900 --- /dev/null +++ b/arch/sparc/prom/ranges.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* $Id: ranges.c,v 1.15 2001/12/19 00:29:51 davem Exp $ | ||
2 | * ranges.c: Handle ranges in newer proms for obio/sbus. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <asm/openprom.h> | ||
10 | #include <asm/oplib.h> | ||
11 | #include <asm/types.h> | ||
12 | #include <asm/sbus.h> | ||
13 | #include <asm/system.h> | ||
14 | |||
15 | struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; | ||
16 | int num_obio_ranges; | ||
17 | |||
18 | /* Adjust register values based upon the ranges parameters. */ | ||
19 | static void | ||
20 | prom_adjust_regs(struct linux_prom_registers *regp, int nregs, | ||
21 | struct linux_prom_ranges *rangep, int nranges) | ||
22 | { | ||
23 | int regc, rngc; | ||
24 | |||
25 | for (regc = 0; regc < nregs; regc++) { | ||
26 | for (rngc = 0; rngc < nranges; rngc++) | ||
27 | if (regp[regc].which_io == rangep[rngc].ot_child_space) | ||
28 | break; /* Fount it */ | ||
29 | if (rngc == nranges) /* oops */ | ||
30 | prom_printf("adjust_regs: Could not find range with matching bus type...\n"); | ||
31 | regp[regc].which_io = rangep[rngc].ot_parent_space; | ||
32 | regp[regc].phys_addr -= rangep[rngc].ot_child_base; | ||
33 | regp[regc].phys_addr += rangep[rngc].ot_parent_base; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | void | ||
38 | prom_adjust_ranges(struct linux_prom_ranges *ranges1, int nranges1, | ||
39 | struct linux_prom_ranges *ranges2, int nranges2) | ||
40 | { | ||
41 | int rng1c, rng2c; | ||
42 | |||
43 | for(rng1c=0; rng1c < nranges1; rng1c++) { | ||
44 | for(rng2c=0; rng2c < nranges2; rng2c++) | ||
45 | if(ranges1[rng1c].ot_parent_space == ranges2[rng2c].ot_child_space && | ||
46 | ranges1[rng1c].ot_parent_base >= ranges2[rng2c].ot_child_base && | ||
47 | ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base > 0U) | ||
48 | break; | ||
49 | if(rng2c == nranges2) /* oops */ | ||
50 | prom_printf("adjust_ranges: Could not find matching bus type...\n"); | ||
51 | else if (ranges1[rng1c].ot_parent_base + ranges1[rng1c].or_size > ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size) | ||
52 | ranges1[rng1c].or_size = | ||
53 | ranges2[rng2c].ot_child_base + ranges2[rng2c].or_size - ranges1[rng1c].ot_parent_base; | ||
54 | ranges1[rng1c].ot_parent_space = ranges2[rng2c].ot_parent_space; | ||
55 | ranges1[rng1c].ot_parent_base += ranges2[rng2c].ot_parent_base; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /* Apply probed obio ranges to registers passed, if no ranges return. */ | ||
60 | void | ||
61 | prom_apply_obio_ranges(struct linux_prom_registers *regs, int nregs) | ||
62 | { | ||
63 | if(num_obio_ranges) | ||
64 | prom_adjust_regs(regs, nregs, promlib_obio_ranges, num_obio_ranges); | ||
65 | } | ||
66 | |||
67 | void __init prom_ranges_init(void) | ||
68 | { | ||
69 | int node, obio_node; | ||
70 | int success; | ||
71 | |||
72 | num_obio_ranges = 0; | ||
73 | |||
74 | /* Check for obio and sbus ranges. */ | ||
75 | node = prom_getchild(prom_root_node); | ||
76 | obio_node = prom_searchsiblings(node, "obio"); | ||
77 | |||
78 | if(obio_node) { | ||
79 | success = prom_getproperty(obio_node, "ranges", | ||
80 | (char *) promlib_obio_ranges, | ||
81 | sizeof(promlib_obio_ranges)); | ||
82 | if(success != -1) | ||
83 | num_obio_ranges = (success/sizeof(struct linux_prom_ranges)); | ||
84 | } | ||
85 | |||
86 | if(num_obio_ranges) | ||
87 | prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges); | ||
88 | |||
89 | return; | ||
90 | } | ||
91 | |||
92 | void | ||
93 | prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) | ||
94 | { | ||
95 | int success; | ||
96 | int num_ranges; | ||
97 | struct linux_prom_ranges ranges[PROMREG_MAX]; | ||
98 | |||
99 | success = prom_getproperty(node, "ranges", | ||
100 | (char *) ranges, | ||
101 | sizeof (ranges)); | ||
102 | if (success != -1) { | ||
103 | num_ranges = (success/sizeof(struct linux_prom_ranges)); | ||
104 | if (parent) { | ||
105 | struct linux_prom_ranges parent_ranges[PROMREG_MAX]; | ||
106 | int num_parent_ranges; | ||
107 | |||
108 | success = prom_getproperty(parent, "ranges", | ||
109 | (char *) parent_ranges, | ||
110 | sizeof (parent_ranges)); | ||
111 | if (success != -1) { | ||
112 | num_parent_ranges = (success/sizeof(struct linux_prom_ranges)); | ||
113 | prom_adjust_ranges (ranges, num_ranges, parent_ranges, num_parent_ranges); | ||
114 | } | ||
115 | } | ||
116 | prom_adjust_regs(regs, nregs, ranges, num_ranges); | ||
117 | } | ||
118 | } | ||
diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c new file mode 100644 index 000000000000..09d6460165ab --- /dev/null +++ b/arch/sparc/prom/segment.c | |||
@@ -0,0 +1,29 @@ | |||
1 | /* $Id: segment.c,v 1.7 2000/08/26 02:38:03 anton Exp $ | ||
2 | * segment.c: Prom routine to map segments in other contexts before | ||
3 | * a standalone is completely mapped. This is for sun4 and | ||
4 | * sun4c architectures only. | ||
5 | * | ||
6 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | |||
15 | extern void restore_current(void); | ||
16 | |||
17 | /* Set physical segment 'segment' at virtual address 'vaddr' in | ||
18 | * context 'ctx'. | ||
19 | */ | ||
20 | void | ||
21 | prom_putsegment(int ctx, unsigned long vaddr, int segment) | ||
22 | { | ||
23 | unsigned long flags; | ||
24 | spin_lock_irqsave(&prom_lock, flags); | ||
25 | (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); | ||
26 | restore_current(); | ||
27 | spin_unlock_irqrestore(&prom_lock, flags); | ||
28 | return; | ||
29 | } | ||
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c new file mode 100644 index 000000000000..69ca735f0d4e --- /dev/null +++ b/arch/sparc/prom/sun4prom.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996 The Australian National University. | ||
3 | * Copyright (C) 1996 Fujitsu Laboratories Limited | ||
4 | * Copyright (C) 1997 Michael A. Griffith (grif@acm.org) | ||
5 | * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us) | ||
6 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
7 | * | ||
8 | * This software may be distributed under the terms of the Gnu | ||
9 | * Public License version 2 or later | ||
10 | * | ||
11 | * fake a really simple Sun prom for the SUN4 | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <asm/oplib.h> | ||
17 | #include <asm/idprom.h> | ||
18 | #include <asm/machines.h> | ||
19 | #include <asm/sun4prom.h> | ||
20 | #include <asm/asi.h> | ||
21 | #include <asm/contregs.h> | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | static struct linux_romvec sun4romvec; | ||
25 | static struct idprom sun4_idprom; | ||
26 | |||
27 | struct property { | ||
28 | char *name; | ||
29 | char *value; | ||
30 | int length; | ||
31 | }; | ||
32 | |||
33 | struct node { | ||
34 | int level; | ||
35 | struct property *properties; | ||
36 | }; | ||
37 | |||
38 | struct property null_properties = { NULL, NULL, -1 }; | ||
39 | |||
40 | struct property root_properties[] = { | ||
41 | {"device_type", "cpu", 4}, | ||
42 | {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)}, | ||
43 | {NULL, NULL, -1} | ||
44 | }; | ||
45 | |||
46 | struct node nodes[] = { | ||
47 | { 0, &null_properties }, | ||
48 | { 0, root_properties }, | ||
49 | { -1,&null_properties } | ||
50 | }; | ||
51 | |||
52 | |||
53 | static int no_nextnode(int node) | ||
54 | { | ||
55 | if (nodes[node].level == nodes[node+1].level) | ||
56 | return node+1; | ||
57 | return -1; | ||
58 | } | ||
59 | |||
60 | static int no_child(int node) | ||
61 | { | ||
62 | if (nodes[node].level == nodes[node+1].level-1) | ||
63 | return node+1; | ||
64 | return -1; | ||
65 | } | ||
66 | |||
67 | static struct property *find_property(int node,char *name) | ||
68 | { | ||
69 | struct property *prop = &nodes[node].properties[0]; | ||
70 | while (prop && prop->name) { | ||
71 | if (strcmp(prop->name,name) == 0) return prop; | ||
72 | prop++; | ||
73 | } | ||
74 | return NULL; | ||
75 | } | ||
76 | |||
77 | static int no_proplen(int node,char *name) | ||
78 | { | ||
79 | struct property *prop = find_property(node,name); | ||
80 | if (prop) return prop->length; | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | static int no_getprop(int node,char *name,char *value) | ||
85 | { | ||
86 | struct property *prop = find_property(node,name); | ||
87 | if (prop) { | ||
88 | memcpy(value,prop->value,prop->length); | ||
89 | return 1; | ||
90 | } | ||
91 | return -1; | ||
92 | } | ||
93 | |||
94 | static int no_setprop(int node,char *name,char *value,int len) | ||
95 | { | ||
96 | return -1; | ||
97 | } | ||
98 | |||
99 | static char *no_nextprop(int node,char *name) | ||
100 | { | ||
101 | struct property *prop = find_property(node,name); | ||
102 | if (prop) return prop[1].name; | ||
103 | return NULL; | ||
104 | } | ||
105 | |||
106 | static struct linux_nodeops sun4_nodeops = { | ||
107 | no_nextnode, | ||
108 | no_child, | ||
109 | no_proplen, | ||
110 | no_getprop, | ||
111 | no_setprop, | ||
112 | no_nextprop | ||
113 | }; | ||
114 | |||
115 | static int synch_hook; | ||
116 | |||
117 | struct linux_romvec * __init sun4_prom_init(void) | ||
118 | { | ||
119 | int i; | ||
120 | unsigned char x; | ||
121 | char *p; | ||
122 | |||
123 | p = (char *)&sun4_idprom; | ||
124 | for (i = 0; i < sizeof(sun4_idprom); i++) { | ||
125 | __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) : | ||
126 | "r" (AC_IDPROM + i), "i" (ASI_CONTROL)); | ||
127 | *p++ = x; | ||
128 | } | ||
129 | |||
130 | memset(&sun4romvec,0,sizeof(sun4romvec)); | ||
131 | |||
132 | sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR; | ||
133 | |||
134 | sun4romvec.pv_romvers = 40; | ||
135 | sun4romvec.pv_nodeops = &sun4_nodeops; | ||
136 | sun4romvec.pv_reboot = sun4_romvec->reboot; | ||
137 | sun4romvec.pv_abort = sun4_romvec->abortentry; | ||
138 | sun4romvec.pv_halt = sun4_romvec->exittomon; | ||
139 | sun4romvec.pv_synchook = (void (**)(void))&synch_hook; | ||
140 | sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap; | ||
141 | sun4romvec.pv_v0bootargs = sun4_romvec->bootParam; | ||
142 | sun4romvec.pv_nbgetchar = sun4_romvec->mayget; | ||
143 | sun4romvec.pv_nbputchar = sun4_romvec->mayput; | ||
144 | sun4romvec.pv_stdin = sun4_romvec->insource; | ||
145 | sun4romvec.pv_stdout = sun4_romvec->outsink; | ||
146 | |||
147 | /* | ||
148 | * We turn on the LEDs to let folks without monitors or | ||
149 | * terminals know we booted. Nothing too fancy now. They | ||
150 | * are all on, except for LED 5, which blinks. When we | ||
151 | * have more time, we can teach the penguin to say "By your | ||
152 | * command" or "Activating turbo boost, Michael". :-) | ||
153 | */ | ||
154 | sun4_romvec->setLEDs(0x0); | ||
155 | |||
156 | printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n", | ||
157 | sun4_romvec->monid, | ||
158 | sun4_romvec->romvecversion); | ||
159 | |||
160 | return &sun4romvec; | ||
161 | } | ||
diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c new file mode 100644 index 000000000000..2bf03ee8cde5 --- /dev/null +++ b/arch/sparc/prom/tree.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* $Id: tree.c,v 1.26 2000/08/26 02:38:03 anton Exp $ | ||
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 | */ | ||
7 | |||
8 | #define PROMLIB_INTERNAL | ||
9 | |||
10 | #include <linux/string.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/ctype.h> | ||
15 | |||
16 | #include <asm/openprom.h> | ||
17 | #include <asm/oplib.h> | ||
18 | |||
19 | extern void restore_current(void); | ||
20 | |||
21 | static char promlib_buf[128]; | ||
22 | |||
23 | /* Internal version of prom_getchild that does not alter return values. */ | ||
24 | int __prom_getchild(int node) | ||
25 | { | ||
26 | unsigned long flags; | ||
27 | int cnode; | ||
28 | |||
29 | spin_lock_irqsave(&prom_lock, flags); | ||
30 | cnode = prom_nodeops->no_child(node); | ||
31 | restore_current(); | ||
32 | spin_unlock_irqrestore(&prom_lock, flags); | ||
33 | |||
34 | return cnode; | ||
35 | } | ||
36 | |||
37 | /* Return the child of node 'node' or zero if no this node has no | ||
38 | * direct descendent. | ||
39 | */ | ||
40 | int prom_getchild(int node) | ||
41 | { | ||
42 | int cnode; | ||
43 | |||
44 | if (node == -1) | ||
45 | return 0; | ||
46 | |||
47 | cnode = __prom_getchild(node); | ||
48 | if (cnode == 0 || cnode == -1) | ||
49 | return 0; | ||
50 | |||
51 | return cnode; | ||
52 | } | ||
53 | |||
54 | /* Internal version of prom_getsibling that does not alter return values. */ | ||
55 | int __prom_getsibling(int node) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | int cnode; | ||
59 | |||
60 | spin_lock_irqsave(&prom_lock, flags); | ||
61 | cnode = prom_nodeops->no_nextnode(node); | ||
62 | restore_current(); | ||
63 | spin_unlock_irqrestore(&prom_lock, flags); | ||
64 | |||
65 | return cnode; | ||
66 | } | ||
67 | |||
68 | /* Return the next sibling of node 'node' or zero if no more siblings | ||
69 | * at this level of depth in the tree. | ||
70 | */ | ||
71 | int prom_getsibling(int node) | ||
72 | { | ||
73 | int sibnode; | ||
74 | |||
75 | if (node == -1) | ||
76 | return 0; | ||
77 | |||
78 | sibnode = __prom_getsibling(node); | ||
79 | if (sibnode == 0 || sibnode == -1) | ||
80 | return 0; | ||
81 | |||
82 | return sibnode; | ||
83 | } | ||
84 | |||
85 | /* Return the length in bytes of property 'prop' at node 'node'. | ||
86 | * Return -1 on error. | ||
87 | */ | ||
88 | int prom_getproplen(int node, char *prop) | ||
89 | { | ||
90 | int ret; | ||
91 | unsigned long flags; | ||
92 | |||
93 | if((!node) || (!prop)) | ||
94 | return -1; | ||
95 | |||
96 | spin_lock_irqsave(&prom_lock, flags); | ||
97 | ret = prom_nodeops->no_proplen(node, prop); | ||
98 | restore_current(); | ||
99 | spin_unlock_irqrestore(&prom_lock, flags); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* Acquire a property 'prop' at node 'node' and place it in | ||
104 | * 'buffer' which has a size of 'bufsize'. If the acquisition | ||
105 | * was successful the length will be returned, else -1 is returned. | ||
106 | */ | ||
107 | int prom_getproperty(int node, char *prop, char *buffer, int bufsize) | ||
108 | { | ||
109 | int plen, ret; | ||
110 | unsigned long flags; | ||
111 | |||
112 | plen = prom_getproplen(node, prop); | ||
113 | if((plen > bufsize) || (plen == 0) || (plen == -1)) | ||
114 | return -1; | ||
115 | /* Ok, things seem all right. */ | ||
116 | spin_lock_irqsave(&prom_lock, flags); | ||
117 | ret = prom_nodeops->no_getprop(node, prop, buffer); | ||
118 | restore_current(); | ||
119 | spin_unlock_irqrestore(&prom_lock, flags); | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | /* Acquire an integer property and return its value. Returns -1 | ||
124 | * on failure. | ||
125 | */ | ||
126 | int prom_getint(int node, char *prop) | ||
127 | { | ||
128 | static int intprop; | ||
129 | |||
130 | if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) | ||
131 | return intprop; | ||
132 | |||
133 | return -1; | ||
134 | } | ||
135 | |||
136 | /* Acquire an integer property, upon error return the passed default | ||
137 | * integer. | ||
138 | */ | ||
139 | int prom_getintdefault(int node, char *property, int deflt) | ||
140 | { | ||
141 | int retval; | ||
142 | |||
143 | retval = prom_getint(node, property); | ||
144 | if(retval == -1) return deflt; | ||
145 | |||
146 | return retval; | ||
147 | } | ||
148 | |||
149 | /* Acquire a boolean property, 1=TRUE 0=FALSE. */ | ||
150 | int prom_getbool(int node, char *prop) | ||
151 | { | ||
152 | int retval; | ||
153 | |||
154 | retval = prom_getproplen(node, prop); | ||
155 | if(retval == -1) return 0; | ||
156 | return 1; | ||
157 | } | ||
158 | |||
159 | /* Acquire a property whose value is a string, returns a null | ||
160 | * string on error. The char pointer is the user supplied string | ||
161 | * buffer. | ||
162 | */ | ||
163 | void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) | ||
164 | { | ||
165 | int len; | ||
166 | |||
167 | len = prom_getproperty(node, prop, user_buf, ubuf_size); | ||
168 | if(len != -1) return; | ||
169 | user_buf[0] = 0; | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | |||
174 | /* Does the device at node 'node' have name 'name'? | ||
175 | * YES = 1 NO = 0 | ||
176 | */ | ||
177 | int prom_nodematch(int node, char *name) | ||
178 | { | ||
179 | int error; | ||
180 | |||
181 | static char namebuf[128]; | ||
182 | error = prom_getproperty(node, "name", namebuf, sizeof(namebuf)); | ||
183 | if (error == -1) return 0; | ||
184 | if(strcmp(namebuf, name) == 0) return 1; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* Search siblings at 'node_start' for a node with name | ||
189 | * 'nodename'. Return node if successful, zero if not. | ||
190 | */ | ||
191 | int prom_searchsiblings(int node_start, char *nodename) | ||
192 | { | ||
193 | |||
194 | int thisnode, error; | ||
195 | |||
196 | for(thisnode = node_start; thisnode; | ||
197 | thisnode=prom_getsibling(thisnode)) { | ||
198 | error = prom_getproperty(thisnode, "name", promlib_buf, | ||
199 | sizeof(promlib_buf)); | ||
200 | /* Should this ever happen? */ | ||
201 | if(error == -1) continue; | ||
202 | if(strcmp(nodename, promlib_buf)==0) return thisnode; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* Gets name in the form prom v2+ uses it (name@x,yyyyy or name (if no reg)) */ | ||
209 | int prom_getname (int node, char *buffer, int len) | ||
210 | { | ||
211 | int i; | ||
212 | struct linux_prom_registers reg[PROMREG_MAX]; | ||
213 | |||
214 | i = prom_getproperty (node, "name", buffer, len); | ||
215 | if (i <= 0) return -1; | ||
216 | buffer [i] = 0; | ||
217 | len -= i; | ||
218 | i = prom_getproperty (node, "reg", (char *)reg, sizeof (reg)); | ||
219 | if (i <= 0) return 0; | ||
220 | if (len < 11) return -1; | ||
221 | buffer = strchr (buffer, 0); | ||
222 | sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | /* Interal version of nextprop that does not alter return values. */ | ||
227 | char * __prom_nextprop(int node, char * oprop) | ||
228 | { | ||
229 | unsigned long flags; | ||
230 | char *prop; | ||
231 | |||
232 | spin_lock_irqsave(&prom_lock, flags); | ||
233 | prop = prom_nodeops->no_nextprop(node, oprop); | ||
234 | restore_current(); | ||
235 | spin_unlock_irqrestore(&prom_lock, flags); | ||
236 | |||
237 | return prop; | ||
238 | } | ||
239 | |||
240 | /* Return the first property name for node 'node'. */ | ||
241 | /* buffer is unused argument, but as v9 uses it, we need to have the same interface */ | ||
242 | char * prom_firstprop(int node, char *bufer) | ||
243 | { | ||
244 | if (node == 0 || node == -1) | ||
245 | return ""; | ||
246 | |||
247 | return __prom_nextprop(node, ""); | ||
248 | } | ||
249 | |||
250 | /* Return the property type string after property type 'oprop' | ||
251 | * at node 'node' . Returns empty string if no more | ||
252 | * property types for this node. | ||
253 | */ | ||
254 | char * prom_nextprop(int node, char *oprop, char *buffer) | ||
255 | { | ||
256 | if (node == 0 || node == -1) | ||
257 | return ""; | ||
258 | |||
259 | return __prom_nextprop(node, oprop); | ||
260 | } | ||
261 | |||
262 | int prom_finddevice(char *name) | ||
263 | { | ||
264 | char nbuf[128]; | ||
265 | char *s = name, *d; | ||
266 | int node = prom_root_node, node2; | ||
267 | unsigned int which_io, phys_addr; | ||
268 | struct linux_prom_registers reg[PROMREG_MAX]; | ||
269 | |||
270 | while (*s++) { | ||
271 | if (!*s) return node; /* path '.../' is legal */ | ||
272 | node = prom_getchild(node); | ||
273 | |||
274 | for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) | ||
275 | *d++ = *s++; | ||
276 | *d = 0; | ||
277 | |||
278 | node = prom_searchsiblings(node, nbuf); | ||
279 | if (!node) | ||
280 | return 0; | ||
281 | |||
282 | if (*s == '@') { | ||
283 | if (isxdigit(s[1]) && s[2] == ',') { | ||
284 | which_io = simple_strtoul(s+1, NULL, 16); | ||
285 | phys_addr = simple_strtoul(s+3, &d, 16); | ||
286 | if (d != s + 3 && (!*d || *d == '/') | ||
287 | && d <= s + 3 + 8) { | ||
288 | node2 = node; | ||
289 | while (node2 && node2 != -1) { | ||
290 | if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { | ||
291 | if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { | ||
292 | node = node2; | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | node2 = prom_getsibling(node2); | ||
297 | if (!node2 || node2 == -1) | ||
298 | break; | ||
299 | node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); | ||
300 | } | ||
301 | } | ||
302 | } | ||
303 | while (*s != 0 && *s != '/') s++; | ||
304 | } | ||
305 | } | ||
306 | return node; | ||
307 | } | ||
308 | |||
309 | int prom_node_has_property(int node, char *prop) | ||
310 | { | ||
311 | char *current_property = ""; | ||
312 | |||
313 | do { | ||
314 | current_property = prom_nextprop(node, current_property, NULL); | ||
315 | if(!strcmp(current_property, prop)) | ||
316 | return 1; | ||
317 | } while (*current_property); | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | /* Set property 'pname' at node 'node' to value 'value' which has a length | ||
322 | * of 'size' bytes. Return the number of bytes the prom accepted. | ||
323 | */ | ||
324 | int prom_setprop(int node, char *pname, char *value, int size) | ||
325 | { | ||
326 | unsigned long flags; | ||
327 | int ret; | ||
328 | |||
329 | if(size == 0) return 0; | ||
330 | if((pname == 0) || (value == 0)) return 0; | ||
331 | spin_lock_irqsave(&prom_lock, flags); | ||
332 | ret = prom_nodeops->no_setprop(node, pname, value, size); | ||
333 | restore_current(); | ||
334 | spin_unlock_irqrestore(&prom_lock, flags); | ||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | int prom_inst2pkg(int inst) | ||
339 | { | ||
340 | int node; | ||
341 | unsigned long flags; | ||
342 | |||
343 | spin_lock_irqsave(&prom_lock, flags); | ||
344 | node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); | ||
345 | restore_current(); | ||
346 | spin_unlock_irqrestore(&prom_lock, flags); | ||
347 | if (node == -1) return 0; | ||
348 | return node; | ||
349 | } | ||
350 | |||
351 | /* Return 'node' assigned to a particular prom 'path' | ||
352 | * FIXME: Should work for v0 as well | ||
353 | */ | ||
354 | int prom_pathtoinode(char *path) | ||
355 | { | ||
356 | int node, inst; | ||
357 | |||
358 | inst = prom_devopen (path); | ||
359 | if (inst == -1) return 0; | ||
360 | node = prom_inst2pkg (inst); | ||
361 | prom_devclose (inst); | ||
362 | if (node == -1) return 0; | ||
363 | return node; | ||
364 | } | ||