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/system.h> 19 #include <asm/ldc.h> 20 21 int prom_service_exists(const char *service_name) 22 { 23 int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | 24 P1275_INOUT(1, 1), service_name); 25 26 if (err) 27 return 0; 28 return 1; 29 } 30 31 void prom_sun4v_guest_soft_state(void) 32 { 33 const char *svc = "SUNW,soft-state-supported"; 34 35 if (!prom_service_exists(svc)) 36 return; 37 p1275_cmd(svc, P1275_INOUT(0, 0)); 38 } 39 40 /* Reset and reboot the machine with the command 'bcommand'. */ 41 void prom_reboot(const char *bcommand) 42 { 43 #ifdef CONFIG_SUN_LDOMS 44 if (ldom_domaining_enabled) 45 ldom_reboot(bcommand); 46 #endif 47 p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) | 48 P1275_INOUT(1, 0), bcommand); 49 } 50 51 /* Forth evaluate the expression contained in 'fstring'. */ 52 void prom_feval(const char *fstring) 53 { 54 if (!fstring || fstring[0] == 0) 55 return; 56 p1275_cmd("interpret", P1275_ARG(0, P1275_ARG_IN_STRING) | 57 P1275_INOUT(1, 1), fstring); 58 } 59 EXPORT_SYMBOL(prom_feval); 60 61 #ifdef CONFIG_SMP 62 extern void smp_capture(void); 63 extern void smp_release(void); 64 #endif 65 66 /* Drop into the prom, with the chance to continue with the 'go' 67 * prom command. 68 */ 69 void prom_cmdline(void) 70 { 71 unsigned long flags; 72 73 local_irq_save(flags); 74 75 #ifdef CONFIG_SMP 76 smp_capture(); 77 #endif 78 79 p1275_cmd("enter", P1275_INOUT(0, 0)); 80 81 #ifdef CONFIG_SMP 82 smp_release(); 83 #endif 84 85 local_irq_restore(flags); 86 } 87 88 /* Drop into the prom, but completely terminate the program. 89 * No chance of continuing. 90 */ 91 void prom_halt(void) 92 { 93 #ifdef CONFIG_SUN_LDOMS 94 if (ldom_domaining_enabled) 95 ldom_power_off(); 96 #endif 97 again: 98 p1275_cmd("exit", P1275_INOUT(0, 0)); 99 goto again; /* PROM is out to get me -DaveM */ 100 } 101 102 void prom_halt_power_off(void) 103 { 104 #ifdef CONFIG_SUN_LDOMS 105 if (ldom_domaining_enabled) 106 ldom_power_off(); 107 #endif 108 p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); 109 110 /* if nothing else helps, we just halt */ 111 prom_halt(); 112 } 113 114 /* Set prom sync handler to call function 'funcp'. */ 115 void prom_setcallback(callback_func_t funcp) 116 { 117 if (!funcp) 118 return; 119 p1275_cmd("set-callback", P1275_ARG(0, P1275_ARG_IN_FUNCTION) | 120 P1275_INOUT(1, 1), funcp); 121 } 122 123 /* Get the idprom and stuff it into buffer 'idbuf'. Returns the 124 * format type. 'num_bytes' is the number of bytes that your idbuf 125 * has space for. Returns 0xff on error. 126 */ 127 unsigned char prom_get_idprom(char *idbuf, int num_bytes) 128 { 129 int len; 130 131 len = prom_getproplen(prom_root_node, "idprom"); 132 if ((len >num_bytes) || (len == -1)) 133 return 0xff; 134 if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes)) 135 return idbuf[0]; 136 137 return 0xff; 138 } 139 140 int prom_get_mmu_ihandle(void) 141 { 142 int node, ret; 143 144 if (prom_mmu_ihandle_cache != 0) 145 return prom_mmu_ihandle_cache; 146 147 node = prom_finddevice(prom_chosen_path); 148 ret = prom_getint(node, prom_mmu_name); 149 if (ret == -1 || ret == 0) 150 prom_mmu_ihandle_cache = -1; 151 else 152 prom_mmu_ihandle_cache = ret; 153 154 return ret; 155 } 156 157 static int prom_get_memory_ihandle(void) 158 { 159 static int memory_ihandle_cache; 160 int node, ret; 161 162 if (memory_ihandle_cache != 0) 163 return memory_ihandle_cache; 164 165 node = prom_finddevice("/chosen"); 166 ret = prom_getint(node, "memory"); 167 if (ret == -1 || ret == 0) 168 memory_ihandle_cache = -1; 169 else 170 memory_ihandle_cache = ret; 171 172 return ret; 173 } 174 175 /* Load explicit I/D TLB entries. */ 176 long prom_itlb_load(unsigned long index, 177 unsigned long tte_data, 178 unsigned long vaddr) 179 { 180 return p1275_cmd(prom_callmethod_name, 181 (P1275_ARG(0, P1275_ARG_IN_STRING) | 182 P1275_ARG(2, P1275_ARG_IN_64B) | 183 P1275_ARG(3, P1275_ARG_IN_64B) | 184 P1275_INOUT(5, 1)), 185 "SUNW,itlb-load", 186 prom_get_mmu_ihandle(), 187 /* And then our actual args are pushed backwards. */ 188 vaddr, 189 tte_data, 190 index); 191 } 192 193 long prom_dtlb_load(unsigned long index, 194 unsigned long tte_data, 195 unsigned long vaddr) 196 { 197 return p1275_cmd(prom_callmethod_name, 198 (P1275_ARG(0, P1275_ARG_IN_STRING) | 199 P1275_ARG(2, P1275_ARG_IN_64B) | 200 P1275_ARG(3, P1275_ARG_IN_64B) | 201 P1275_INOUT(5, 1)), 202 "SUNW,dtlb-load", 203 prom_get_mmu_ihandle(), 204 /* And then our actual args are pushed backwards. */ 205 vaddr, 206 tte_data, 207 index); 208 } 209 210 int prom_map(int mode, unsigned long size, 211 unsigned long vaddr, unsigned long paddr) 212 { 213 int ret = p1275_cmd(prom_callmethod_name, 214 (P1275_ARG(0, P1275_ARG_IN_STRING) | 215 P1275_ARG(3, P1275_ARG_IN_64B) | 216 P1275_ARG(4, P1275_ARG_IN_64B) | 217 P1275_ARG(6, P1275_ARG_IN_64B) | 218 P1275_INOUT(7, 1)), 219 prom_map_name, 220 prom_get_mmu_ihandle(), 221 mode, 222 size, 223 vaddr, 224 0, 225 paddr); 226 227 if (ret == 0) 228 ret = -1; 229 return ret; 230 } 231 232 void prom_unmap(unsigned long size, unsigned long vaddr) 233 { 234 p1275_cmd(prom_callmethod_name, 235 (P1275_ARG(0, P1275_ARG_IN_STRING) | 236 P1275_ARG(2, P1275_ARG_IN_64B) | 237 P1275_ARG(3, P1275_ARG_IN_64B) | 238 P1275_INOUT(4, 0)), 239 prom_unmap_name, 240 prom_get_mmu_ihandle(), 241 size, 242 vaddr); 243 } 244 245 /* Set aside physical memory which is not touched or modified 246 * across soft resets. 247 */ 248 unsigned long prom_retain(const char *name, 249 unsigned long pa_low, unsigned long pa_high, 250 long size, long align) 251 { 252 /* XXX I don't think we return multiple values correctly. 253 * XXX OBP supposedly returns pa_low/pa_high here, how does 254 * XXX it work? 255 */ 256 257 /* If align is zero, the pa_low/pa_high args are passed, 258 * else they are not. 259 */ 260 if (align == 0) 261 return p1275_cmd("SUNW,retain", 262 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(5, 2)), 263 name, pa_low, pa_high, size, align); 264 else 265 return p1275_cmd("SUNW,retain", 266 (P1275_ARG(0, P1275_ARG_IN_BUF) | P1275_INOUT(3, 2)), 267 name, size, align); 268 } 269 270 /* Get "Unumber" string for the SIMM at the given 271 * memory address. Usually this will be of the form 272 * "Uxxxx" where xxxx is a decimal number which is 273 * etched into the motherboard next to the SIMM slot 274 * in question. 275 */ 276 int prom_getunumber(int syndrome_code, 277 unsigned long phys_addr, 278 char *buf, int buflen) 279 { 280 return p1275_cmd(prom_callmethod_name, 281 (P1275_ARG(0, P1275_ARG_IN_STRING) | 282 P1275_ARG(3, P1275_ARG_OUT_BUF) | 283 P1275_ARG(6, P1275_ARG_IN_64B) | 284 P1275_INOUT(8, 2)), 285 "SUNW,get-unumber", prom_get_memory_ihandle(), 286 buflen, buf, P1275_SIZE(buflen), 287 0, phys_addr, syndrome_code); 288 } 289 290 /* Power management extensions. */ 291 void prom_sleepself(void) 292 { 293 p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0)); 294 } 295 296 int prom_sleepsystem(void) 297 { 298 return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1)); 299 } 300 301 int prom_wakeupsystem(void) 302 { 303 return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1)); 304 } 305 306 #ifdef CONFIG_SMP 307 void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg) 308 { 309 p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, arg); 310 } 311 312 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg) 313 { 314 p1275_cmd("SUNW,start-cpu-by-cpuid", P1275_INOUT(3, 0), 315 cpuid, pc, arg); 316 } 317 318 void prom_stopcpu_cpuid(int cpuid) 319 { 320 p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0), 321 cpuid); 322 } 323 324 void prom_stopself(void) 325 { 326 p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0)); 327 } 328 329 void prom_idleself(void) 330 { 331 p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0)); 332 } 333 334 void prom_resumecpu(int cpunode) 335 { 336 p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode); 337 } 338 #endif 339