linux/arch/sparc/prom/misc_64.c
<<
>>
Prefs
   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
  21static 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
  38void 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'. */
  52void 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'. */
  69void 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}
  83EXPORT_SYMBOL(prom_feval);
  84
  85/* Drop into the prom, with the chance to continue with the 'go'
  86 * prom command.
  87 */
  88void 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 */
 115void 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
 123again:
 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
 131void 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 */
 152unsigned 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
 165int 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
 183static 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. */
 203static 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
 223long 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
 230long 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
 237int 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
 263void 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 */
 281int 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 */
 318int 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. */
 343void 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
 353int 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
 366int 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
 380void 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
 393void 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
 406void 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
 417void 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
 427void 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
 437void 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