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