Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sparc/prom/misc_64.c
26425 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* misc.c: Miscellaneous prom functions that don't belong
4
* anywhere else.
5
*
6
* Copyright (C) 1995 David S. Miller ([email protected])
7
* Copyright (C) 1996,1997 Jakub Jelinek ([email protected])
8
*/
9
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 <linux/module.h>
16
17
#include <asm/openprom.h>
18
#include <asm/oplib.h>
19
#include <asm/ldc.h>
20
21
static int prom_service_exists(const char *service_name)
22
{
23
unsigned long args[5];
24
25
args[0] = (unsigned long) "test";
26
args[1] = 1;
27
args[2] = 1;
28
args[3] = (unsigned long) service_name;
29
args[4] = (unsigned long) -1;
30
31
p1275_cmd_direct(args);
32
33
if (args[4])
34
return 0;
35
return 1;
36
}
37
38
void prom_sun4v_guest_soft_state(void)
39
{
40
const char *svc = "SUNW,soft-state-supported";
41
unsigned long args[3];
42
43
if (!prom_service_exists(svc))
44
return;
45
args[0] = (unsigned long) svc;
46
args[1] = 0;
47
args[2] = 0;
48
p1275_cmd_direct(args);
49
}
50
51
/* Reset and reboot the machine with the command 'bcommand'. */
52
void prom_reboot(const char *bcommand)
53
{
54
unsigned long args[4];
55
56
#ifdef CONFIG_SUN_LDOMS
57
if (ldom_domaining_enabled)
58
ldom_reboot(bcommand);
59
#endif
60
args[0] = (unsigned long) "boot";
61
args[1] = 1;
62
args[2] = 0;
63
args[3] = (unsigned long) bcommand;
64
65
p1275_cmd_direct(args);
66
}
67
68
/* Forth evaluate the expression contained in 'fstring'. */
69
void prom_feval(const char *fstring)
70
{
71
unsigned long args[5];
72
73
if (!fstring || fstring[0] == 0)
74
return;
75
args[0] = (unsigned long) "interpret";
76
args[1] = 1;
77
args[2] = 1;
78
args[3] = (unsigned long) fstring;
79
args[4] = (unsigned long) -1;
80
81
p1275_cmd_direct(args);
82
}
83
EXPORT_SYMBOL(prom_feval);
84
85
/* Drop into the prom, with the chance to continue with the 'go'
86
* prom command.
87
*/
88
void prom_cmdline(void)
89
{
90
unsigned long args[3];
91
unsigned long flags;
92
93
local_irq_save(flags);
94
95
#ifdef CONFIG_SMP
96
smp_capture();
97
#endif
98
99
args[0] = (unsigned long) "enter";
100
args[1] = 0;
101
args[2] = 0;
102
103
p1275_cmd_direct(args);
104
105
#ifdef CONFIG_SMP
106
smp_release();
107
#endif
108
109
local_irq_restore(flags);
110
}
111
112
/* Drop into the prom, but completely terminate the program.
113
* No chance of continuing.
114
*/
115
void notrace prom_halt(void)
116
{
117
unsigned long args[3];
118
119
#ifdef CONFIG_SUN_LDOMS
120
if (ldom_domaining_enabled)
121
ldom_power_off();
122
#endif
123
again:
124
args[0] = (unsigned long) "exit";
125
args[1] = 0;
126
args[2] = 0;
127
p1275_cmd_direct(args);
128
goto again; /* PROM is out to get me -DaveM */
129
}
130
131
void prom_halt_power_off(void)
132
{
133
unsigned long args[3];
134
135
#ifdef CONFIG_SUN_LDOMS
136
if (ldom_domaining_enabled)
137
ldom_power_off();
138
#endif
139
args[0] = (unsigned long) "SUNW,power-off";
140
args[1] = 0;
141
args[2] = 0;
142
p1275_cmd_direct(args);
143
144
/* if nothing else helps, we just halt */
145
prom_halt();
146
}
147
148
/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
149
* format type. 'num_bytes' is the number of bytes that your idbuf
150
* has space for. Returns 0xff on error.
151
*/
152
unsigned char prom_get_idprom(char *idbuf, int num_bytes)
153
{
154
int len;
155
156
len = prom_getproplen(prom_root_node, "idprom");
157
if ((len >num_bytes) || (len == -1))
158
return 0xff;
159
if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
160
return idbuf[0];
161
162
return 0xff;
163
}
164
165
static int prom_get_mmu_ihandle(void)
166
{
167
phandle node;
168
int ret;
169
170
if (prom_mmu_ihandle_cache != 0)
171
return prom_mmu_ihandle_cache;
172
173
node = prom_finddevice(prom_chosen_path);
174
ret = prom_getint(node, prom_mmu_name);
175
if (ret == -1 || ret == 0)
176
prom_mmu_ihandle_cache = -1;
177
else
178
prom_mmu_ihandle_cache = ret;
179
180
return ret;
181
}
182
183
static int prom_get_memory_ihandle(void)
184
{
185
static int memory_ihandle_cache;
186
phandle node;
187
int ret;
188
189
if (memory_ihandle_cache != 0)
190
return memory_ihandle_cache;
191
192
node = prom_finddevice("/chosen");
193
ret = prom_getint(node, "memory");
194
if (ret == -1 || ret == 0)
195
memory_ihandle_cache = -1;
196
else
197
memory_ihandle_cache = ret;
198
199
return ret;
200
}
201
202
/* Load explicit I/D TLB entries. */
203
static long tlb_load(const char *type, unsigned long index,
204
unsigned long tte_data, unsigned long vaddr)
205
{
206
unsigned long args[9];
207
208
args[0] = (unsigned long) prom_callmethod_name;
209
args[1] = 5;
210
args[2] = 1;
211
args[3] = (unsigned long) type;
212
args[4] = (unsigned int) prom_get_mmu_ihandle();
213
args[5] = vaddr;
214
args[6] = tte_data;
215
args[7] = index;
216
args[8] = (unsigned long) -1;
217
218
p1275_cmd_direct(args);
219
220
return (long) args[8];
221
}
222
223
long prom_itlb_load(unsigned long index,
224
unsigned long tte_data,
225
unsigned long vaddr)
226
{
227
return tlb_load("SUNW,itlb-load", index, tte_data, vaddr);
228
}
229
230
long prom_dtlb_load(unsigned long index,
231
unsigned long tte_data,
232
unsigned long vaddr)
233
{
234
return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr);
235
}
236
237
int prom_map(int mode, unsigned long size,
238
unsigned long vaddr, unsigned long paddr)
239
{
240
unsigned long args[11];
241
int ret;
242
243
args[0] = (unsigned long) prom_callmethod_name;
244
args[1] = 7;
245
args[2] = 1;
246
args[3] = (unsigned long) prom_map_name;
247
args[4] = (unsigned int) prom_get_mmu_ihandle();
248
args[5] = (unsigned int) mode;
249
args[6] = size;
250
args[7] = vaddr;
251
args[8] = 0;
252
args[9] = paddr;
253
args[10] = (unsigned long) -1;
254
255
p1275_cmd_direct(args);
256
257
ret = (int) args[10];
258
if (ret == 0)
259
ret = -1;
260
return ret;
261
}
262
263
void prom_unmap(unsigned long size, unsigned long vaddr)
264
{
265
unsigned long args[7];
266
267
args[0] = (unsigned long) prom_callmethod_name;
268
args[1] = 4;
269
args[2] = 0;
270
args[3] = (unsigned long) prom_unmap_name;
271
args[4] = (unsigned int) prom_get_mmu_ihandle();
272
args[5] = size;
273
args[6] = vaddr;
274
275
p1275_cmd_direct(args);
276
}
277
278
/* Set aside physical memory which is not touched or modified
279
* across soft resets.
280
*/
281
int prom_retain(const char *name, unsigned long size,
282
unsigned long align, unsigned long *paddr)
283
{
284
unsigned long args[11];
285
286
args[0] = (unsigned long) prom_callmethod_name;
287
args[1] = 5;
288
args[2] = 3;
289
args[3] = (unsigned long) "SUNW,retain";
290
args[4] = (unsigned int) prom_get_memory_ihandle();
291
args[5] = align;
292
args[6] = size;
293
args[7] = (unsigned long) name;
294
args[8] = (unsigned long) -1;
295
args[9] = (unsigned long) -1;
296
args[10] = (unsigned long) -1;
297
298
p1275_cmd_direct(args);
299
300
if (args[8])
301
return (int) args[8];
302
303
/* Next we get "phys_high" then "phys_low". On 64-bit
304
* the phys_high cell is don't care since the phys_low
305
* cell has the full value.
306
*/
307
*paddr = args[10];
308
309
return 0;
310
}
311
312
/* Get "Unumber" string for the SIMM at the given
313
* memory address. Usually this will be of the form
314
* "Uxxxx" where xxxx is a decimal number which is
315
* etched into the motherboard next to the SIMM slot
316
* in question.
317
*/
318
int prom_getunumber(int syndrome_code,
319
unsigned long phys_addr,
320
char *buf, int buflen)
321
{
322
unsigned long args[12];
323
324
args[0] = (unsigned long) prom_callmethod_name;
325
args[1] = 7;
326
args[2] = 2;
327
args[3] = (unsigned long) "SUNW,get-unumber";
328
args[4] = (unsigned int) prom_get_memory_ihandle();
329
args[5] = buflen;
330
args[6] = (unsigned long) buf;
331
args[7] = 0;
332
args[8] = phys_addr;
333
args[9] = (unsigned int) syndrome_code;
334
args[10] = (unsigned long) -1;
335
args[11] = (unsigned long) -1;
336
337
p1275_cmd_direct(args);
338
339
return (int) args[10];
340
}
341
342
/* Power management extensions. */
343
void prom_sleepself(void)
344
{
345
unsigned long args[3];
346
347
args[0] = (unsigned long) "SUNW,sleep-self";
348
args[1] = 0;
349
args[2] = 0;
350
p1275_cmd_direct(args);
351
}
352
353
int prom_sleepsystem(void)
354
{
355
unsigned long args[4];
356
357
args[0] = (unsigned long) "SUNW,sleep-system";
358
args[1] = 0;
359
args[2] = 1;
360
args[3] = (unsigned long) -1;
361
p1275_cmd_direct(args);
362
363
return (int) args[3];
364
}
365
366
int prom_wakeupsystem(void)
367
{
368
unsigned long args[4];
369
370
args[0] = (unsigned long) "SUNW,wakeup-system";
371
args[1] = 0;
372
args[2] = 1;
373
args[3] = (unsigned long) -1;
374
p1275_cmd_direct(args);
375
376
return (int) args[3];
377
}
378
379
#ifdef CONFIG_SMP
380
void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
381
{
382
unsigned long args[6];
383
384
args[0] = (unsigned long) "SUNW,start-cpu";
385
args[1] = 3;
386
args[2] = 0;
387
args[3] = (unsigned int) cpunode;
388
args[4] = pc;
389
args[5] = arg;
390
p1275_cmd_direct(args);
391
}
392
393
void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
394
{
395
unsigned long args[6];
396
397
args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid";
398
args[1] = 3;
399
args[2] = 0;
400
args[3] = (unsigned int) cpuid;
401
args[4] = pc;
402
args[5] = arg;
403
p1275_cmd_direct(args);
404
}
405
406
void prom_stopcpu_cpuid(int cpuid)
407
{
408
unsigned long args[4];
409
410
args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid";
411
args[1] = 1;
412
args[2] = 0;
413
args[3] = (unsigned int) cpuid;
414
p1275_cmd_direct(args);
415
}
416
417
void prom_stopself(void)
418
{
419
unsigned long args[3];
420
421
args[0] = (unsigned long) "SUNW,stop-self";
422
args[1] = 0;
423
args[2] = 0;
424
p1275_cmd_direct(args);
425
}
426
427
void prom_idleself(void)
428
{
429
unsigned long args[3];
430
431
args[0] = (unsigned long) "SUNW,idle-self";
432
args[1] = 0;
433
args[2] = 0;
434
p1275_cmd_direct(args);
435
}
436
437
void prom_resumecpu(int cpunode)
438
{
439
unsigned long args[4];
440
441
args[0] = (unsigned long) "SUNW,resume-cpu";
442
args[1] = 1;
443
args[2] = 0;
444
args[3] = (unsigned int) cpunode;
445
p1275_cmd_direct(args);
446
}
447
#endif
448
449