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