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 21 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 #ifdef CONFIG_SMP 86 extern void smp_capture(void); 87 extern void smp_release(void); 88 #endif 89 90 /* Drop into the prom, with the chance to continue with the 'go' 91 * prom command. 92 */ 93 void 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 */ 120 void 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 128 again: 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 136 void 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 /* Set prom sync handler to call function 'funcp'. */ 154 void prom_setcallback(callback_func_t funcp) 155 { 156 unsigned long args[5]; 157 if (!funcp) 158 return; 159 args[0] = (unsigned long) "set-callback"; 160 args[1] = 1; 161 args[2] = 1; 162 args[3] = (unsigned long) funcp; 163 args[4] = (unsigned long) -1; 164 p1275_cmd_direct(args); 165 } 166 167 /* Get the idprom and stuff it into buffer 'idbuf'. Returns the 168 * format type. 'num_bytes' is the number of bytes that your idbuf 169 * has space for. Returns 0xff on error. 170 */ 171 unsigned char prom_get_idprom(char *idbuf, int num_bytes) 172 { 173 int len; 174 175 len = prom_getproplen(prom_root_node, "idprom"); 176 if ((len >num_bytes) || (len == -1)) 177 return 0xff; 178 if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) 179 return idbuf[0]; 180 181 return 0xff; 182 } 183 184 int prom_get_mmu_ihandle(void) 185 { 186 phandle node; 187 int ret; 188 189 if (prom_mmu_ihandle_cache != 0) 190 return prom_mmu_ihandle_cache; 191 192 node = prom_finddevice(prom_chosen_path); 193 ret = prom_getint(node, prom_mmu_name); 194 if (ret == -1 || ret == 0) 195 prom_mmu_ihandle_cache = -1; 196 else 197 prom_mmu_ihandle_cache = ret; 198 199 return ret; 200 } 201 202 static int prom_get_memory_ihandle(void) 203 { 204 static int memory_ihandle_cache; 205 phandle node; 206 int ret; 207 208 if (memory_ihandle_cache != 0) 209 return memory_ihandle_cache; 210 211 node = prom_finddevice("/chosen"); 212 ret = prom_getint(node, "memory"); 213 if (ret == -1 || ret == 0) 214 memory_ihandle_cache = -1; 215 else 216 memory_ihandle_cache = ret; 217 218 return ret; 219 } 220 221 /* Load explicit I/D TLB entries. */ 222 static long tlb_load(const char *type, unsigned long index, 223 unsigned long tte_data, unsigned long vaddr) 224 { 225 unsigned long args[9]; 226 227 args[0] = (unsigned long) prom_callmethod_name; 228 args[1] = 5; 229 args[2] = 1; 230 args[3] = (unsigned long) type; 231 args[4] = (unsigned int) prom_get_mmu_ihandle(); 232 args[5] = vaddr; 233 args[6] = tte_data; 234 args[7] = index; 235 args[8] = (unsigned long) -1; 236 237 p1275_cmd_direct(args); 238 239 return (long) args[8]; 240 } 241 242 long prom_itlb_load(unsigned long index, 243 unsigned long tte_data, 244 unsigned long vaddr) 245 { 246 return tlb_load("SUNW,itlb-load", index, tte_data, vaddr); 247 } 248 249 long prom_dtlb_load(unsigned long index, 250 unsigned long tte_data, 251 unsigned long vaddr) 252 { 253 return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr); 254 } 255 256 int prom_map(int mode, unsigned long size, 257 unsigned long vaddr, unsigned long paddr) 258 { 259 unsigned long args[11]; 260 int ret; 261 262 args[0] = (unsigned long) prom_callmethod_name; 263 args[1] = 7; 264 args[2] = 1; 265 args[3] = (unsigned long) prom_map_name; 266 args[4] = (unsigned int) prom_get_mmu_ihandle(); 267 args[5] = (unsigned int) mode; 268 args[6] = size; 269 args[7] = vaddr; 270 args[8] = 0; 271 args[9] = paddr; 272 args[10] = (unsigned long) -1; 273 274 p1275_cmd_direct(args); 275 276 ret = (int) args[10]; 277 if (ret == 0) 278 ret = -1; 279 return ret; 280 } 281 282 void prom_unmap(unsigned long size, unsigned long vaddr) 283 { 284 unsigned long args[7]; 285 286 args[0] = (unsigned long) prom_callmethod_name; 287 args[1] = 4; 288 args[2] = 0; 289 args[3] = (unsigned long) prom_unmap_name; 290 args[4] = (unsigned int) prom_get_mmu_ihandle(); 291 args[5] = size; 292 args[6] = vaddr; 293 294 p1275_cmd_direct(args); 295 } 296 297 /* Set aside physical memory which is not touched or modified 298 * across soft resets. 299 */ 300 int prom_retain(const char *name, unsigned long size, 301 unsigned long align, unsigned long *paddr) 302 { 303 unsigned long args[11]; 304 305 args[0] = (unsigned long) prom_callmethod_name; 306 args[1] = 5; 307 args[2] = 3; 308 args[3] = (unsigned long) "SUNW,retain"; 309 args[4] = (unsigned int) prom_get_memory_ihandle(); 310 args[5] = align; 311 args[6] = size; 312 args[7] = (unsigned long) name; 313 args[8] = (unsigned long) -1; 314 args[9] = (unsigned long) -1; 315 args[10] = (unsigned long) -1; 316 317 p1275_cmd_direct(args); 318 319 if (args[8]) 320 return (int) args[8]; 321 322 /* Next we get "phys_high" then "phys_low". On 64-bit 323 * the phys_high cell is don't care since the phys_low 324 * cell has the full value. 325 */ 326 *paddr = args[10]; 327 328 return 0; 329 } 330 331 /* Get "Unumber" string for the SIMM at the given 332 * memory address. Usually this will be of the form 333 * "Uxxxx" where xxxx is a decimal number which is 334 * etched into the motherboard next to the SIMM slot 335 * in question. 336 */ 337 int prom_getunumber(int syndrome_code, 338 unsigned long phys_addr, 339 char *buf, int buflen) 340 { 341 unsigned long args[12]; 342 343 args[0] = (unsigned long) prom_callmethod_name; 344 args[1] = 7; 345 args[2] = 2; 346 args[3] = (unsigned long) "SUNW,get-unumber"; 347 args[4] = (unsigned int) prom_get_memory_ihandle(); 348 args[5] = buflen; 349 args[6] = (unsigned long) buf; 350 args[7] = 0; 351 args[8] = phys_addr; 352 args[9] = (unsigned int) syndrome_code; 353 args[10] = (unsigned long) -1; 354 args[11] = (unsigned long) -1; 355 356 p1275_cmd_direct(args); 357 358 return (int) args[10]; 359 } 360 361 /* Power management extensions. */ 362 void prom_sleepself(void) 363 { 364 unsigned long args[3]; 365 366 args[0] = (unsigned long) "SUNW,sleep-self"; 367 args[1] = 0; 368 args[2] = 0; 369 p1275_cmd_direct(args); 370 } 371 372 int prom_sleepsystem(void) 373 { 374 unsigned long args[4]; 375 376 args[0] = (unsigned long) "SUNW,sleep-system"; 377 args[1] = 0; 378 args[2] = 1; 379 args[3] = (unsigned long) -1; 380 p1275_cmd_direct(args); 381 382 return (int) args[3]; 383 } 384 385 int prom_wakeupsystem(void) 386 { 387 unsigned long args[4]; 388 389 args[0] = (unsigned long) "SUNW,wakeup-system"; 390 args[1] = 0; 391 args[2] = 1; 392 args[3] = (unsigned long) -1; 393 p1275_cmd_direct(args); 394 395 return (int) args[3]; 396 } 397 398 #ifdef CONFIG_SMP 399 void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) 400 { 401 unsigned long args[6]; 402 403 args[0] = (unsigned long) "SUNW,start-cpu"; 404 args[1] = 3; 405 args[2] = 0; 406 args[3] = (unsigned int) cpunode; 407 args[4] = pc; 408 args[5] = arg; 409 p1275_cmd_direct(args); 410 } 411 412 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) 413 { 414 unsigned long args[6]; 415 416 args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid"; 417 args[1] = 3; 418 args[2] = 0; 419 args[3] = (unsigned int) cpuid; 420 args[4] = pc; 421 args[5] = arg; 422 p1275_cmd_direct(args); 423 } 424 425 void prom_stopcpu_cpuid(int cpuid) 426 { 427 unsigned long args[4]; 428 429 args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid"; 430 args[1] = 1; 431 args[2] = 0; 432 args[3] = (unsigned int) cpuid; 433 p1275_cmd_direct(args); 434 } 435 436 void prom_stopself(void) 437 { 438 unsigned long args[3]; 439 440 args[0] = (unsigned long) "SUNW,stop-self"; 441 args[1] = 0; 442 args[2] = 0; 443 p1275_cmd_direct(args); 444 } 445 446 void prom_idleself(void) 447 { 448 unsigned long args[3]; 449 450 args[0] = (unsigned long) "SUNW,idle-self"; 451 args[1] = 0; 452 args[2] = 0; 453 p1275_cmd_direct(args); 454 } 455 456 void prom_resumecpu(int cpunode) 457 { 458 unsigned long args[4]; 459 460 args[0] = (unsigned long) "SUNW,resume-cpu"; 461 args[1] = 1; 462 args[2] = 0; 463 args[3] = (unsigned int) cpunode; 464 p1275_cmd_direct(args); 465 } 466 #endif 467