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