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