File: /usr/src/linux/arch/sparc64/prom/misc.c

1     /* $Id: misc.c,v 1.19 2000/06/30 10:18:38 davem 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      * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7      */
8     
9     #include <linux/config.h>
10     #include <linux/types.h>
11     #include <linux/kernel.h>
12     #include <linux/sched.h>
13     #include <linux/interrupt.h>
14     #include <linux/delay.h>
15     #include <asm/openprom.h>
16     #include <asm/oplib.h>
17     
18     /* Reset and reboot the machine with the command 'bcommand'. */
19     void
20     prom_reboot(char *bcommand)
21     {
22     	p1275_cmd ("boot", P1275_ARG(0,P1275_ARG_IN_STRING)|
23     		           P1275_INOUT(1,0), bcommand);
24     }
25     
26     /* Forth evaluate the expression contained in 'fstring'. */
27     void
28     prom_feval(char *fstring)
29     {
30     	if(!fstring || fstring[0] == 0)
31     		return;
32     	p1275_cmd ("interpret", P1275_ARG(0,P1275_ARG_IN_STRING)|
33     				P1275_INOUT(1,1), fstring);
34     }
35     
36     /* We want to do this more nicely some day. */
37     #ifdef CONFIG_SUN_CONSOLE
38     extern void (*prom_palette)(int);
39     extern int serial_console;
40     #endif
41     
42     #ifdef CONFIG_SMP
43     extern void smp_capture(void);
44     extern void smp_release(void);
45     #endif
46     
47     /* Drop into the prom, with the chance to continue with the 'go'
48      * prom command.
49      */
50     void
51     prom_cmdline(void)
52     {
53     	unsigned long flags;
54     
55     	__save_and_cli(flags);
56     
57     #ifdef CONFIG_SUN_CONSOLE
58     	if(!serial_console && prom_palette)
59     		prom_palette (1);
60     #endif
61     
62     	/* We always arrive here via a serial interrupt.
63     	 * So in order for everything to work reliably, even
64     	 * on SMP, we need to drop the IRQ locks we hold.
65     	 */
66     #ifdef CONFIG_SMP
67     	irq_exit(smp_processor_id(), 0);
68     	smp_capture();
69     #else
70     	local_irq_count(smp_processor_id())--;
71     #endif
72     
73     	p1275_cmd ("enter", P1275_INOUT(0,0));
74     
75     #ifdef CONFIG_SMP
76     	smp_release();
77     	irq_enter(smp_processor_id(), 0);
78     	spin_unlock_wait(&__br_write_locks[BR_GLOBALIRQ_LOCK].lock);
79     #else
80     	local_irq_count(smp_processor_id())++;
81     #endif
82     
83     #ifdef CONFIG_SUN_CONSOLE
84     	if(!serial_console && prom_palette)
85     		prom_palette (0);
86     #endif
87     
88     	__restore_flags(flags);
89     }
90     
91     #ifdef CONFIG_SMP
92     extern void smp_promstop_others(void);
93     #endif
94     
95     /* Drop into the prom, but completely terminate the program.
96      * No chance of continuing.
97      */
98     void
99     prom_halt(void)
100     {
101     #ifdef CONFIG_SMP
102     	smp_promstop_others();
103     	udelay(8000);
104     #endif
105     again:
106     	p1275_cmd ("exit", P1275_INOUT(0,0));
107     	goto again; /* PROM is out to get me -DaveM */
108     }
109     
110     /* Set prom sync handler to call function 'funcp'. */
111     void
112     prom_setcallback(callback_func_t funcp)
113     {
114     	if(!funcp) return;
115     	p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)|
116     				   P1275_INOUT(1,1), funcp);
117     }
118     
119     /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
120      * format type.  'num_bytes' is the number of bytes that your idbuf
121      * has space for.  Returns 0xff on error.
122      */
123     unsigned char
124     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)) return 0xff;
130     	if(!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
131     		return idbuf[0];
132     
133     	return 0xff;
134     }
135     
136     /* Get the major prom version number. */
137     int
138     prom_version(void)
139     {
140     	return PROM_P1275;
141     }
142     
143     /* Get the prom plugin-revision. */
144     int
145     prom_getrev(void)
146     {
147     	return prom_rev;
148     }
149     
150     /* Get the prom firmware print revision. */
151     int
152     prom_getprev(void)
153     {
154     	return prom_prev;
155     }
156     
157     /* Install Linux trap table so PROM uses that instead of it's own. */
158     void prom_set_trap_table(unsigned long tba)
159     {
160     	p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba);
161     }
162     
163     int mmu_ihandle_cache = 0;
164     
165     int prom_get_mmu_ihandle(void)
166     {
167     	int node, ret;
168     
169     	if (mmu_ihandle_cache != 0)
170     		return mmu_ihandle_cache;
171     
172     	node = prom_finddevice("/chosen");
173     	ret = prom_getint(node, "mmu");
174     	if(ret == -1 || ret == 0)
175     		mmu_ihandle_cache = -1;
176     	else
177     		mmu_ihandle_cache = ret;
178     
179     	return ret;
180     }
181     
182     static int prom_get_memory_ihandle(void)
183     {
184     	static int memory_ihandle_cache = 0;
185     	int node, ret;
186     
187     	if (memory_ihandle_cache != 0)
188     		return memory_ihandle_cache;
189     
190     	node = prom_finddevice("/chosen");
191     	ret = prom_getint(node, "memory");
192     	if (ret == -1 || ret == 0)
193     		memory_ihandle_cache = -1;
194     	else
195     		memory_ihandle_cache = ret;
196     
197     	return ret;
198     }
199     
200     /* Load explicit I/D TLB entries. */
201     long prom_itlb_load(unsigned long index,
202     		    unsigned long tte_data,
203     		    unsigned long vaddr)
204     {
205     	return p1275_cmd("call-method",
206     			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
207     			  P1275_ARG(2, P1275_ARG_IN_64B) |
208     			  P1275_ARG(3, P1275_ARG_IN_64B) |
209     			  P1275_INOUT(5, 1)),
210     			 "SUNW,itlb-load",
211     			 prom_get_mmu_ihandle(),
212     			 /* And then our actual args are pushed backwards. */
213     			 vaddr,
214     			 tte_data,
215     			 index);
216     }
217     
218     long prom_dtlb_load(unsigned long index,
219     		    unsigned long tte_data,
220     		    unsigned long vaddr)
221     {
222     	return p1275_cmd("call-method",
223     			 (P1275_ARG(0, P1275_ARG_IN_STRING) |
224     			  P1275_ARG(2, P1275_ARG_IN_64B) |
225     			  P1275_ARG(3, P1275_ARG_IN_64B) |
226     			  P1275_INOUT(5, 1)),
227     			 "SUNW,dtlb-load",
228     			 prom_get_mmu_ihandle(),
229     			 /* And then our actual args are pushed backwards. */
230     			 vaddr,
231     			 tte_data,
232     			 index);
233     }
234     
235     int prom_map(int mode, unsigned long size,
236     	     unsigned long vaddr, unsigned long paddr)
237     {
238     	int ret = p1275_cmd("call-method",
239     			    (P1275_ARG(0, P1275_ARG_IN_STRING) |
240     			     P1275_ARG(3, P1275_ARG_IN_64B) |
241     			     P1275_ARG(4, P1275_ARG_IN_64B) |
242     			     P1275_ARG(6, P1275_ARG_IN_64B) |
243     			     P1275_INOUT(7, 1)),
244     			    "map",
245     			    prom_get_mmu_ihandle(),
246     			    mode,
247     			    size,
248     			    vaddr,
249     			    0,
250     			    paddr);
251     
252     	if (ret == 0)
253     		ret = -1;
254     	return ret;
255     }
256     
257     void prom_unmap(unsigned long size, unsigned long vaddr)
258     {
259     	p1275_cmd("call-method",
260     		  (P1275_ARG(0, P1275_ARG_IN_STRING) |
261     		   P1275_ARG(2, P1275_ARG_IN_64B) |
262     		   P1275_ARG(3, P1275_ARG_IN_64B) |
263     		   P1275_INOUT(4, 0)),
264     		  "unmap",
265     		  prom_get_mmu_ihandle(),
266     		  size,
267     		  vaddr);
268     }
269     
270     /* Set aside physical memory which is not touched or modified
271      * across soft resets.
272      */
273     unsigned long prom_retain(char *name,
274     			  unsigned long pa_low, unsigned long pa_high,
275     			  long size, long align)
276     {
277     	/* XXX I don't think we return multiple values correctly.
278     	 * XXX OBP supposedly returns pa_low/pa_high here, how does
279     	 * XXX it work?
280     	 */
281     
282     	/* If align is zero, the pa_low/pa_high args are passed,
283     	 * else they are not.
284     	 */
285     	if(align == 0)
286     		return p1275_cmd("SUNW,retain",
287     				 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
288     				 name, pa_low, pa_high, size, align);
289     	else
290     		return p1275_cmd("SUNW,retain",
291     				 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
292     				 name, size, align);
293     }
294     
295     /* Get "Unumber" string for the SIMM at the given
296      * memory address.  Usually this will be of the form
297      * "Uxxxx" where xxxx is a decimal number which is
298      * etched into the motherboard next to the SIMM slot
299      * in question.
300      */
301     int prom_getunumber(int syndrome_code,
302     		    unsigned long phys_addr,
303     		    char *buf, int buflen)
304     {
305     	return p1275_cmd("call-method",
306     			 (P1275_ARG(0, P1275_ARG_IN_STRING)	|
307     			  P1275_ARG(3, P1275_ARG_OUT_BUF)	|
308     			  P1275_ARG(6, P1275_ARG_IN_64B)	|
309     			  P1275_INOUT(8, 2)),
310     			 "SUNW,get-unumber", prom_get_memory_ihandle(),
311     			 buflen, buf, P1275_SIZE(buflen),
312     			 0, phys_addr, syndrome_code);
313     }
314     
315     /* Power management extensions. */
316     void prom_sleepself(void)
317     {
318     	p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
319     }
320     
321     int prom_sleepsystem(void)
322     {
323     	return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
324     }
325     
326     int prom_wakeupsystem(void)
327     {
328     	return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
329     }
330     
331     #ifdef CONFIG_SMP
332     void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
333     {
334     	p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
335     }
336     
337     void prom_stopself(void)
338     {
339     	p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
340     }
341     
342     void prom_idleself(void)
343     {
344     	p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
345     }
346     
347     void prom_resumecpu(int cpunode)
348     {
349     	p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
350     }
351     #endif
352