Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.13 451 lines 9.1 kB view raw
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#ifdef CONFIG_SMP 85extern void smp_capture(void); 86extern void smp_release(void); 87#endif 88 89/* Drop into the prom, with the chance to continue with the 'go' 90 * prom command. 91 */ 92void 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 */ 119void 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 127again: 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 135void 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 */ 156unsigned 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 169int 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 187static 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. */ 207static 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 227long 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 234long 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 241int 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 267void 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 */ 285int 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 */ 322int 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. */ 347void 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 357int 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 370int 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 384void 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 397void 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 410void 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 421void 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 431void 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 441void 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