Import 2.3.18pre1
[davej-history.git] / arch / sparc64 / prom / p1275.c
blob8ddb5aec3fd1bca06d88d976a383b08212941640
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)
5 */
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>
20 struct {
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];
26 } p1275buf;
28 extern void prom_world(int);
30 void prom_cif_interface (void)
32 __asm__ __volatile__ ("
33 mov %0, %%o0
34 ldx [%%o0 + 0x010], %%o1 ! prom_cif_stack
35 save %%o1, -0x190, %%sp
36 ldx [%%i0 + 0x008], %%l2 ! prom_cif_handler
37 rdpr %%pstate, %%l4
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.
73 mov %%g7, %%l5
74 wrpr %%l4, %1, %%pstate ! turn off interrupts
75 call %%l2
76 add %%i0, 0x018, %%o0 ! prom_args
77 wrpr %%g0, 0x414, %%pstate ! restore mmu globals
78 mov %%l0, %%g1
79 mov %%l1, %%g2
80 mov %%l3, %%g3
81 mov %%l5, %%g7
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
108 restore
109 " : : "r" (&p1275buf), "i" (PSTATE_IE));
112 void prom_cif_callback(void)
114 __asm__ __volatile__ ("
115 mov %0, %%o1
116 save %%sp, -0x270, %%sp
117 rdpr %%pstate, %%l4
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
185 mov %%o0, %%g1
186 mov %%o1, %%g2
187 mov %%l2, %%g3
188 mov %%l3, %%g4
189 mov %%l5, %%g5
190 mov %%l6, %%g6
191 mov %%l7, %%g7
192 wrpr %%l1, %%tba ! install Linux tba
193 wrpr %%l4, 0, %%pstate ! restore PSTATE
194 call prom_world
195 mov %%g0, %%o0
196 ldx [%%i1 + 0x000], %%l2
197 call %%l2
198 mov %%i0, %%o0
199 mov %%o0, %%l1
200 call prom_world
201 or %%g0, 1, %%o0
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
212 mov %%o0, %%g1
213 mov %%o1, %%g2
214 mov %%l2, %%g3
215 mov %%l3, %%g4
216 mov %%l5, %%g5
217 mov %%l6, %%g6
218 mov %%l7, %%g7
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;
256 #ifdef __SMP__
257 extern void smp_capture(void);
258 extern void smp_release(void);
259 #endif
261 static __inline__ unsigned long prom_get_lock(void)
263 unsigned long flags;
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");
272 #endif
273 #ifdef __SMP__
274 smp_capture();
275 #endif
277 prom_entry_depth++;
279 return flags;
282 static __inline__ void prom_release_lock(unsigned long flags)
284 if (--prom_entry_depth == 0) {
285 #ifdef __SMP__
286 smp_release();
287 #endif
288 spin_unlock(&prom_entry_lock);
290 __restore_flags(flags);
293 long p1275_cmd (char *service, long fmt, ...)
295 char *p, *q;
296 unsigned long flags;
297 int nargs, nrets, i;
298 va_list list;
299 long attrs, x;
300 long ctx = 0;
302 p = p1275buf.prom_buffer;
303 ctx = spitfire_get_primary_context ();
304 if (ctx) {
305 flushw_user ();
306 spitfire_set_primary_context (0);
309 flags = prom_get_lock();
311 p1275buf.prom_args[0] = (unsigned long)p; /* service */
312 strcpy (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 */
316 attrs = fmt >> 8;
317 va_start(list, fmt);
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);
323 break;
324 case P1275_ARG_IN_64B:
325 p1275buf.prom_args[i + 3] =
326 va_arg(list, unsigned long);
327 break;
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);
332 break;
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);
337 i++; attrs >>= 3;
338 p = (char *)(((long)(p + (int)x + 7)) & ~7);
339 p1275buf.prom_args[i + 3] = x;
340 break;
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);
345 i++; attrs >>= 3;
346 memcpy (p, q, (int)x);
347 p = (char *)(((long)(p + (int)x + 7)) & ~7);
348 p1275buf.prom_args[i + 3] = x;
349 break;
350 case P1275_ARG_OUT_32B:
351 (void) va_arg(list, char *);
352 p1275buf.prom_args[i + 3] = (unsigned long)p;
353 p += 32;
354 break;
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);
359 break;
362 va_end(list);
364 prom_world(1);
365 prom_cif_interface();
366 prom_world(0);
368 attrs = fmt >> 8;
369 va_start(list, fmt);
370 for (i = 0; i < nargs; i++, attrs >>= 3) {
371 switch (attrs & 0x7) {
372 case P1275_ARG_NUMBER:
373 (void) va_arg(list, long);
374 break;
375 case P1275_ARG_IN_STRING:
376 (void) va_arg(list, char *);
377 break;
378 case P1275_ARG_IN_FUNCTION:
379 (void) va_arg(list, long);
380 break;
381 case P1275_ARG_IN_BUF:
382 (void) va_arg(list, char *);
383 (void) va_arg(list, long);
384 i++; attrs >>= 3;
385 break;
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);
390 i++; attrs >>= 3;
391 break;
392 case P1275_ARG_OUT_32B:
393 p = va_arg(list, char *);
394 memcpy (p, (char *)(p1275buf.prom_args[i + 3]), 32);
395 break;
398 va_end(list);
399 x = p1275buf.prom_args [nargs + 3];
401 prom_release_lock(flags);
403 if (ctx)
404 spitfire_set_primary_context (ctx);
406 return x;
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;