1 /* $Id: p1275.c,v 1.17 1999/08/31 19:25:43 davem Exp $
2 * p1275.c: Sun IEEE 1275 PROM low level interface routines
4 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
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>
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>
21 long prom_callback
; /* 0x00 */
22 void (*prom_cif_handler
)(long *); /* 0x08 */
23 unsigned long prom_cif_stack
; /* 0x10 */
24 unsigned long prom_args
[23]; /* 0x18 */
25 char prom_buffer
[3000];
28 extern void prom_world(int);
30 void prom_cif_interface (void)
32 __asm__
__volatile__ ("
34 ldx [%%o0 + 0x010], %%o1 ! prom_cif_stack
35 save %%o1, -0x190, %%sp
36 ldx [%%i0 + 0x008], %%l2 ! prom_cif_handler
38 wrpr %%g0, 0x15, %%pstate ! save alternate globals
39 stx %%g1, [%%sp + 2047 + 0x0b0]
40 stx %%g2, [%%sp + 2047 + 0x0b8]
41 stx %%g3, [%%sp + 2047 + 0x0c0]
42 stx %%g4, [%%sp + 2047 + 0x0c8]
43 stx %%g5, [%%sp + 2047 + 0x0d0]
44 stx %%g6, [%%sp + 2047 + 0x0d8]
45 stx %%g7, [%%sp + 2047 + 0x0e0]
46 wrpr %%g0, 0x814, %%pstate ! save interrupt globals
47 stx %%g1, [%%sp + 2047 + 0x0e8]
48 stx %%g2, [%%sp + 2047 + 0x0f0]
49 stx %%g3, [%%sp + 2047 + 0x0f8]
50 stx %%g4, [%%sp + 2047 + 0x100]
51 stx %%g5, [%%sp + 2047 + 0x108]
52 stx %%g6, [%%sp + 2047 + 0x110]
53 stx %%g7, [%%sp + 2047 + 0x118]
54 wrpr %%g0, 0x14, %%pstate ! save normal globals
55 stx %%g1, [%%sp + 2047 + 0x120]
56 stx %%g2, [%%sp + 2047 + 0x128]
57 stx %%g3, [%%sp + 2047 + 0x130]
58 stx %%g4, [%%sp + 2047 + 0x138]
59 stx %%g5, [%%sp + 2047 + 0x140]
60 stx %%g6, [%%sp + 2047 + 0x148]
61 stx %%g7, [%%sp + 2047 + 0x150]
62 wrpr %%g0, 0x414, %%pstate ! save mmu globals
63 stx %%g1, [%%sp + 2047 + 0x158]
64 stx %%g2, [%%sp + 2047 + 0x160]
65 stx %%g3, [%%sp + 2047 + 0x168]
66 stx %%g4, [%%sp + 2047 + 0x170]
67 stx %%g5, [%%sp + 2047 + 0x178]
68 stx %%g6, [%%sp + 2047 + 0x180]
69 stx %%g7, [%%sp + 2047 + 0x188]
70 mov %%g1, %%l0 ! also save to locals, so we can handle
71 mov %%g2, %%l1 ! tlb faults later on, when accessing
72 mov %%g3, %%l3 ! the stack.
74 wrpr %%l4, %1, %%pstate ! turn off interrupts
76 add %%i0, 0x018, %%o0 ! prom_args
77 wrpr %%g0, 0x414, %%pstate ! restore mmu globals
82 wrpr %%g0, 0x14, %%pstate ! restore normal globals
83 ldx [%%sp + 2047 + 0x120], %%g1
84 ldx [%%sp + 2047 + 0x128], %%g2
85 ldx [%%sp + 2047 + 0x130], %%g3
86 ldx [%%sp + 2047 + 0x138], %%g4
87 ldx [%%sp + 2047 + 0x140], %%g5
88 ldx [%%sp + 2047 + 0x148], %%g6
89 ldx [%%sp + 2047 + 0x150], %%g7
90 wrpr %%g0, 0x814, %%pstate ! restore interrupt globals
91 ldx [%%sp + 2047 + 0x0e8], %%g1
92 ldx [%%sp + 2047 + 0x0f0], %%g2
93 ldx [%%sp + 2047 + 0x0f8], %%g3
94 ldx [%%sp + 2047 + 0x100], %%g4
95 ldx [%%sp + 2047 + 0x108], %%g5
96 ldx [%%sp + 2047 + 0x110], %%g6
97 ldx [%%sp + 2047 + 0x118], %%g7
98 wrpr %%g0, 0x15, %%pstate ! restore alternate globals
99 ldx [%%sp + 2047 + 0x0b0], %%g1
100 ldx [%%sp + 2047 + 0x0b8], %%g2
101 ldx [%%sp + 2047 + 0x0c0], %%g3
102 ldx [%%sp + 2047 + 0x0c8], %%g4
103 ldx [%%sp + 2047 + 0x0d0], %%g5
104 ldx [%%sp + 2047 + 0x0d8], %%g6
105 ldx [%%sp + 2047 + 0x0e0], %%g7
106 wrpr %%l4, 0, %%pstate ! restore original pstate
109 " : : "r" (&p1275buf
), "i" (PSTATE_IE
));
112 void prom_cif_callback(void)
114 __asm__
__volatile__ ("
116 save %%sp, -0x270, %%sp
118 wrpr %%g0, 0x15, %%pstate ! save PROM alternate globals
119 stx %%g1, [%%sp + 2047 + 0x0b0]
120 stx %%g2, [%%sp + 2047 + 0x0b8]
121 stx %%g3, [%%sp + 2047 + 0x0c0]
122 stx %%g4, [%%sp + 2047 + 0x0c8]
123 stx %%g5, [%%sp + 2047 + 0x0d0]
124 stx %%g6, [%%sp + 2047 + 0x0d8]
125 stx %%g7, [%%sp + 2047 + 0x0e0]
126 ! restore Linux alternate globals
127 ldx [%%sp + 2047 + 0x190], %%g1
128 ldx [%%sp + 2047 + 0x198], %%g2
129 ldx [%%sp + 2047 + 0x1a0], %%g3
130 ldx [%%sp + 2047 + 0x1a8], %%g4
131 ldx [%%sp + 2047 + 0x1b0], %%g5
132 ldx [%%sp + 2047 + 0x1b8], %%g6
133 ldx [%%sp + 2047 + 0x1c0], %%g7
134 wrpr %%g0, 0x814, %%pstate ! save PROM interrupt globals
135 stx %%g1, [%%sp + 2047 + 0x0e8]
136 stx %%g2, [%%sp + 2047 + 0x0f0]
137 stx %%g3, [%%sp + 2047 + 0x0f8]
138 stx %%g4, [%%sp + 2047 + 0x100]
139 stx %%g5, [%%sp + 2047 + 0x108]
140 stx %%g6, [%%sp + 2047 + 0x110]
141 stx %%g7, [%%sp + 2047 + 0x118]
142 ! restore Linux interrupt globals
143 ldx [%%sp + 2047 + 0x1c8], %%g1
144 ldx [%%sp + 2047 + 0x1d0], %%g2
145 ldx [%%sp + 2047 + 0x1d8], %%g3
146 ldx [%%sp + 2047 + 0x1e0], %%g4
147 ldx [%%sp + 2047 + 0x1e8], %%g5
148 ldx [%%sp + 2047 + 0x1f0], %%g6
149 ldx [%%sp + 2047 + 0x1f8], %%g7
150 wrpr %%g0, 0x14, %%pstate ! save PROM normal globals
151 stx %%g1, [%%sp + 2047 + 0x120]
152 stx %%g2, [%%sp + 2047 + 0x128]
153 stx %%g3, [%%sp + 2047 + 0x130]
154 stx %%g4, [%%sp + 2047 + 0x138]
155 stx %%g5, [%%sp + 2047 + 0x140]
156 stx %%g6, [%%sp + 2047 + 0x148]
157 stx %%g7, [%%sp + 2047 + 0x150]
158 ! restore Linux normal globals
159 ldx [%%sp + 2047 + 0x200], %%g1
160 ldx [%%sp + 2047 + 0x208], %%g2
161 ldx [%%sp + 2047 + 0x210], %%g3
162 ldx [%%sp + 2047 + 0x218], %%g4
163 ldx [%%sp + 2047 + 0x220], %%g5
164 ldx [%%sp + 2047 + 0x228], %%g6
165 ldx [%%sp + 2047 + 0x230], %%g7
166 wrpr %%g0, 0x414, %%pstate ! save PROM mmu globals
167 stx %%g1, [%%sp + 2047 + 0x158]
168 stx %%g2, [%%sp + 2047 + 0x160]
169 stx %%g3, [%%sp + 2047 + 0x168]
170 stx %%g4, [%%sp + 2047 + 0x170]
171 stx %%g5, [%%sp + 2047 + 0x178]
172 stx %%g6, [%%sp + 2047 + 0x180]
173 stx %%g7, [%%sp + 2047 + 0x188]
174 ! restore Linux mmu globals
175 ldx [%%sp + 2047 + 0x238], %%o0
176 ldx [%%sp + 2047 + 0x240], %%o1
177 ldx [%%sp + 2047 + 0x248], %%l2
178 ldx [%%sp + 2047 + 0x250], %%l3
179 ldx [%%sp + 2047 + 0x258], %%l5
180 ldx [%%sp + 2047 + 0x260], %%l6
181 ldx [%%sp + 2047 + 0x268], %%l7
182 ! switch to Linux tba
183 sethi %%hi(sparc64_ttable_tl0), %%l1
184 rdpr %%tba, %%l0 ! save PROM tba
192 wrpr %%l1, %%tba ! install Linux tba
193 wrpr %%l4, 0, %%pstate ! restore PSTATE
196 ldx [%%i1 + 0x000], %%l2
202 wrpr %%g0, 0x14, %%pstate ! interrupts off
203 ! restore PROM mmu globals
204 ldx [%%sp + 2047 + 0x158], %%o0
205 ldx [%%sp + 2047 + 0x160], %%o1
206 ldx [%%sp + 2047 + 0x168], %%l2
207 ldx [%%sp + 2047 + 0x170], %%l3
208 ldx [%%sp + 2047 + 0x178], %%l5
209 ldx [%%sp + 2047 + 0x180], %%l6
210 ldx [%%sp + 2047 + 0x188], %%l7
211 wrpr %%g0, 0x414, %%pstate ! restore PROM mmu globals
219 wrpr %%l0, %%tba ! restore PROM tba
220 wrpr %%g0, 0x14, %%pstate ! restore PROM normal globals
221 ldx [%%sp + 2047 + 0x120], %%g1
222 ldx [%%sp + 2047 + 0x128], %%g2
223 ldx [%%sp + 2047 + 0x130], %%g3
224 ldx [%%sp + 2047 + 0x138], %%g4
225 ldx [%%sp + 2047 + 0x140], %%g5
226 ldx [%%sp + 2047 + 0x148], %%g6
227 ldx [%%sp + 2047 + 0x150], %%g7
228 wrpr %%g0, 0x814, %%pstate ! restore PROM interrupt globals
229 ldx [%%sp + 2047 + 0x0e8], %%g1
230 ldx [%%sp + 2047 + 0x0f0], %%g2
231 ldx [%%sp + 2047 + 0x0f8], %%g3
232 ldx [%%sp + 2047 + 0x100], %%g4
233 ldx [%%sp + 2047 + 0x108], %%g5
234 ldx [%%sp + 2047 + 0x110], %%g6
235 ldx [%%sp + 2047 + 0x118], %%g7
236 wrpr %%g0, 0x15, %%pstate ! restore PROM alternate globals
237 ldx [%%sp + 2047 + 0x0b0], %%g1
238 ldx [%%sp + 2047 + 0x0b8], %%g2
239 ldx [%%sp + 2047 + 0x0c0], %%g3
240 ldx [%%sp + 2047 + 0x0c8], %%g4
241 ldx [%%sp + 2047 + 0x0d0], %%g5
242 ldx [%%sp + 2047 + 0x0d8], %%g6
243 ldx [%%sp + 2047 + 0x0e0], %%g7
244 wrpr %%l4, 0, %%pstate
246 restore %%l1, 0, %%o0
247 " : : "r" (&p1275buf
), "i" (PSTATE_PRIV
));
250 /* We need some SMP protection here. But be careful as
251 * prom callback code can call into here too, this is why
252 * the counter is needed. -DaveM
254 static int prom_entry_depth
= 0;
255 static spinlock_t prom_entry_lock
= SPIN_LOCK_UNLOCKED
;
257 extern void smp_capture(void);
258 extern void smp_release(void);
261 static __inline__
unsigned long prom_get_lock(void)
265 __save_and_cli(flags
);
266 if (prom_entry_depth
== 0) {
267 spin_lock(&prom_entry_lock
);
269 #if 1 /* DEBUGGING */
270 if (prom_entry_depth
!= 0)
271 panic("prom_get_lock");
282 static __inline__
void prom_release_lock(unsigned long flags
)
284 if (--prom_entry_depth
== 0) {
288 spin_unlock(&prom_entry_lock
);
290 __restore_flags(flags
);
293 long p1275_cmd (char *service
, long fmt
, ...)
302 p
= p1275buf
.prom_buffer
;
303 ctx
= spitfire_get_primary_context ();
306 spitfire_set_primary_context (0);
309 flags
= prom_get_lock();
311 p1275buf
.prom_args
[0] = (unsigned long)p
; /* service */
313 p
= (char *)(((long)(strchr (p
, 0) + 8)) & ~7);
314 p1275buf
.prom_args
[1] = nargs
= (fmt
& 0x0f); /* nargs */
315 p1275buf
.prom_args
[2] = nrets
= ((fmt
& 0xf0) >> 4); /* nrets */
318 for (i
= 0; i
< nargs
; i
++, attrs
>>= 3) {
319 switch (attrs
& 0x7) {
320 case P1275_ARG_NUMBER
:
321 p1275buf
.prom_args
[i
+ 3] =
322 (unsigned)va_arg(list
, long);
324 case P1275_ARG_IN_64B
:
325 p1275buf
.prom_args
[i
+ 3] =
326 va_arg(list
, unsigned long);
328 case P1275_ARG_IN_STRING
:
329 strcpy (p
, va_arg(list
, char *));
330 p1275buf
.prom_args
[i
+ 3] = (unsigned long)p
;
331 p
= (char *)(((long)(strchr (p
, 0) + 8)) & ~7);
333 case P1275_ARG_OUT_BUF
:
334 (void) va_arg(list
, char *);
335 p1275buf
.prom_args
[i
+ 3] = (unsigned long)p
;
336 x
= va_arg(list
, long);
338 p
= (char *)(((long)(p
+ (int)x
+ 7)) & ~7);
339 p1275buf
.prom_args
[i
+ 3] = x
;
341 case P1275_ARG_IN_BUF
:
342 q
= va_arg(list
, char *);
343 p1275buf
.prom_args
[i
+ 3] = (unsigned long)p
;
344 x
= va_arg(list
, long);
346 memcpy (p
, q
, (int)x
);
347 p
= (char *)(((long)(p
+ (int)x
+ 7)) & ~7);
348 p1275buf
.prom_args
[i
+ 3] = x
;
350 case P1275_ARG_OUT_32B
:
351 (void) va_arg(list
, char *);
352 p1275buf
.prom_args
[i
+ 3] = (unsigned long)p
;
355 case P1275_ARG_IN_FUNCTION
:
356 p1275buf
.prom_args
[i
+ 3] =
357 (unsigned long)prom_cif_callback
;
358 p1275buf
.prom_callback
= va_arg(list
, long);
365 prom_cif_interface();
370 for (i
= 0; i
< nargs
; i
++, attrs
>>= 3) {
371 switch (attrs
& 0x7) {
372 case P1275_ARG_NUMBER
:
373 (void) va_arg(list
, long);
375 case P1275_ARG_IN_STRING
:
376 (void) va_arg(list
, char *);
378 case P1275_ARG_IN_FUNCTION
:
379 (void) va_arg(list
, long);
381 case P1275_ARG_IN_BUF
:
382 (void) va_arg(list
, char *);
383 (void) va_arg(list
, long);
386 case P1275_ARG_OUT_BUF
:
387 p
= va_arg(list
, char *);
388 x
= va_arg(list
, long);
389 memcpy (p
, (char *)(p1275buf
.prom_args
[i
+ 3]), (int)x
);
392 case P1275_ARG_OUT_32B
:
393 p
= va_arg(list
, char *);
394 memcpy (p
, (char *)(p1275buf
.prom_args
[i
+ 3]), 32);
399 x
= p1275buf
.prom_args
[nargs
+ 3];
401 prom_release_lock(flags
);
404 spitfire_set_primary_context (ctx
);
409 void prom_cif_init(void *cif_handler
, void *cif_stack
)
411 p1275buf
.prom_cif_handler
= (void (*)(long *))cif_handler
;
412 p1275buf
.prom_cif_stack
= (unsigned long)cif_stack
;