Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
[linux-2.6] / arch / sparc64 / prom / misc.c
1 /*
2  * misc.c:  Miscellaneous prom functions that don't belong
3  *          anywhere else.
4  *
5  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
6  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7  */
8
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/interrupt.h>
13 #include <linux/delay.h>
14 #include <asm/openprom.h>
15 #include <asm/oplib.h>
16 #include <asm/system.h>
17 #include <asm/ldc.h>
18
19 int prom_service_exists(const char *service_name)
20 {
21         int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) |
22                             P1275_INOUT(1, 1), service_name);
23
24         if (err)
25                 return 0;
26         return 1;
27 }
28
29 void prom_sun4v_guest_soft_state(void)
30 {
31         const char *svc = "SUNW,soft-state-supported";
32
33         if (!prom_service_exists(svc))
34                 return;
35         p1275_cmd(svc, P1275_INOUT(0, 0));
36 }
37
38 /* Reset and reboot the machine with the command 'bcommand'. */
39 void prom_reboot(const char *bcommand)
40 {
41 #ifdef CONFIG_SUN_LDOMS
42         if (ldom_domaining_enabled)
43                 ldom_reboot(bcommand);
44 #endif
45         p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
46                   P1275_INOUT(1, 0), bcommand);
47 }
48
49 /* Forth evaluate the expression contained in 'fstring'. */
50 void prom_feval(const char *fstring)
51 {
52         if (!fstring || fstring[0] == 0)
53                 return;
54         p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) |
55                   P1275_INOUT(1, 1), fstring);
56 }
57
58 #ifdef CONFIG_SMP
59 extern void smp_capture(void);
60 extern void smp_release(void);
61 #endif
62
63 /* Drop into the prom, with the chance to continue with the 'go'
64  * prom command.
65  */
66 void prom_cmdline(void)
67 {
68         unsigned long flags;
69
70         local_irq_save(flags);
71
72 #ifdef CONFIG_SMP
73         smp_capture();
74 #endif
75
76         p1275_cmd("enter", P1275_INOUT(0, 0));
77
78 #ifdef CONFIG_SMP
79         smp_release();
80 #endif
81
82         local_irq_restore(flags);
83 }
84
85 /* Drop into the prom, but completely terminate the program.
86  * No chance of continuing.
87  */
88 void prom_halt(void)
89 {
90 #ifdef CONFIG_SUN_LDOMS
91         if (ldom_domaining_enabled)
92                 ldom_power_off();
93 #endif
94 again:
95         p1275_cmd("exit", P1275_INOUT(0, 0));
96         goto again; /* PROM is out to get me -DaveM */
97 }
98
99 void prom_halt_power_off(void)
100 {
101 #ifdef CONFIG_SUN_LDOMS
102         if (ldom_domaining_enabled)
103                 ldom_power_off();
104 #endif
105         p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
106
107         /* if nothing else helps, we just halt */
108         prom_halt();
109 }
110
111 /* Set prom sync handler to call function 'funcp'. */
112 void prom_setcallback(callback_func_t funcp)
113 {
114         if (!funcp)
115                 return;
116         p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) |
117                   P1275_INOUT(1, 1), funcp);
118 }
119
120 /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
121  * format type.  'num_bytes' is the number of bytes that your idbuf
122  * has space for.  Returns 0xff on error.
123  */
124 unsigned char prom_get_idprom(char *idbuf, int num_bytes)
125 {
126         int len;
127
128         len = prom_getproplen(prom_root_node, "idprom");
129         if ((len >num_bytes) || (len == -1))
130                 return 0xff;
131         if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
132                 return idbuf[0];
133
134         return 0xff;
135 }
136
137 int prom_get_mmu_ihandle(void)
138 {
139         int node, ret;
140
141         if (prom_mmu_ihandle_cache != 0)
142                 return prom_mmu_ihandle_cache;
143
144         node = prom_finddevice(prom_chosen_path);
145         ret = prom_getint(node, prom_mmu_name);
146         if (ret == -1 || ret == 0)
147                 prom_mmu_ihandle_cache = -1;
148         else
149                 prom_mmu_ihandle_cache = ret;
150
151         return ret;
152 }
153
154 static int prom_get_memory_ihandle(void)
155 {
156         static int memory_ihandle_cache;
157         int node, ret;
158
159         if (memory_ihandle_cache != 0)
160                 return memory_ihandle_cache;
161
162         node = prom_finddevice("/chosen");
163         ret = prom_getint(node, "memory");
164         if (ret == -1 || ret == 0)
165                 memory_ihandle_cache = -1;
166         else
167                 memory_ihandle_cache = ret;
168
169         return ret;
170 }
171
172 /* Load explicit I/D TLB entries. */
173 long prom_itlb_load(unsigned long index,
174                     unsigned long tte_data,
175                     unsigned long vaddr)
176 {
177         return p1275_cmd(prom_callmethod_name,
178                          (P1275_ARG(0, P1275_ARG_IN_STRING) |
179                           P1275_ARG(2, P1275_ARG_IN_64B) |
180                           P1275_ARG(3, P1275_ARG_IN_64B) |
181                           P1275_INOUT(5, 1)),
182                          "SUNW,itlb-load",
183                          prom_get_mmu_ihandle(),
184                          /* And then our actual args are pushed backwards. */
185                          vaddr,
186                          tte_data,
187                          index);
188 }
189
190 long prom_dtlb_load(unsigned long index,
191                     unsigned long tte_data,
192                     unsigned long vaddr)
193 {
194         return p1275_cmd(prom_callmethod_name,
195                          (P1275_ARG(0, P1275_ARG_IN_STRING) |
196                           P1275_ARG(2, P1275_ARG_IN_64B) |
197                           P1275_ARG(3, P1275_ARG_IN_64B) |
198                           P1275_INOUT(5, 1)),
199                          "SUNW,dtlb-load",
200                          prom_get_mmu_ihandle(),
201                          /* And then our actual args are pushed backwards. */
202                          vaddr,
203                          tte_data,
204                          index);
205 }
206
207 int prom_map(int mode, unsigned long size,
208              unsigned long vaddr, unsigned long paddr)
209 {
210         int ret = p1275_cmd(prom_callmethod_name,
211                             (P1275_ARG(0, P1275_ARG_IN_STRING) |
212                              P1275_ARG(3, P1275_ARG_IN_64B) |
213                              P1275_ARG(4, P1275_ARG_IN_64B) |
214                              P1275_ARG(6, P1275_ARG_IN_64B) |
215                              P1275_INOUT(7, 1)),
216                             prom_map_name,
217                             prom_get_mmu_ihandle(),
218                             mode,
219                             size,
220                             vaddr,
221                             0,
222                             paddr);
223
224         if (ret == 0)
225                 ret = -1;
226         return ret;
227 }
228
229 void prom_unmap(unsigned long size, unsigned long vaddr)
230 {
231         p1275_cmd(prom_callmethod_name,
232                   (P1275_ARG(0, P1275_ARG_IN_STRING) |
233                    P1275_ARG(2, P1275_ARG_IN_64B) |
234                    P1275_ARG(3, P1275_ARG_IN_64B) |
235                    P1275_INOUT(4, 0)),
236                   prom_unmap_name,
237                   prom_get_mmu_ihandle(),
238                   size,
239                   vaddr);
240 }
241
242 /* Set aside physical memory which is not touched or modified
243  * across soft resets.
244  */
245 unsigned long prom_retain(const char *name,
246                           unsigned long pa_low, unsigned long pa_high,
247                           long size, long align)
248 {
249         /* XXX I don't think we return multiple values correctly.
250          * XXX OBP supposedly returns pa_low/pa_high here, how does
251          * XXX it work?
252          */
253
254         /* If align is zero, the pa_low/pa_high args are passed,
255          * else they are not.
256          */
257         if (align == 0)
258                 return p1275_cmd("SUNW,retain",
259                                  (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)),
260                                  name, pa_low, pa_high, size, align);
261         else
262                 return p1275_cmd("SUNW,retain",
263                                  (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)),
264                                  name, size, align);
265 }
266
267 /* Get "Unumber" string for the SIMM at the given
268  * memory address.  Usually this will be of the form
269  * "Uxxxx" where xxxx is a decimal number which is
270  * etched into the motherboard next to the SIMM slot
271  * in question.
272  */
273 int prom_getunumber(int syndrome_code,
274                     unsigned long phys_addr,
275                     char *buf, int buflen)
276 {
277         return p1275_cmd(prom_callmethod_name,
278                          (P1275_ARG(0, P1275_ARG_IN_STRING)     |
279                           P1275_ARG(3, P1275_ARG_OUT_BUF)       |
280                           P1275_ARG(6, P1275_ARG_IN_64B)        |
281                           P1275_INOUT(8, 2)),
282                          "SUNW,get-unumber", prom_get_memory_ihandle(),
283                          buflen, buf, P1275_SIZE(buflen),
284                          0, phys_addr, syndrome_code);
285 }
286
287 /* Power management extensions. */
288 void prom_sleepself(void)
289 {
290         p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
291 }
292
293 int prom_sleepsystem(void)
294 {
295         return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
296 }
297
298 int prom_wakeupsystem(void)
299 {
300         return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
301 }
302
303 #ifdef CONFIG_SMP
304 void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
305 {
306         p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg);
307 }
308
309 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
310 {
311         p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0),
312                   cpuid, pc, arg);
313 }
314
315 void prom_stopcpu_cpuid(int cpuid)
316 {
317         p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
318                   cpuid);
319 }
320
321 void prom_stopself(void)
322 {
323         p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
324 }
325
326 void prom_idleself(void)
327 {
328         p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
329 }
330
331 void prom_resumecpu(int cpunode)
332 {
333         p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
334 }
335 #endif