Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * misc.c:  Miscellaneous prom functions that don't belong
0004  *          anywhere else.
0005  *
0006  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
0007  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
0008  */
0009 
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/sched.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/delay.h>
0015 #include <linux/module.h>
0016 
0017 #include <asm/openprom.h>
0018 #include <asm/oplib.h>
0019 #include <asm/ldc.h>
0020 
0021 static int prom_service_exists(const char *service_name)
0022 {
0023     unsigned long args[5];
0024 
0025     args[0] = (unsigned long) "test";
0026     args[1] = 1;
0027     args[2] = 1;
0028     args[3] = (unsigned long) service_name;
0029     args[4] = (unsigned long) -1;
0030 
0031     p1275_cmd_direct(args);
0032 
0033     if (args[4])
0034         return 0;
0035     return 1;
0036 }
0037 
0038 void prom_sun4v_guest_soft_state(void)
0039 {
0040     const char *svc = "SUNW,soft-state-supported";
0041     unsigned long args[3];
0042 
0043     if (!prom_service_exists(svc))
0044         return;
0045     args[0] = (unsigned long) svc;
0046     args[1] = 0;
0047     args[2] = 0;
0048     p1275_cmd_direct(args);
0049 }
0050 
0051 /* Reset and reboot the machine with the command 'bcommand'. */
0052 void prom_reboot(const char *bcommand)
0053 {
0054     unsigned long args[4];
0055 
0056 #ifdef CONFIG_SUN_LDOMS
0057     if (ldom_domaining_enabled)
0058         ldom_reboot(bcommand);
0059 #endif
0060     args[0] = (unsigned long) "boot";
0061     args[1] = 1;
0062     args[2] = 0;
0063     args[3] = (unsigned long) bcommand;
0064 
0065     p1275_cmd_direct(args);
0066 }
0067 
0068 /* Forth evaluate the expression contained in 'fstring'. */
0069 void prom_feval(const char *fstring)
0070 {
0071     unsigned long args[5];
0072 
0073     if (!fstring || fstring[0] == 0)
0074         return;
0075     args[0] = (unsigned long) "interpret";
0076     args[1] = 1;
0077     args[2] = 1;
0078     args[3] = (unsigned long) fstring;
0079     args[4] = (unsigned long) -1;
0080 
0081     p1275_cmd_direct(args);
0082 }
0083 EXPORT_SYMBOL(prom_feval);
0084 
0085 /* Drop into the prom, with the chance to continue with the 'go'
0086  * prom command.
0087  */
0088 void prom_cmdline(void)
0089 {
0090     unsigned long args[3];
0091     unsigned long flags;
0092 
0093     local_irq_save(flags);
0094 
0095 #ifdef CONFIG_SMP
0096     smp_capture();
0097 #endif
0098 
0099     args[0] = (unsigned long) "enter";
0100     args[1] = 0;
0101     args[2] = 0;
0102 
0103     p1275_cmd_direct(args);
0104 
0105 #ifdef CONFIG_SMP
0106     smp_release();
0107 #endif
0108 
0109     local_irq_restore(flags);
0110 }
0111 
0112 /* Drop into the prom, but completely terminate the program.
0113  * No chance of continuing.
0114  */
0115 void notrace prom_halt(void)
0116 {
0117     unsigned long args[3];
0118 
0119 #ifdef CONFIG_SUN_LDOMS
0120     if (ldom_domaining_enabled)
0121         ldom_power_off();
0122 #endif
0123 again:
0124     args[0] = (unsigned long) "exit";
0125     args[1] = 0;
0126     args[2] = 0;
0127     p1275_cmd_direct(args);
0128     goto again; /* PROM is out to get me -DaveM */
0129 }
0130 
0131 void prom_halt_power_off(void)
0132 {
0133     unsigned long args[3];
0134 
0135 #ifdef CONFIG_SUN_LDOMS
0136     if (ldom_domaining_enabled)
0137         ldom_power_off();
0138 #endif
0139     args[0] = (unsigned long) "SUNW,power-off";
0140     args[1] = 0;
0141     args[2] = 0;
0142     p1275_cmd_direct(args);
0143 
0144     /* if nothing else helps, we just halt */
0145     prom_halt();
0146 }
0147 
0148 /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
0149  * format type.  'num_bytes' is the number of bytes that your idbuf
0150  * has space for.  Returns 0xff on error.
0151  */
0152 unsigned char prom_get_idprom(char *idbuf, int num_bytes)
0153 {
0154     int len;
0155 
0156     len = prom_getproplen(prom_root_node, "idprom");
0157     if ((len >num_bytes) || (len == -1))
0158         return 0xff;
0159     if (!prom_getproperty(prom_root_node, "idprom", idbuf, num_bytes))
0160         return idbuf[0];
0161 
0162     return 0xff;
0163 }
0164 
0165 int prom_get_mmu_ihandle(void)
0166 {
0167     phandle node;
0168     int ret;
0169 
0170     if (prom_mmu_ihandle_cache != 0)
0171         return prom_mmu_ihandle_cache;
0172 
0173     node = prom_finddevice(prom_chosen_path);
0174     ret = prom_getint(node, prom_mmu_name);
0175     if (ret == -1 || ret == 0)
0176         prom_mmu_ihandle_cache = -1;
0177     else
0178         prom_mmu_ihandle_cache = ret;
0179 
0180     return ret;
0181 }
0182 
0183 static int prom_get_memory_ihandle(void)
0184 {
0185     static int memory_ihandle_cache;
0186     phandle node;
0187     int ret;
0188 
0189     if (memory_ihandle_cache != 0)
0190         return memory_ihandle_cache;
0191 
0192     node = prom_finddevice("/chosen");
0193     ret = prom_getint(node, "memory");
0194     if (ret == -1 || ret == 0)
0195         memory_ihandle_cache = -1;
0196     else
0197         memory_ihandle_cache = ret;
0198 
0199     return ret;
0200 }
0201 
0202 /* Load explicit I/D TLB entries. */
0203 static long tlb_load(const char *type, unsigned long index,
0204              unsigned long tte_data, unsigned long vaddr)
0205 {
0206     unsigned long args[9];
0207 
0208     args[0] = (unsigned long) prom_callmethod_name;
0209     args[1] = 5;
0210     args[2] = 1;
0211     args[3] = (unsigned long) type;
0212     args[4] = (unsigned int) prom_get_mmu_ihandle();
0213     args[5] = vaddr;
0214     args[6] = tte_data;
0215     args[7] = index;
0216     args[8] = (unsigned long) -1;
0217 
0218     p1275_cmd_direct(args);
0219 
0220     return (long) args[8];
0221 }
0222 
0223 long prom_itlb_load(unsigned long index,
0224             unsigned long tte_data,
0225             unsigned long vaddr)
0226 {
0227     return tlb_load("SUNW,itlb-load", index, tte_data, vaddr);
0228 }
0229 
0230 long prom_dtlb_load(unsigned long index,
0231             unsigned long tte_data,
0232             unsigned long vaddr)
0233 {
0234     return tlb_load("SUNW,dtlb-load", index, tte_data, vaddr);
0235 }
0236 
0237 int prom_map(int mode, unsigned long size,
0238          unsigned long vaddr, unsigned long paddr)
0239 {
0240     unsigned long args[11];
0241     int ret;
0242 
0243     args[0] = (unsigned long) prom_callmethod_name;
0244     args[1] = 7;
0245     args[2] = 1;
0246     args[3] = (unsigned long) prom_map_name;
0247     args[4] = (unsigned int) prom_get_mmu_ihandle();
0248     args[5] = (unsigned int) mode;
0249     args[6] = size;
0250     args[7] = vaddr;
0251     args[8] = 0;
0252     args[9] = paddr;
0253     args[10] = (unsigned long) -1;
0254 
0255     p1275_cmd_direct(args);
0256 
0257     ret = (int) args[10];
0258     if (ret == 0)
0259         ret = -1;
0260     return ret;
0261 }
0262 
0263 void prom_unmap(unsigned long size, unsigned long vaddr)
0264 {
0265     unsigned long args[7];
0266 
0267     args[0] = (unsigned long) prom_callmethod_name;
0268     args[1] = 4;
0269     args[2] = 0;
0270     args[3] = (unsigned long) prom_unmap_name;
0271     args[4] = (unsigned int) prom_get_mmu_ihandle();
0272     args[5] = size;
0273     args[6] = vaddr;
0274 
0275     p1275_cmd_direct(args);
0276 }
0277 
0278 /* Set aside physical memory which is not touched or modified
0279  * across soft resets.
0280  */
0281 int prom_retain(const char *name, unsigned long size,
0282         unsigned long align, unsigned long *paddr)
0283 {
0284     unsigned long args[11];
0285 
0286     args[0] = (unsigned long) prom_callmethod_name;
0287     args[1] = 5;
0288     args[2] = 3;
0289     args[3] = (unsigned long) "SUNW,retain";
0290     args[4] = (unsigned int) prom_get_memory_ihandle();
0291     args[5] = align;
0292     args[6] = size;
0293     args[7] = (unsigned long) name;
0294     args[8] = (unsigned long) -1;
0295     args[9] = (unsigned long) -1;
0296     args[10] = (unsigned long) -1;
0297 
0298     p1275_cmd_direct(args);
0299 
0300     if (args[8])
0301         return (int) args[8];
0302 
0303     /* Next we get "phys_high" then "phys_low".  On 64-bit
0304      * the phys_high cell is don't care since the phys_low
0305      * cell has the full value.
0306      */
0307     *paddr = args[10];
0308 
0309     return 0;
0310 }
0311 
0312 /* Get "Unumber" string for the SIMM at the given
0313  * memory address.  Usually this will be of the form
0314  * "Uxxxx" where xxxx is a decimal number which is
0315  * etched into the motherboard next to the SIMM slot
0316  * in question.
0317  */
0318 int prom_getunumber(int syndrome_code,
0319             unsigned long phys_addr,
0320             char *buf, int buflen)
0321 {
0322     unsigned long args[12];
0323 
0324     args[0] = (unsigned long) prom_callmethod_name;
0325     args[1] = 7;
0326     args[2] = 2;
0327     args[3] = (unsigned long) "SUNW,get-unumber";
0328     args[4] = (unsigned int) prom_get_memory_ihandle();
0329     args[5] = buflen;
0330     args[6] = (unsigned long) buf;
0331     args[7] = 0;
0332     args[8] = phys_addr;
0333     args[9] = (unsigned int) syndrome_code;
0334     args[10] = (unsigned long) -1;
0335     args[11] = (unsigned long) -1;
0336 
0337     p1275_cmd_direct(args);
0338 
0339     return (int) args[10];
0340 }
0341 
0342 /* Power management extensions. */
0343 void prom_sleepself(void)
0344 {
0345     unsigned long args[3];
0346 
0347     args[0] = (unsigned long) "SUNW,sleep-self";
0348     args[1] = 0;
0349     args[2] = 0;
0350     p1275_cmd_direct(args);
0351 }
0352 
0353 int prom_sleepsystem(void)
0354 {
0355     unsigned long args[4];
0356 
0357     args[0] = (unsigned long) "SUNW,sleep-system";
0358     args[1] = 0;
0359     args[2] = 1;
0360     args[3] = (unsigned long) -1;
0361     p1275_cmd_direct(args);
0362 
0363     return (int) args[3];
0364 }
0365 
0366 int prom_wakeupsystem(void)
0367 {
0368     unsigned long args[4];
0369 
0370     args[0] = (unsigned long) "SUNW,wakeup-system";
0371     args[1] = 0;
0372     args[2] = 1;
0373     args[3] = (unsigned long) -1;
0374     p1275_cmd_direct(args);
0375 
0376     return (int) args[3];
0377 }
0378 
0379 #ifdef CONFIG_SMP
0380 void prom_startcpu(int cpunode, unsigned long pc, unsigned long arg)
0381 {
0382     unsigned long args[6];
0383 
0384     args[0] = (unsigned long) "SUNW,start-cpu";
0385     args[1] = 3;
0386     args[2] = 0;
0387     args[3] = (unsigned int) cpunode;
0388     args[4] = pc;
0389     args[5] = arg;
0390     p1275_cmd_direct(args);
0391 }
0392 
0393 void prom_startcpu_cpuid(int cpuid, unsigned long pc, unsigned long arg)
0394 {
0395     unsigned long args[6];
0396 
0397     args[0] = (unsigned long) "SUNW,start-cpu-by-cpuid";
0398     args[1] = 3;
0399     args[2] = 0;
0400     args[3] = (unsigned int) cpuid;
0401     args[4] = pc;
0402     args[5] = arg;
0403     p1275_cmd_direct(args);
0404 }
0405 
0406 void prom_stopcpu_cpuid(int cpuid)
0407 {
0408     unsigned long args[4];
0409 
0410     args[0] = (unsigned long) "SUNW,stop-cpu-by-cpuid";
0411     args[1] = 1;
0412     args[2] = 0;
0413     args[3] = (unsigned int) cpuid;
0414     p1275_cmd_direct(args);
0415 }
0416 
0417 void prom_stopself(void)
0418 {
0419     unsigned long args[3];
0420 
0421     args[0] = (unsigned long) "SUNW,stop-self";
0422     args[1] = 0;
0423     args[2] = 0;
0424     p1275_cmd_direct(args);
0425 }
0426 
0427 void prom_idleself(void)
0428 {
0429     unsigned long args[3];
0430 
0431     args[0] = (unsigned long) "SUNW,idle-self";
0432     args[1] = 0;
0433     args[2] = 0;
0434     p1275_cmd_direct(args);
0435 }
0436 
0437 void prom_resumecpu(int cpunode)
0438 {
0439     unsigned long args[4];
0440 
0441     args[0] = (unsigned long) "SUNW,resume-cpu";
0442     args[1] = 1;
0443     args[2] = 0;
0444     args[3] = (unsigned int) cpunode;
0445     p1275_cmd_direct(args);
0446 }
0447 #endif