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