linux/arch/sparc/prom/misc_64.c
<<
>>
Prefs
   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
  21int 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
  31void 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'. */
  41void 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'. */
  52void 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}
  59EXPORT_SYMBOL(prom_feval);
  60
  61#ifdef CONFIG_SMP
  62extern void smp_capture(void);
  63extern void smp_release(void);
  64#endif
  65
  66/* Drop into the prom, with the chance to continue with the 'go'
  67 * prom command.
  68 */
  69void 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 */
  91void notrace prom_halt(void)
  92{
  93#ifdef CONFIG_SUN_LDOMS
  94        if (ldom_domaining_enabled)
  95                ldom_power_off();
  96#endif
  97again:
  98        p1275_cmd("exit", P1275_INOUT(0, 0));
  99        goto again; /* PROM is out to get me -DaveM */
 100}
 101
 102void 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'. */
 115void 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 */
 127unsigned 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
 140int 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
 157static 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. */
 176long 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
 193long 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
 210int 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
 232void 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 */
 248unsigned 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 */
 276int 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. */
 291void prom_sleepself(void)
 292{
 293        p1275_cmd("SUNW,sleep-self", P1275_INOUT(0, 0));
 294}
 295
 296int prom_sleepsystem(void)
 297{
 298        return p1275_cmd("SUNW,sleep-system", P1275_INOUT(0, 1));
 299}
 300
 301int prom_wakeupsystem(void)
 302{
 303        return p1275_cmd("SUNW,wakeup-system", P1275_INOUT(0, 1));
 304}
 305
 306#ifdef CONFIG_SMP
 307void 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
 312void 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
 318void prom_stopcpu_cpuid(int cpuid)
 319{
 320        p1275_cmd("SUNW,stop-cpu-by-cpuid", P1275_INOUT(1, 0),
 321                  cpuid);
 322}
 323
 324void prom_stopself(void)
 325{
 326        p1275_cmd("SUNW,stop-self", P1275_INOUT(0, 0));
 327}
 328
 329void prom_idleself(void)
 330{
 331        p1275_cmd("SUNW,idle-self", P1275_INOUT(0, 0));
 332}
 333
 334void prom_resumecpu(int cpunode)
 335{
 336        p1275_cmd("SUNW,resume-cpu", P1275_INOUT(1, 0), cpunode);
 337}
 338#endif
 339