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 20static 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 37void 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'. */ 51void 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'. */ 68void 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} 82EXPORT_SYMBOL(prom_feval); 83 84/* Drop into the prom, with the chance to continue with the 'go' 85 * prom command. 86 */ 87void 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 */ 114void 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 122again: 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 130void 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 */ 151unsigned 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 164int 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 182static 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. */ 202static 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 222long 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 229long 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 236int 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 262void 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 */ 280int 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 */ 317int 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. */ 342void 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 352int 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 365int 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 379void 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 392void 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 405void 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 416void 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 426void 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 436void 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