linux-old/arch/ppc64/kernel/prom.c
<<
>>
Prefs
   1/* - undefined for user space
   2 * 
   3 *
   4 * Procedures for interfacing to Open Firmware.
   5 *
   6 * Paul Mackerras       August 1996.
   7 * Copyright (C) 1996 Paul Mackerras.
   8 * 
   9 *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
  10 *    {engebret|bergner}@us.ibm.com 
  11 *
  12 *      This program is free software; you can redistribute it and/or
  13 *      modify it under the terms of the GNU General Public License
  14 *      as published by the Free Software Foundation; either version
  15 *      2 of the License, or (at your option) any later version.
  16 */
  17
  18#if 0
  19#define DEBUG_YABOOT
  20#endif
  21
  22#if 0
  23#define DEBUG_PROM
  24#endif
  25
  26#include <stdarg.h>
  27#include <linux/config.h>
  28#include <linux/kernel.h>
  29#include <linux/string.h>
  30#include <linux/init.h>
  31#include <linux/version.h>
  32#include <linux/threads.h>
  33#include <linux/spinlock.h>
  34#include <linux/blk.h>
  35
  36#ifdef DEBUG_YABOOT
  37#define call_yaboot(FUNC,...) \
  38        do { \
  39                if (FUNC) {                                     \
  40                        struct prom_t *_prom = PTRRELOC(&prom); \
  41                        unsigned long prom_entry = _prom->entry;\
  42                        _prom->entry = (unsigned long)(FUNC);   \
  43                        enter_prom(__VA_ARGS__);                \
  44                        _prom->entry = prom_entry;              \
  45                }                                               \
  46        } while (0)
  47#else
  48#define call_yaboot(FUNC,...) do { ; } while (0)
  49#endif
  50
  51#include <asm/init.h>
  52#include <linux/types.h>
  53#include <linux/pci.h>
  54#include <asm/prom.h>
  55#include <asm/rtas.h>
  56#include <asm/lmb.h>
  57#include <asm/abs_addr.h>
  58#include <asm/page.h>
  59#include <asm/processor.h>
  60#include <asm/irq.h>
  61#include <asm/io.h>
  62#include <asm/smp.h>
  63#include <asm/system.h>
  64#include <asm/mmu.h>
  65#include <asm/pgtable.h>
  66#include <asm/bitops.h>
  67#include <asm/naca.h>
  68#include <asm/pci.h>
  69#include "open_pic.h"
  70#include <asm/bootinfo.h>
  71#include <asm/ppcdebug.h>
  72
  73#ifdef CONFIG_FB
  74#include <asm/linux_logo.h>
  75#endif
  76
  77extern char _end[];
  78
  79/*
  80 * prom_init() is called very early on, before the kernel text
  81 * and data have been mapped to KERNELBASE.  At this point the code
  82 * is running at whatever address it has been loaded at, so
  83 * references to extern and static variables must be relocated
  84 * explicitly.  The procedure reloc_offset() returns the address
  85 * we're currently running at minus the address we were linked at.
  86 * (Note that strings count as static variables.)
  87 *
  88 * Because OF may have mapped I/O devices into the area starting at
  89 * KERNELBASE, particularly on CHRP machines, we can't safely call
  90 * OF once the kernel has been mapped to KERNELBASE.  Therefore all
  91 * OF calls should be done within prom_init(), and prom_init()
  92 * and all routines called within it must be careful to relocate
  93 * references as necessary.
  94 *
  95 * Note that the bss is cleared *after* prom_init runs, so we have
  96 * to make sure that any static or extern variables it accesses
  97 * are put in the data segment.
  98 */
  99
 100
 101#define PROM_BUG() do { \
 102        prom_print(RELOC("kernel BUG at ")); \
 103        prom_print(RELOC(__FILE__)); \
 104        prom_print(RELOC(":")); \
 105        prom_print_hex(__LINE__); \
 106        prom_print(RELOC("!\n")); \
 107        __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
 108} while (0)
 109
 110
 111
 112struct pci_reg_property {
 113        struct pci_address addr;
 114        u32 size_hi;
 115        u32 size_lo;
 116};
 117
 118
 119struct isa_reg_property {
 120        u32 space;
 121        u32 address;
 122        u32 size;
 123};
 124
 125struct pci_intr_map {
 126        struct pci_address addr;
 127        u32 dunno;
 128        phandle int_ctrler;
 129        u32 intr;
 130};
 131
 132
 133typedef unsigned long interpret_func(struct device_node *, unsigned long,
 134                                     int, int);
 135#if 0
 136static interpret_func interpret_pci_props;
 137#endif
 138static unsigned long interpret_pci_props(struct device_node *, unsigned long,
 139                                         int, int);
 140
 141static interpret_func interpret_isa_props;
 142static interpret_func interpret_root_props;
 143
 144#ifndef FB_MAX                  /* avoid pulling in all of the fb stuff */
 145#define FB_MAX  8
 146#endif
 147
 148
 149struct prom_t prom = {
 150        0,                      /* entry */
 151        0,                      /* chosen */
 152        0,                      /* cpu */
 153        0,                      /* stdout */
 154        0,                      /* disp_node */
 155        {0,0,0,{0},NULL},       /* args */
 156        0,                      /* version */
 157        32,                     /* encode_phys_size */
 158        0                       /* bi_rec pointer */
 159#ifdef DEBUG_YABOOT
 160        ,NULL                   /* yaboot */
 161#endif
 162};
 163
 164
 165char *prom_display_paths[FB_MAX] __initdata = { 0, };
 166unsigned int prom_num_displays = 0;
 167char *of_stdout_device = 0;
 168
 169extern struct rtas_t rtas;
 170extern unsigned long klimit;
 171extern unsigned long embedded_sysmap_end;
 172extern struct lmb lmb;
 173#ifdef CONFIG_MSCHUNKS
 174extern struct msChunks msChunks;
 175#endif /* CONFIG_MSCHUNKS */
 176
 177#define MAX_PHB 16 * 3  // 16 Towers * 3 PHBs/tower
 178struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}};
 179
 180char *bootpath = 0;
 181char *bootdevice = 0;
 182
 183struct device_node *allnodes = 0;
 184
 185#define UNDEFINED_IRQ 0xffff
 186unsigned short real_irq_to_virt_map[NR_HW_IRQS];
 187unsigned short virt_irq_to_real_map[NR_IRQS];
 188int last_virt_irq = 2;  /* index of last virt_irq.  Skip through IPI */
 189
 190static unsigned long call_prom(const char *service, int nargs, int nret, ...);
 191static void prom_exit(void);
 192static unsigned long copy_device_tree(unsigned long);
 193static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
 194                                  unsigned long, struct device_node ***);
 195static unsigned long finish_node(struct device_node *, unsigned long,
 196                                 interpret_func *, int, int);
 197static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
 198static unsigned long check_display(unsigned long);
 199static int prom_next_node(phandle *);
 200static struct bi_record * prom_bi_rec_verify(struct bi_record *);
 201static unsigned long prom_bi_rec_reserve(unsigned long);
 202static struct device_node *find_phandle(phandle);
 203
 204#ifdef CONFIG_MSCHUNKS
 205static unsigned long prom_initialize_mschunks(unsigned long);
 206#ifdef DEBUG_PROM
 207void prom_dump_mschunks_mapping(void);
 208#endif /* DEBUG_PROM */
 209#endif /* CONFIG_MSCHUNKS */
 210#ifdef DEBUG_PROM
 211void prom_dump_lmb(void);
 212#endif
 213
 214extern unsigned long reloc_offset(void);
 215
 216extern void enter_prom(void *dummy,...);
 217
 218void cacheable_memzero(void *, unsigned int);
 219
 220#ifndef CONFIG_CMDLINE
 221#define CONFIG_CMDLINE ""
 222#endif
 223char cmd_line[512] = CONFIG_CMDLINE;
 224unsigned long dev_tree_size;
 225
 226#ifdef CONFIG_HMT
 227struct {
 228        unsigned int pir;
 229        unsigned int threadid;
 230} hmt_thread_data[NR_CPUS] = {0};
 231#endif /* CONFIG_HMT */
 232
 233char testString[] = "LINUX\n"; 
 234
 235
 236/* This is the one and *ONLY* place where we actually call open
 237 * firmware from, since we need to make sure we're running in 32b
 238 * mode when we do.  We switch back to 64b mode upon return.
 239 */
 240
 241static unsigned long __init
 242call_prom(const char *service, int nargs, int nret, ...)
 243{
 244        int i;
 245        unsigned long offset = reloc_offset();
 246        struct prom_t *_prom = PTRRELOC(&prom);
 247        va_list list;
 248        
 249        _prom->args.service = (u32)LONG_LSW(service);
 250        _prom->args.nargs = nargs;
 251        _prom->args.nret = nret;
 252        _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);
 253
 254        va_start(list, nret);
 255        for (i=0; i < nargs ;i++)
 256                _prom->args.args[i] = (prom_arg_t)LONG_LSW(va_arg(list, unsigned long));
 257        va_end(list);
 258
 259        for (i=0; i < nret ;i++)
 260                _prom->args.rets[i] = 0;
 261
 262        enter_prom(&_prom->args);
 263
 264        return (unsigned long)((nret > 0) ? _prom->args.rets[0] : 0);
 265}
 266
 267
 268static void __init
 269prom_exit()
 270{
 271        unsigned long offset = reloc_offset();
 272
 273        call_prom(RELOC("exit"), 0, 0);
 274
 275        for (;;)                        /* should never get here */
 276                ;
 277}
 278
 279void __init
 280prom_enter(void)
 281{
 282        unsigned long offset = reloc_offset();
 283
 284        call_prom(RELOC("enter"), 0, 0);
 285}
 286
 287
 288void __init
 289prom_print(const char *msg)
 290{
 291        const char *p, *q;
 292        unsigned long offset = reloc_offset();
 293        struct prom_t *_prom = PTRRELOC(&prom);
 294
 295        if (_prom->stdout == 0)
 296                return;
 297
 298        for (p = msg; *p != 0; p = q) {
 299                for (q = p; *q != 0 && *q != '\n'; ++q)
 300                        ;
 301                if (q > p)
 302                        call_prom(RELOC("write"), 3, 1, _prom->stdout,
 303                                  p, q - p);
 304                if (*q != 0) {
 305                        ++q;
 306                        call_prom(RELOC("write"), 3, 1, _prom->stdout,
 307                                  RELOC("\r\n"), 2);
 308                }
 309        }
 310}
 311
 312void
 313prom_print_hex(unsigned long val)
 314{
 315        int i, nibbles = sizeof(val)*2;
 316        char buf[sizeof(val)*2+1];
 317
 318        for (i = nibbles-1;  i >= 0;  i--) {
 319                buf[i] = (val & 0xf) + '0';
 320                if (buf[i] > '9')
 321                    buf[i] += ('a'-'0'-10);
 322                val >>= 4;
 323        }
 324        buf[nibbles] = '\0';
 325        prom_print(buf);
 326}
 327
 328void
 329prom_print_nl(void)
 330{
 331        unsigned long offset = reloc_offset();
 332        prom_print(RELOC("\n"));
 333}
 334
 335
 336static unsigned long
 337prom_initialize_naca(unsigned long mem)
 338{
 339        phandle node;
 340        char type[64];
 341        unsigned long num_cpus = 0;
 342        unsigned long offset = reloc_offset();
 343        struct prom_t *_prom = PTRRELOC(&prom);
 344        struct naca_struct *_naca = RELOC(naca);
 345        struct systemcfg *_systemcfg = RELOC(systemcfg);
 346
 347        /* NOTE: _naca->debug_switch is already initialized. */
 348#ifdef DEBUG_PROM
 349        prom_print(RELOC("prom_initialize_naca: start...\n"));
 350#endif
 351
 352        _naca->pftSize = 0;     /* ilog2 of htab size.  computed below. */
 353
 354        for (node = 0; prom_next_node(&node); ) {
 355                type[0] = 0;
 356                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
 357                          type, sizeof(type));
 358
 359                if (!strcmp(type, RELOC("cpu"))) {
 360                        num_cpus += 1;
 361
 362                        /* We're assuming *all* of the CPUs have the same
 363                         * d-cache and i-cache sizes... -Peter
 364                         */
 365                        if ( num_cpus == 1 ) {
 366                                u32 size, lsize, sets;
 367
 368                                call_prom(RELOC("getprop"), 4, 1, node,
 369                                          RELOC("d-cache-size"),
 370                                          &size, sizeof(size));
 371
 372                                call_prom(RELOC("getprop"), 4, 1, node,
 373                                          RELOC("d-cache-line-size"),
 374                                          &lsize, sizeof(lsize));
 375
 376                                _systemcfg->dCacheL1Size = size;
 377                                _systemcfg->dCacheL1LineSize = lsize;
 378                                _naca->dCacheL1LogLineSize = __ilog2(lsize);
 379                                _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
 380
 381                                call_prom(RELOC("getprop"), 4, 1, node,
 382                                          RELOC("i-cache-size"),
 383                                          &size, sizeof(size));
 384
 385                                call_prom(RELOC("getprop"), 4, 1, node,
 386                                          RELOC("i-cache-line-size"),
 387                                          &lsize, sizeof(lsize));
 388
 389                                _systemcfg->iCacheL1Size = size;
 390                                _systemcfg->iCacheL1LineSize = lsize;
 391                                _naca->iCacheL1LogLineSize = __ilog2(lsize);
 392                                _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
 393
 394                                if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 395                                        u32 pft_size[2];
 396                                        call_prom(RELOC("getprop"), 4, 1, node, 
 397                                                  RELOC("ibm,pft-size"),
 398                                                  &pft_size, sizeof(pft_size));
 399                                /* pft_size[0] is the NUMA CEC cookie */
 400                                        _naca->pftSize = pft_size[1];
 401                                }
 402                        }
 403                } else if (!strcmp(type, RELOC("serial"))) {
 404                        phandle isa, pci;
 405                        struct isa_reg_property reg;
 406                        union pci_range ranges;
 407
 408                        type[0] = 0;
 409                        call_prom(RELOC("getprop"), 4, 1, node,
 410                                  RELOC("ibm,aix-loc"), type, sizeof(type));
 411
 412                        if (strcmp(type, RELOC("S1")))
 413                                continue;
 414
 415                        call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
 416                                  &reg, sizeof(reg));
 417
 418                        isa = call_prom(RELOC("parent"), 1, 1, node);
 419                        if (!isa)
 420                                PROM_BUG();
 421                        pci = call_prom(RELOC("parent"), 1, 1, isa);
 422                        if (!pci)
 423                                PROM_BUG();
 424
 425                        call_prom(RELOC("getprop"), 4, 1, pci, RELOC("ranges"),
 426                                  &ranges, sizeof(ranges));
 427
 428                        if ( _prom->encode_phys_size == 32 )
 429                                _naca->serialPortAddr = ranges.pci32.phys+reg.address;
 430                        else {
 431                                _naca->serialPortAddr = 
 432                                        ((((unsigned long)ranges.pci64.phys_hi) << 32) |
 433                                         (ranges.pci64.phys_lo)) + reg.address;
 434                        }
 435                }
 436        }
 437
 438        _naca->interrupt_controller = IC_INVALID;
 439        for (node = 0; prom_next_node(&node); ) {
 440                type[0] = 0;
 441                call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
 442                          type, sizeof(type));
 443                if (strcmp(type, RELOC("interrupt-controller"))) {
 444                        continue;
 445                }
 446                call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
 447                          type, sizeof(type));
 448                if (strstr(type, RELOC("open-pic"))) {
 449                        _naca->interrupt_controller = IC_OPEN_PIC;
 450                } else if (strstr(type, RELOC("ppc-xicp"))) {
 451                        _naca->interrupt_controller = IC_PPC_XIC;
 452                } else {
 453                        prom_print(RELOC("prom: failed to recognize interrupt-controller\n"));
 454                }
 455                break;
 456        }
 457
 458        if (_naca->interrupt_controller == IC_INVALID) {
 459                prom_print(RELOC("prom: failed to find interrupt-controller\n"));
 460                PROM_BUG();
 461        }
 462
 463        /* We gotta have at least 1 cpu... */
 464        if ( (_systemcfg->processorCount = num_cpus) < 1 )
 465                PROM_BUG();
 466
 467        _systemcfg->physicalMemorySize = lmb_phys_mem_size();
 468
 469        if (_systemcfg->platform == PLATFORM_PSERIES) {
 470                unsigned long rnd_mem_size, pteg_count;
 471
 472                /* round mem_size up to next power of 2 */
 473                rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
 474                if (rnd_mem_size < _systemcfg->physicalMemorySize)
 475                        rnd_mem_size <<= 1;
 476
 477                /* # pages / 2 */
 478                pteg_count = (rnd_mem_size >> (12 + 1));
 479
 480                _naca->pftSize = __ilog2(pteg_count << 7);
 481        }
 482
 483        if (_naca->pftSize == 0) {
 484                prom_print(RELOC("prom: failed to compute pftSize!\n"));
 485                PROM_BUG();
 486        }
 487
 488        /* 
 489         * Hardcode to GP size.  I am not sure where to get this info
 490         * in general, as there does not appear to be a slb-size OF
 491         * entry.  At least in Condor and earlier.  DRENG 
 492         */
 493        _naca->slb_size = 64;
 494
 495        /* Add an eye catcher and the systemcfg layout version number */
 496        strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
 497        _systemcfg->version.major = SYSTEMCFG_MAJOR;
 498        _systemcfg->version.minor = SYSTEMCFG_MINOR;
 499        _systemcfg->processor = _get_PVR();
 500
 501#ifdef DEBUG_PROM
 502        prom_print(RELOC("systemcfg->processorCount       = 0x"));
 503        prom_print_hex(_systemcfg->processorCount);
 504        prom_print_nl();
 505
 506        prom_print(RELOC("systemcfg->physicalMemorySize   = 0x"));
 507        prom_print_hex(_systemcfg->physicalMemorySize);
 508        prom_print_nl();
 509
 510        prom_print(RELOC("naca->pftSize                   = 0x"));
 511        prom_print_hex(_naca->pftSize);
 512        prom_print_nl();
 513
 514        prom_print(RELOC("systemcfg->dCacheL1LineSize     = 0x"));
 515        prom_print_hex(_systemcfg->dCacheL1LineSize);
 516        prom_print_nl();
 517
 518        prom_print(RELOC("systemcfg->iCacheL1LineSize     = 0x"));
 519        prom_print_hex(_systemcfg->iCacheL1LineSize);
 520        prom_print_nl();
 521
 522        prom_print(RELOC("naca->serialPortAddr            = 0x"));
 523        prom_print_hex(_naca->serialPortAddr);
 524        prom_print_nl();
 525
 526        prom_print(RELOC("naca->interrupt_controller      = 0x"));
 527        prom_print_hex(_naca->interrupt_controller);
 528        prom_print_nl();
 529
 530        prom_print(RELOC("systemcfg->platform             = 0x"));
 531        prom_print_hex(_systemcfg->platform);
 532        prom_print_nl();
 533
 534        prom_print(RELOC("prom_initialize_naca: end...\n"));
 535#endif
 536
 537        return mem;
 538}
 539
 540
 541static unsigned long __init
 542prom_initialize_lmb(unsigned long mem)
 543{
 544        phandle node;
 545        char type[64];
 546        unsigned long i, offset = reloc_offset();
 547        struct prom_t *_prom = PTRRELOC(&prom);
 548        union lmb_reg_property reg;
 549        unsigned long lmb_base, lmb_size;
 550        unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
 551
 552#ifdef CONFIG_MSCHUNKS
 553        unsigned long max_addr = 0;
 554#if 1
 555        /* Fix me: 630 3G-4G IO hack here... -Peter (PPPBBB) */
 556        unsigned long io_base = 3UL<<30;
 557        unsigned long io_size = 1UL<<30;
 558        unsigned long have_630 = 1;     /* assume we have a 630 */
 559
 560#else
 561        unsigned long io_base = <real io base here>;
 562        unsigned long io_size = <real io size here>;
 563#endif
 564#endif /* CONFIG_MSCHUNKS */
 565
 566        lmb_init();
 567
 568        for (node = 0; prom_next_node(&node); ) {
 569                type[0] = 0;
 570                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
 571                          type, sizeof(type));
 572
 573                if (strcmp(type, RELOC("memory")))
 574                        continue;
 575
 576                num_regs = call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
 577                        &reg, sizeof(reg)) / bytes_per_reg;
 578
 579                for (i=0; i < num_regs ;i++) {
 580                        if (_prom->encode_phys_size == 32) {
 581                                lmb_base = reg.addr32[i].address;
 582                                lmb_size = reg.addr32[i].size;
 583                        } else {
 584                                lmb_base = reg.addr64[i].address;
 585                                lmb_size = reg.addr64[i].size;
 586                        }
 587
 588#ifdef CONFIG_MSCHUNKS
 589                        if ( lmb_addrs_overlap(lmb_base,lmb_size,
 590                                                io_base,io_size) ) {
 591                                /* If we really have dram here, then we don't
 592                                 * have a 630! -Peter
 593                                 */
 594                                have_630 = 0;
 595                        }
 596#endif /* CONFIG_MSCHUNKS */
 597                        if ( lmb_add(lmb_base, lmb_size) < 0 )
 598                                prom_print(RELOC("Too many LMB's, discarding this one...\n"));
 599#ifdef CONFIG_MSCHUNKS
 600                        else if ( max_addr < (lmb_base+lmb_size-1) )
 601                                max_addr = lmb_base+lmb_size-1;
 602#endif /* CONFIG_MSCHUNKS */
 603                }
 604
 605        }
 606
 607#ifdef CONFIG_MSCHUNKS
 608        if ( have_630 && lmb_addrs_overlap(0,max_addr,io_base,io_size) )
 609                lmb_add_io(io_base, io_size);
 610#endif /* CONFIG_MSCHUNKS */
 611
 612        lmb_analyze();
 613#ifdef DEBUG_PROM
 614        prom_dump_lmb();
 615#endif /* DEBUG_PROM */
 616
 617#ifdef CONFIG_MSCHUNKS
 618        mem = prom_initialize_mschunks(mem);
 619#ifdef DEBUG_PROM
 620        prom_dump_mschunks_mapping();
 621#endif /* DEBUG_PROM */
 622#endif /* CONFIG_MSCHUNKS */
 623
 624        return mem;
 625}
 626
 627
 628static void __init
 629prom_instantiate_rtas(void)
 630{
 631        unsigned long offset = reloc_offset();
 632        struct prom_t *_prom = PTRRELOC(&prom);
 633        struct rtas_t *_rtas = PTRRELOC(&rtas);
 634        struct naca_struct *_naca = RELOC(naca);
 635        struct systemcfg *_systemcfg = RELOC(systemcfg);
 636        ihandle prom_rtas;
 637        u32 getprop_rval;
 638
 639#ifdef DEBUG_PROM
 640        prom_print(RELOC("prom_instantiate_rtas: start...\n"));
 641#endif
 642        prom_rtas = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
 643        if (prom_rtas != (ihandle) -1) {
 644                char hypertas_funcs[1024];
 645                int  rc; 
 646                
 647                if ((rc = call_prom(RELOC("getprop"), 
 648                                  4, 1, prom_rtas,
 649                                  RELOC("ibm,hypertas-functions"), 
 650                                  hypertas_funcs, 
 651                                  sizeof(hypertas_funcs))) > 0) {
 652                        _systemcfg->platform = PLATFORM_PSERIES_LPAR;
 653                }
 654
 655                call_prom(RELOC("getprop"), 
 656                          4, 1, prom_rtas,
 657                          RELOC("rtas-size"), 
 658                          &getprop_rval, 
 659                          sizeof(getprop_rval));
 660                _rtas->size = getprop_rval;
 661                prom_print(RELOC("instantiating rtas"));
 662                if (_rtas->size != 0) {
 663                        unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
 664
 665                        /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes
 666                         * of physical memory (or within the RMO region) because RTAS
 667                         * runs in 32-bit mode and relocate off.
 668                         */
 669                        if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
 670                                struct lmb *_lmb  = PTRRELOC(&lmb);
 671                                rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
 672                        }
 673                        _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region);
 674
 675                        prom_print(RELOC(" at 0x"));
 676                        prom_print_hex(_rtas->base);
 677
 678                        prom_rtas = (ihandle)call_prom(RELOC("open"), 
 679                                                1, 1, RELOC("/rtas"));
 680                        prom_print(RELOC("..."));
 681
 682                        if ((long)call_prom(RELOC("call-method"), 3, 2,
 683                                                      RELOC("instantiate-rtas"),
 684                                                      prom_rtas,
 685                                                      _rtas->base) >= 0) {
 686                                _rtas->entry = (long)_prom->args.rets[1];
 687                        }
 688                }
 689
 690                if (_rtas->entry <= 0) {
 691                        prom_print(RELOC(" failed\n"));
 692                } else {
 693                        prom_print(RELOC(" done\n"));
 694                }
 695
 696#ifdef DEBUG_PROM
 697                prom_print(RELOC("rtas->base                 = 0x"));
 698                prom_print_hex(_rtas->base);
 699                prom_print_nl();
 700                prom_print(RELOC("rtas->entry                = 0x"));
 701                prom_print_hex(_rtas->entry);
 702                prom_print_nl();
 703                prom_print(RELOC("rtas->size                 = 0x"));
 704                prom_print_hex(_rtas->size);
 705                prom_print_nl();
 706#endif
 707        }
 708#ifdef DEBUG_PROM
 709        prom_print(RELOC("prom_instantiate_rtas: end...\n"));
 710#endif
 711}
 712
 713unsigned long prom_strtoul(const char *cp)
 714{
 715        unsigned long result = 0,value;
 716
 717        while (*cp) {
 718                value = *cp-'0';
 719                result = result*10 + value;
 720                cp++;
 721        } 
 722
 723        return result;
 724}
 725
 726
 727#ifdef CONFIG_MSCHUNKS
 728static unsigned long
 729prom_initialize_mschunks(unsigned long mem)
 730{
 731        unsigned long offset = reloc_offset();
 732        struct lmb *_lmb  = PTRRELOC(&lmb);
 733        struct msChunks *_msChunks = PTRRELOC(&msChunks);
 734        unsigned long i, pchunk = 0;
 735        unsigned long addr_range = _lmb->memory.size + _lmb->memory.iosize;
 736        unsigned long chunk_size = _lmb->memory.lcd_size;
 737
 738
 739        mem = msChunks_alloc(mem, addr_range / chunk_size, chunk_size);
 740
 741        /* First create phys -> abs mapping for memory/dram */
 742        for (i=0; i < _lmb->memory.cnt ;i++) {
 743                unsigned long base = _lmb->memory.region[i].base;
 744                unsigned long size = _lmb->memory.region[i].size;
 745                unsigned long achunk = addr_to_chunk(base);
 746                unsigned long end_achunk = addr_to_chunk(base+size);
 747
 748                if(_lmb->memory.region[i].type != LMB_MEMORY_AREA)
 749                        continue;
 750
 751                _lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
 752                for (; achunk < end_achunk ;) {
 753                        PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
 754                }
 755        }
 756
 757#ifdef CONFIG_MSCHUNKS
 758        /* Now create phys -> abs mapping for IO */
 759        for (i=0; i < _lmb->memory.cnt ;i++) {
 760                unsigned long base = _lmb->memory.region[i].base;
 761                unsigned long size = _lmb->memory.region[i].size;
 762                unsigned long achunk = addr_to_chunk(base);
 763                unsigned long end_achunk = addr_to_chunk(base+size);
 764
 765                if(_lmb->memory.region[i].type != LMB_IO_AREA)
 766                        continue;
 767
 768                _lmb->memory.region[i].physbase = chunk_to_addr(pchunk);
 769                for (; achunk < end_achunk ;) {
 770                        PTRRELOC(_msChunks->abs)[pchunk++] = achunk++;
 771                }
 772        }
 773#endif /* CONFIG_MSCHUNKS */
 774
 775        return mem;
 776}
 777
 778#ifdef DEBUG_PROM
 779void
 780prom_dump_mschunks_mapping(void)
 781{
 782        unsigned long offset = reloc_offset();
 783        struct msChunks *_msChunks = PTRRELOC(&msChunks);
 784        unsigned long chunk;
 785
 786        prom_print(RELOC("\nprom_dump_mschunks_mapping:\n"));
 787        prom_print(RELOC("    msChunks.num_chunks         = 0x"));
 788        prom_print_hex(_msChunks->num_chunks);
 789        prom_print_nl();
 790        prom_print(RELOC("    msChunks.chunk_size         = 0x"));
 791        prom_print_hex(_msChunks->chunk_size);
 792        prom_print_nl();
 793        prom_print(RELOC("    msChunks.chunk_shift        = 0x"));
 794        prom_print_hex(_msChunks->chunk_shift);
 795        prom_print_nl();
 796        prom_print(RELOC("    msChunks.chunk_mask         = 0x"));
 797        prom_print_hex(_msChunks->chunk_mask);
 798        prom_print_nl();
 799        prom_print(RELOC("    msChunks.abs                = 0x"));
 800        prom_print_hex(_msChunks->abs);
 801        prom_print_nl();
 802
 803        prom_print(RELOC("    msChunks mapping:\n"));
 804        for(chunk=0; chunk < _msChunks->num_chunks ;chunk++) {
 805                prom_print(RELOC("        phys 0x"));
 806                prom_print_hex(chunk);
 807                prom_print(RELOC(" -> abs 0x"));
 808                prom_print_hex(PTRRELOC(_msChunks->abs)[chunk]);
 809                prom_print_nl();
 810        }
 811
 812}
 813#endif /* DEBUG_PROM */
 814#endif /* CONFIG_MSCHUNKS */
 815
 816#ifdef DEBUG_PROM
 817void
 818prom_dump_lmb(void)
 819{
 820        unsigned long i;
 821        unsigned long offset = reloc_offset();
 822        struct lmb *_lmb  = PTRRELOC(&lmb);
 823
 824        prom_print(RELOC("\nprom_dump_lmb:\n"));
 825        prom_print(RELOC("    memory.cnt                  = 0x"));
 826        prom_print_hex(_lmb->memory.cnt);
 827        prom_print_nl();
 828        prom_print(RELOC("    memory.size                 = 0x"));
 829        prom_print_hex(_lmb->memory.size);
 830        prom_print_nl();
 831        prom_print(RELOC("    memory.lcd_size             = 0x"));
 832        prom_print_hex(_lmb->memory.lcd_size);
 833        prom_print_nl();
 834        for (i=0; i < _lmb->memory.cnt ;i++) {
 835                prom_print(RELOC("    memory.region[0x"));
 836                prom_print_hex(i);
 837                prom_print(RELOC("].base       = 0x"));
 838                prom_print_hex(_lmb->memory.region[i].base);
 839                prom_print_nl();
 840                prom_print(RELOC("                      .physbase = 0x"));
 841                prom_print_hex(_lmb->memory.region[i].physbase);
 842                prom_print_nl();
 843                prom_print(RELOC("                      .size     = 0x"));
 844                prom_print_hex(_lmb->memory.region[i].size);
 845                prom_print_nl();
 846                prom_print(RELOC("                      .type     = 0x"));
 847                prom_print_hex(_lmb->memory.region[i].type);
 848                prom_print_nl();
 849        }
 850
 851        prom_print_nl();
 852        prom_print(RELOC("    reserved.cnt                  = 0x"));
 853        prom_print_hex(_lmb->reserved.cnt);
 854        prom_print_nl();
 855        prom_print(RELOC("    reserved.size                 = 0x"));
 856        prom_print_hex(_lmb->reserved.size);
 857        prom_print_nl();
 858        prom_print(RELOC("    reserved.lcd_size             = 0x"));
 859        prom_print_hex(_lmb->reserved.lcd_size);
 860        prom_print_nl();
 861        for (i=0; i < _lmb->reserved.cnt ;i++) {
 862                prom_print(RELOC("    reserved.region[0x"));
 863                prom_print_hex(i);
 864                prom_print(RELOC("].base       = 0x"));
 865                prom_print_hex(_lmb->reserved.region[i].base);
 866                prom_print_nl();
 867                prom_print(RELOC("                      .physbase = 0x"));
 868                prom_print_hex(_lmb->reserved.region[i].physbase);
 869                prom_print_nl();
 870                prom_print(RELOC("                      .size     = 0x"));
 871                prom_print_hex(_lmb->reserved.region[i].size);
 872                prom_print_nl();
 873                prom_print(RELOC("                      .type     = 0x"));
 874                prom_print_hex(_lmb->reserved.region[i].type);
 875                prom_print_nl();
 876        }
 877}
 878#endif /* DEBUG_PROM */
 879
 880
 881void
 882prom_initialize_tce_table(void)
 883{
 884        phandle node;
 885        ihandle phb_node;
 886        unsigned long offset = reloc_offset();
 887        char compatible[64], path[64], type[64], model[64];
 888        unsigned long i, table = 0;
 889        unsigned long base, vbase, align;
 890        unsigned int minalign, minsize;
 891        struct _of_tce_table *prom_tce_table = RELOC(of_tce_table);
 892        unsigned long tce_entry, *tce_entryp;
 893
 894#ifdef DEBUG_PROM
 895        prom_print(RELOC("starting prom_initialize_tce_table\n"));
 896#endif
 897
 898        /* Search all nodes looking for PHBs. */
 899        for (node = 0; prom_next_node(&node); ) {
 900                compatible[0] = 0;
 901                type[0] = 0;
 902                model[0] = 0;
 903                call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
 904                          compatible, sizeof(compatible));
 905                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
 906                          type, sizeof(type));
 907                call_prom(RELOC("getprop"), 4, 1, node, RELOC("model"),
 908                          model, sizeof(model));
 909
 910                /* Keep the old logic in tack to avoid regression. */
 911                if (compatible[0] != 0) {
 912                        if((strstr(compatible, RELOC("python")) == NULL) &&
 913                           (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
 914                           (strstr(compatible, RELOC("Winnipeg")) == NULL))
 915                                continue;
 916                } else if (model[0] != 0) {
 917                        if ((strstr(model, RELOC("ython")) == NULL) &&
 918                            (strstr(model, RELOC("peedwagon")) == NULL) &&
 919                            (strstr(model, RELOC("innipeg")) == NULL))
 920                                continue;
 921                }
 922
 923                if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) {
 924                        continue;
 925                }
 926
 927                if (call_prom(RELOC("getprop"), 4, 1, node, 
 928                             RELOC("tce-table-minalign"), &minalign, 
 929                             sizeof(minalign)) < 0) {
 930                        minalign = 0;
 931                }
 932
 933                if (call_prom(RELOC("getprop"), 4, 1, node, 
 934                             RELOC("tce-table-minsize"), &minsize, 
 935                             sizeof(minsize)) < 0) {
 936                        minsize = 4UL << 20;
 937                }
 938
 939                /* Even though we read what OF wants, we just set the table
 940                 * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
 941                 * By doing this, we avoid the pitfalls of trying to DMA to
 942                 * MMIO space and the DMA alias hole.
 943                 */
 944                minsize = 4UL << 20;
 945
 946                /* Align to the greater of the align or size */
 947                align = (minalign < minsize) ? minsize : minalign;
 948
 949                /* Carve out storage for the TCE table. */
 950                base = lmb_alloc(minsize, align);
 951
 952                if ( !base ) {
 953                        prom_print(RELOC("ERROR, cannot find space for TCE table.\n"));
 954                        prom_exit();
 955                }
 956
 957                vbase = absolute_to_virt(base);
 958
 959                /* Save away the TCE table attributes for later use. */
 960                prom_tce_table[table].node = node;
 961                prom_tce_table[table].base = vbase;
 962                prom_tce_table[table].size = minsize;
 963
 964#ifdef DEBUG_PROM
 965                prom_print(RELOC("TCE table: 0x"));
 966                prom_print_hex(table);
 967                prom_print_nl();
 968
 969                prom_print(RELOC("\tnode = 0x"));
 970                prom_print_hex(node);
 971                prom_print_nl();
 972
 973                prom_print(RELOC("\tbase = 0x"));
 974                prom_print_hex(vbase);
 975                prom_print_nl();
 976
 977                prom_print(RELOC("\tsize = 0x"));
 978                prom_print_hex(minsize);
 979                prom_print_nl();
 980#endif
 981
 982                /* Initialize the table to have a one-to-one mapping
 983                 * over the allocated size.
 984                 */
 985                tce_entryp = (unsigned long *)base;
 986                for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
 987                        tce_entry = (i << PAGE_SHIFT);
 988                        tce_entry |= 0x3;
 989                        *tce_entryp = tce_entry;
 990                }
 991
 992                /* Call OF to setup the TCE hardware */
 993                if (call_prom(RELOC("package-to-path"), 3, 1, node,
 994                             path, 255) <= 0) {
 995                        prom_print(RELOC("package-to-path failed\n"));
 996                } else {
 997                        prom_print(RELOC("opened "));
 998                        prom_print(path);
 999                        prom_print_nl();
1000                }
1001
1002                phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path);
1003                if ( (long)phb_node <= 0) {
1004                        prom_print(RELOC("open failed\n"));
1005                } else {
1006                        prom_print(RELOC("open success\n"));
1007                }
1008                call_prom(RELOC("call-method"), 6, 0,
1009                             RELOC("set-64-bit-addressing"),
1010                             phb_node,
1011                             -1,
1012                             minsize, 
1013                             base & 0xffffffff,
1014                             (base >> 32) & 0xffffffff);
1015                call_prom(RELOC("close"), 1, 0, phb_node);
1016
1017                table++;
1018        }
1019
1020        /* Flag the first invalid entry */
1021        prom_tce_table[table].node = 0;
1022#ifdef DEBUG_PROM
1023        prom_print(RELOC("ending prom_initialize_tce_table\n"));
1024#endif
1025}
1026
1027/*
1028 * With CHRP SMP we need to use the OF to start the other
1029 * processors so we can't wait until smp_boot_cpus (the OF is
1030 * trashed by then) so we have to put the processors into
1031 * a holding pattern controlled by the kernel (not OF) before
1032 * we destroy the OF.
1033 *
1034 * This uses a chunk of low memory, puts some holding pattern
1035 * code there and sends the other processors off to there until
1036 * smp_boot_cpus tells them to do something.  The holding pattern
1037 * checks that address until its cpu # is there, when it is that
1038 * cpu jumps to __secondary_start().  smp_boot_cpus() takes care
1039 * of setting those values.
1040 *
1041 * We also use physical address 0x4 here to tell when a cpu
1042 * is in its holding pattern code.
1043 *
1044 * Fixup comment... DRENG / PPPBBB - Peter
1045 *
1046 * -- Cort
1047 */
1048static void
1049prom_hold_cpus(unsigned long mem)
1050{
1051        unsigned long i;
1052        unsigned int reg;
1053        phandle node;
1054        unsigned long offset = reloc_offset();
1055        char type[64], *path;
1056        int cpuid = 0;
1057        extern void __secondary_hold(void);
1058        extern unsigned long __secondary_hold_spinloop;
1059        extern unsigned long __secondary_hold_acknowledge;
1060        unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
1061        unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
1062        unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
1063        struct naca_struct *_naca = RELOC(naca);
1064        struct systemcfg *_systemcfg = RELOC(systemcfg);
1065        struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
1066        struct prom_t *_prom = PTRRELOC(&prom);
1067
1068        /* Initially, we must have one active CPU. */
1069        _systemcfg->processorCount = 1;
1070
1071#ifdef DEBUG_PROM
1072        prom_print(RELOC("prom_hold_cpus: start...\n"));
1073        prom_print(RELOC("    1) spinloop       = 0x"));
1074        prom_print_hex(spinloop);
1075        prom_print_nl();
1076        prom_print(RELOC("    1) *spinloop      = 0x"));
1077        prom_print_hex(*spinloop);
1078        prom_print_nl();
1079        prom_print(RELOC("    1) acknowledge    = 0x"));
1080        prom_print_hex(acknowledge);
1081        prom_print_nl();
1082        prom_print(RELOC("    1) *acknowledge   = 0x"));
1083        prom_print_hex(*acknowledge);
1084        prom_print_nl();
1085        prom_print(RELOC("    1) secondary_hold = 0x"));
1086        prom_print_hex(secondary_hold);
1087        prom_print_nl();
1088#endif
1089
1090        /* Set the common spinloop variable, so all of the secondary cpus
1091         * will block when they are awakened from their OF spinloop.
1092         * This must occur for both SMP and non SMP kernels, since OF will
1093         * be trashed when we move the kernel.
1094         */
1095        *spinloop = 0;
1096
1097#ifdef CONFIG_HMT
1098        for (i=0; i < NR_CPUS; i++) {
1099                RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
1100        }
1101#endif
1102        /* look for cpus */
1103        for (node = 0; prom_next_node(&node); ) {
1104                type[0] = 0;
1105                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
1106                          type, sizeof(type));
1107                if (strcmp(type, RELOC("cpu")) != 0)
1108                        continue;
1109
1110                /* Skip non-configured cpus. */
1111                call_prom(RELOC("getprop"), 4, 1, node, RELOC("status"),
1112                          type, sizeof(type));
1113                if (strcmp(type, RELOC("okay")) != 0)
1114                        continue;
1115
1116                reg = -1;
1117                call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
1118                          &reg, sizeof(reg));
1119
1120                /* Only need to start secondary procs, not ourself. */
1121                if ( reg == _prom->cpu )
1122                        continue;
1123
1124                path = (char *) mem;
1125                memset(path, 0, 256);
1126                if ((long) call_prom(RELOC("package-to-path"), 3, 1,
1127                                     node, path, 255) < 0)
1128                        continue;
1129
1130                cpuid++;
1131
1132#ifdef DEBUG_PROM
1133                prom_print_nl();
1134                prom_print(RELOC("cpuid        = 0x"));
1135                prom_print_hex(cpuid);
1136                prom_print_nl();
1137                prom_print(RELOC("cpu hw idx   = 0x"));
1138                prom_print_hex(reg);
1139                prom_print_nl();
1140#endif
1141                _xPaca[cpuid].xHwProcNum = reg;
1142
1143                prom_print(RELOC("starting cpu "));
1144                prom_print(path);
1145
1146                /* Init the acknowledge var which will be reset by
1147                 * the secondary cpu when it awakens from its OF
1148                 * spinloop.
1149                 */
1150                *acknowledge = (unsigned long)-1;
1151
1152#ifdef DEBUG_PROM
1153                prom_print(RELOC("    3) spinloop       = 0x"));
1154                prom_print_hex(spinloop);
1155                prom_print_nl();
1156                prom_print(RELOC("    3) *spinloop      = 0x"));
1157                prom_print_hex(*spinloop);
1158                prom_print_nl();
1159                prom_print(RELOC("    3) acknowledge    = 0x"));
1160                prom_print_hex(acknowledge);
1161                prom_print_nl();
1162                prom_print(RELOC("    3) *acknowledge   = 0x"));
1163                prom_print_hex(*acknowledge);
1164                prom_print_nl();
1165                prom_print(RELOC("    3) secondary_hold = 0x"));
1166                prom_print_hex(secondary_hold);
1167                prom_print_nl();
1168                prom_print(RELOC("    3) cpuid = 0x"));
1169                prom_print_hex(cpuid);
1170                prom_print_nl();
1171#endif
1172                call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid);
1173                prom_print(RELOC("..."));
1174                for ( i = 0 ; (i < 100000000) && 
1175                              (*acknowledge == ((unsigned long)-1)); i++ ) ;
1176#ifdef DEBUG_PROM
1177                {
1178                        unsigned long *p = 0x0;
1179                        prom_print(RELOC("    4) 0x0 = 0x"));
1180                        prom_print_hex(*p);
1181                        prom_print_nl();
1182                }
1183#endif
1184                if (*acknowledge == cpuid) {
1185                        prom_print(RELOC("ok\n"));
1186                        /* Set the number of active processors. */
1187                        _systemcfg->processorCount++;
1188                } else {
1189                        prom_print(RELOC("failed: "));
1190                        prom_print_hex(*acknowledge);
1191                        prom_print_nl();
1192                }
1193        }
1194#ifdef CONFIG_HMT
1195        /* Only enable HMT on processors that provide support. */
1196        if (__is_processor(PV_PULSAR) || 
1197            __is_processor(PV_ICESTAR) ||
1198            __is_processor(PV_SSTAR)) {
1199                prom_print(RELOC("    starting secondary threads\n"));
1200
1201                for (i=0; i < _systemcfg->processorCount ;i++) {
1202                        unsigned long threadid = _systemcfg->processorCount*2-1-i;
1203                        
1204                        if (i == 0) {
1205                                unsigned long pir = _get_PIR();
1206                                if (__is_processor(PV_PULSAR)) {
1207                                        RELOC(hmt_thread_data)[i].pir = 
1208                                                pir & 0x1f;
1209                                } else {
1210                                        RELOC(hmt_thread_data)[i].pir = 
1211                                                pir & 0x3ff;
1212                                }
1213                        }
1214                        
1215                        RELOC(hmt_thread_data)[i].threadid = threadid;
1216#ifdef DEBUG_PROM
1217                        prom_print(RELOC("        cpuid 0x"));
1218                        prom_print_hex(i);
1219                        prom_print(RELOC(" maps to threadid 0x"));
1220                        prom_print_hex(threadid);
1221                        prom_print_nl();
1222                        prom_print(RELOC(" pir 0x"));
1223                        prom_print_hex(RELOC(hmt_thread_data)[i].pir);
1224                        prom_print_nl();
1225#endif
1226                        _xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1;
1227                }
1228                _systemcfg->processorCount *= 2;
1229        } else {
1230                prom_print(RELOC("Processor is not HMT capable\n"));
1231        }
1232#endif
1233        
1234#ifdef DEBUG_PROM
1235        prom_print(RELOC("prom_hold_cpus: end...\n"));
1236#endif
1237}
1238
1239#ifdef CONFIG_PPCDBG
1240extern char *trace_names[];     /* defined in udbg.c -- need a better interface */
1241
1242void parse_ppcdbg_optionlist(const char *cmd,
1243                                    const char *cmdend)
1244{
1245        unsigned long offset = reloc_offset();
1246        char **_trace_names = PTRRELOC(&trace_names[0]);
1247        const char *all = RELOC("all");
1248        struct naca_struct *_naca = RELOC(naca);
1249        const char *p, *pend;
1250        int onoff, i, cmdidx;
1251        unsigned long mask;
1252        char cmdbuf[30];
1253
1254        for (p = cmd, pend = strchr(p, ',');
1255             p < cmdend;
1256             pend = strchr(p, ',')) {
1257                if (pend == NULL || pend > cmdend)
1258                        pend = cmdend;
1259                onoff = 1;      /* default */
1260                if (*p == '+' || *p == '-') {
1261                        /* explicit on or off */
1262                        onoff = (*p == '+');
1263                        p++;
1264                }
1265                /* parse out p..pend here */
1266                if (pend - p < sizeof(cmdbuf)) {
1267                        strncpy(cmdbuf, p, pend - p);
1268                        cmdbuf[pend - p] = '\0';
1269                        for (cmdidx = -1, i = 0; i < PPCDBG_NUM_FLAGS; i++) {
1270                                if (_trace_names[i] &&
1271                                    (strcmp(PTRRELOC(_trace_names[i]), cmdbuf) == 0)) {
1272                                        cmdidx = i;
1273                                        break;
1274                                }
1275                        }
1276                        mask = 0;
1277                        if (cmdidx >= 0) {
1278                                mask = (1 << cmdidx);
1279                        } else if (strcmp(cmdbuf, all) == 0) {
1280                                mask = PPCDBG_ALL;
1281                        } else {
1282                                prom_print(RELOC("ppcdbg: unknown debug: "));
1283                                prom_print(cmdbuf);
1284                                prom_print_nl();
1285                        }
1286                        if (mask) {
1287                                if (onoff)
1288                                        _naca->debug_switch |= mask;
1289                                else
1290                                        _naca->debug_switch &= ~mask;
1291                        }
1292                }
1293                p = pend+1;
1294        }
1295}
1296
1297/*
1298 * Parse ppcdbg= cmdline option.
1299 *
1300 * Option names are listed in <asm/ppcdebug.h> in the trace_names
1301 * table.  Multiple names may be listed separated by commas (no whitespace),
1302 * and each option may be preceeded by a + or - to force on or off state.
1303 * The special option "all" may also be used.  They are processed strictly
1304 * left to right.  Multiple ppcdbg= options are the command line are treated
1305 * as a single option list.
1306 *
1307 * Examples:  ppcdbg=phb_init,buswalk
1308 *            ppcdbg=all,-mm,-tce
1309 *
1310 * ToDo: add "group" names that map to common combinations of flags.
1311 */
1312void parse_ppcdbg_cmd_line(const char *line)
1313{
1314        unsigned long offset = reloc_offset();
1315        const char *ppcdbgopt = RELOC("ppcdbg=");
1316        struct naca_struct *_naca = RELOC(naca);
1317        const char *cmd, *end;
1318
1319        _naca->debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */
1320        cmd = line;
1321        while (cmd && (cmd = strstr(cmd, ppcdbgopt)) != NULL) {
1322                cmd += 7;       /* skip ppcdbg= */
1323                for (end = cmd;
1324                     *end != '\0' && *end != '\t' && *end != ' ';
1325                     end++)
1326                        ; /* scan to whitespace or end */
1327                parse_ppcdbg_optionlist(cmd, end);
1328        }
1329}
1330#endif /* CONFIG_PPCDBG */
1331
1332
1333/*
1334 * Do minimal cmd_line parsing for early boot options.
1335 */
1336static void __init
1337prom_parse_cmd_line(char *line)
1338{
1339#ifdef CONFIG_PPCDBG
1340        parse_ppcdbg_cmd_line(line);
1341#endif
1342}
1343
1344/*
1345 * We enter here early on, when the Open Firmware prom is still
1346 * handling exceptions and the MMU hash table for us.
1347 */
1348
1349unsigned long __init
1350prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
1351          unsigned long r6, unsigned long r7, yaboot_debug_t *yaboot)
1352{
1353        int chrp = 0;
1354        unsigned long mem;
1355        ihandle prom_mmu, prom_op, prom_root, prom_cpu;
1356        phandle cpu_pkg;
1357        unsigned long offset = reloc_offset();
1358        long l, sz;
1359        char *p, *d;
1360        unsigned long phys;
1361        u32 getprop_rval;
1362        struct naca_struct *_naca = RELOC(naca);
1363        struct systemcfg *_systemcfg = RELOC(systemcfg);
1364        struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
1365        struct prom_t *_prom = PTRRELOC(&prom);
1366        char *_cmd_line = PTRRELOC(&cmd_line[0]);
1367
1368        /* Default machine type. */
1369        _systemcfg->platform = PLATFORM_PSERIES;
1370        /* Reset klimit to take into account the embedded system map */
1371        if (RELOC(embedded_sysmap_end))
1372                RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
1373
1374        /* Get a handle to the prom entry point before anything else */
1375        _prom->entry = pp;
1376        _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6);
1377        if ( _prom->bi_recs != NULL ) {
1378                RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + _prom->bi_recs->data[1]);
1379        }
1380
1381#ifdef DEBUG_YABOOT
1382        call_yaboot(yaboot->dummy,offset>>32,offset&0xffffffff);
1383        call_yaboot(yaboot->printf, RELOC("offset = 0x%08x%08x\n"), LONG_MSW(offset), LONG_LSW(offset));
1384#endif
1385
1386        /* Default */
1387        phys = KERNELBASE - offset;
1388
1389#ifdef DEBUG_YABOOT
1390        call_yaboot(yaboot->printf, RELOC("phys = 0x%08x%08x\n"), LONG_MSW(phys), LONG_LSW(phys));
1391#endif
1392
1393
1394#ifdef DEBUG_YABOOT
1395        _prom->yaboot = yaboot;
1396        call_yaboot(yaboot->printf, RELOC("pp = 0x%08x%08x\n"), LONG_MSW(pp), LONG_LSW(pp));
1397        call_yaboot(yaboot->printf, RELOC("prom = 0x%08x%08x\n"), LONG_MSW(_prom->entry), LONG_LSW(_prom->entry));
1398#endif
1399
1400        /* First get a handle for the stdout device */
1401        _prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1,
1402                                       RELOC("/chosen"));
1403
1404#ifdef DEBUG_YABOOT
1405        call_yaboot(yaboot->printf, RELOC("prom->chosen = 0x%08x%08x\n"), LONG_MSW(_prom->chosen), LONG_LSW(_prom->chosen));
1406#endif
1407
1408        if ((long)_prom->chosen <= 0)
1409                prom_exit();
1410
1411        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
1412                            RELOC("stdout"), &getprop_rval,
1413                            sizeof(getprop_rval)) <= 0)
1414                prom_exit();
1415
1416        _prom->stdout = (ihandle)(unsigned long)getprop_rval;
1417
1418#ifdef DEBUG_YABOOT
1419        if (_prom->stdout == 0) {
1420            call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout));
1421        }
1422
1423        call_yaboot(yaboot->printf, RELOC("prom->stdout = 0x%08x%08x\n"), LONG_MSW(_prom->stdout), LONG_LSW(_prom->stdout));
1424#endif
1425
1426#ifdef DEBUG_YABOOT
1427        call_yaboot(yaboot->printf, RELOC("Location: 0x11\n"));
1428#endif
1429
1430        mem = RELOC(klimit) - offset; 
1431#ifdef DEBUG_YABOOT
1432        call_yaboot(yaboot->printf, RELOC("Location: 0x11b\n"));
1433#endif
1434
1435        /* Get the full OF pathname of the stdout device */
1436        p = (char *) mem;
1437        memset(p, 0, 256);
1438        call_prom(RELOC("instance-to-path"), 3, 1, _prom->stdout, p, 255);
1439        RELOC(of_stdout_device) = PTRUNRELOC(p);
1440        mem += strlen(p) + 1;
1441
1442        getprop_rval = 1;
1443        prom_root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
1444        if (prom_root != (ihandle)-1) {
1445                call_prom(RELOC("getprop"), 4, 1,
1446                    prom_root, RELOC("#size-cells"),
1447                    &getprop_rval, sizeof(getprop_rval));
1448        }
1449        _prom->encode_phys_size = (getprop_rval==1) ? 32 : 64;
1450
1451        /* Fetch the cmd_line */
1452        sz = (long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
1453                            RELOC("bootargs"), _cmd_line,
1454                            sizeof(cmd_line)-1);
1455        if (sz > 0)
1456                _cmd_line[sz] = '\0';
1457        if (sz <=1 )
1458                strcpy(_cmd_line,RELOC(CONFIG_CMDLINE));
1459
1460        prom_parse_cmd_line(_cmd_line);
1461
1462#ifdef DEBUG_PROM
1463        prom_print(RELOC("DRENG:    Detect OF version...\n"));
1464#endif
1465        /* Find the OF version */
1466        prom_op = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
1467        if (prom_op != (ihandle)-1) {
1468                char model[64];
1469                sz = (long)call_prom(RELOC("getprop"), 4, 1, prom_op,
1470                                    RELOC("model"), model, 64);
1471                if (sz > 0) {
1472                        char *c;
1473                        /* hack to skip the ibm chrp firmware # */
1474                        if ( strncmp(model,RELOC("IBM"),3) ) {
1475                                for (c = model; *c; c++)
1476                                        if (*c >= '0' && *c <= '9') {
1477                                                _prom->version = *c - '0';
1478                                                break;
1479                                        }
1480                        }
1481                        else
1482                                chrp = 1;
1483                }
1484        }
1485        if (_prom->version >= 3)
1486                prom_print(RELOC("OF Version 3 detected.\n"));
1487
1488
1489        /* Determine which cpu is actually running right _now_ */
1490        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
1491                            RELOC("cpu"), &getprop_rval,
1492                            sizeof(getprop_rval)) <= 0)
1493                prom_exit();
1494
1495        prom_cpu = (ihandle)(unsigned long)getprop_rval;
1496        cpu_pkg = call_prom(RELOC("instance-to-package"), 1, 1, prom_cpu);
1497        call_prom(RELOC("getprop"), 4, 1,
1498                cpu_pkg, RELOC("reg"),
1499                &getprop_rval, sizeof(getprop_rval));
1500        _prom->cpu = (int)(unsigned long)getprop_rval;
1501        _xPaca[0].xHwProcNum = _prom->cpu;
1502
1503#ifdef DEBUG_PROM
1504        prom_print(RELOC("Booting CPU hw index = 0x"));
1505        prom_print_hex(_prom->cpu);
1506        prom_print_nl();
1507#endif
1508
1509        /* Get the boot device and translate it to a full OF pathname. */
1510        p = (char *) mem;
1511        l = (long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
1512                            RELOC("bootpath"), p, 1<<20);
1513        if (l > 0) {
1514                p[l] = 0;       /* should already be null-terminated */
1515                RELOC(bootpath) = PTRUNRELOC(p);
1516                mem += l + 1;
1517                d = (char *) mem;
1518                *d = 0;
1519                call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);
1520                RELOC(bootdevice) = PTRUNRELOC(d);
1521                mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1);
1522        }
1523
1524        mem = prom_initialize_lmb(mem);
1525
1526        mem = prom_bi_rec_reserve(mem);
1527
1528        mem = check_display(mem);
1529
1530        prom_instantiate_rtas();
1531        
1532        /* Initialize some system info into the Naca early... */
1533        mem = prom_initialize_naca(mem);
1534
1535        /* If we are on an SMP machine, then we *MUST* do the
1536         * following, regardless of whether we have an SMP
1537         * kernel or not.
1538         */
1539        if (_systemcfg->processorCount > 1)
1540                prom_hold_cpus(mem);
1541
1542#ifdef DEBUG_PROM
1543        prom_print(RELOC("copying OF device tree...\n"));
1544#endif
1545        mem = copy_device_tree(mem);
1546
1547        RELOC(klimit) = mem + offset;
1548
1549        lmb_reserve(0, __pa(RELOC(klimit)));
1550
1551        if (_systemcfg->platform == PLATFORM_PSERIES)
1552                prom_initialize_tce_table();
1553
1554        if ((long) call_prom(RELOC("getprop"), 4, 1,
1555                                _prom->chosen,
1556                                RELOC("mmu"),
1557                                &getprop_rval,
1558                                sizeof(getprop_rval)) <= 0) {   
1559                prom_print(RELOC(" no MMU found\n"));
1560                prom_exit();
1561        }
1562
1563        /* We assume the phys. address size is 3 cells */
1564        prom_mmu = (ihandle)(unsigned long)getprop_rval;
1565
1566        if ((long)call_prom(RELOC("call-method"), 4, 4,
1567                                RELOC("translate"),
1568                                prom_mmu,
1569                                (void *)(KERNELBASE - offset),
1570                                (void *)1) != 0) {
1571                prom_print(RELOC(" (translate failed) "));
1572        } else {
1573                prom_print(RELOC(" (translate ok) "));
1574                phys = (unsigned long)_prom->args.rets[3];
1575        }
1576
1577        /* If OpenFirmware version >= 3, then use quiesce call */
1578        if (_prom->version >= 3) {
1579                prom_print(RELOC("Calling quiesce ...\n"));
1580                call_prom(RELOC("quiesce"), 0, 0);
1581                phys = KERNELBASE - offset;
1582        }
1583
1584        prom_print(RELOC("returning from prom_init\n"));
1585        return phys;
1586}
1587
1588
1589static int
1590prom_set_color(ihandle ih, int i, int r, int g, int b)
1591{
1592        unsigned long offset = reloc_offset();
1593
1594        return (int)(long)call_prom(RELOC("call-method"), 6, 1,
1595                                    RELOC("color!"),
1596                                    ih,
1597                                    (void *)(long) i,
1598                                    (void *)(long) b,
1599                                    (void *)(long) g,
1600                                    (void *)(long) r );
1601}
1602
1603/*
1604 * If we have a display that we don't know how to drive,
1605 * we will want to try to execute OF's open method for it
1606 * later.  However, OF will probably fall over if we do that
1607 * we've taken over the MMU.
1608 * So we check whether we will need to open the display,
1609 * and if so, open it now.
1610 */
1611static unsigned long __init
1612check_display(unsigned long mem)
1613{
1614        phandle node;
1615        ihandle ih;
1616        int i;
1617        unsigned long offset = reloc_offset();
1618        struct prom_t *_prom = PTRRELOC(&prom);
1619        char type[64], *path;
1620        static unsigned char default_colors[] = {
1621                0x00, 0x00, 0x00,
1622                0x00, 0x00, 0xaa,
1623                0x00, 0xaa, 0x00,
1624                0x00, 0xaa, 0xaa,
1625                0xaa, 0x00, 0x00,
1626                0xaa, 0x00, 0xaa,
1627                0xaa, 0xaa, 0x00,
1628                0xaa, 0xaa, 0xaa,
1629                0x55, 0x55, 0x55,
1630                0x55, 0x55, 0xff,
1631                0x55, 0xff, 0x55,
1632                0x55, 0xff, 0xff,
1633                0xff, 0x55, 0x55,
1634                0xff, 0x55, 0xff,
1635                0xff, 0xff, 0x55,
1636                0xff, 0xff, 0xff
1637        };
1638
1639        _prom->disp_node = 0;
1640
1641        for (node = 0; prom_next_node(&node); ) {
1642                type[0] = 0;
1643                call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
1644                          type, sizeof(type));
1645                if (strcmp(type, RELOC("display")) != 0)
1646                        continue;
1647                /* It seems OF doesn't null-terminate the path :-( */
1648                path = (char *) mem;
1649                memset(path, 0, 256);
1650                if ((long) call_prom(RELOC("package-to-path"), 3, 1,
1651                                    node, path, 255) < 0)
1652                        continue;
1653                prom_print(RELOC("opening display "));
1654                prom_print(path);
1655                ih = (ihandle)call_prom(RELOC("open"), 1, 1, path);
1656                if (ih == (ihandle)0 || ih == (ihandle)-1) {
1657                        prom_print(RELOC("... failed\n"));
1658                        continue;
1659                }
1660                prom_print(RELOC("... ok\n"));
1661
1662                if (_prom->disp_node == 0)
1663                        _prom->disp_node = (ihandle)(unsigned long)node;
1664
1665                /* Setup a useable color table when the appropriate
1666                 * method is available. Should update this to set-colors */
1667                for (i = 0; i < 32; i++)
1668                        if (prom_set_color(ih, i, RELOC(default_colors)[i*3],
1669                                           RELOC(default_colors)[i*3+1],
1670                                           RELOC(default_colors)[i*3+2]) != 0)
1671                                break;
1672
1673#ifdef CONFIG_FB
1674                for (i = 0; i < LINUX_LOGO_COLORS; i++)
1675                        if (prom_set_color(ih, i + 32,
1676                                           RELOC(linux_logo_red)[i],
1677                                           RELOC(linux_logo_green)[i],
1678                                           RELOC(linux_logo_blue)[i]) != 0)
1679                                break;
1680#endif /* CONFIG_FB */
1681
1682                /*
1683                 * If this display is the device that OF is using for stdout,
1684                 * move it to the front of the list.
1685                 */
1686                mem += strlen(path) + 1;
1687                i = RELOC(prom_num_displays)++;
1688                if (RELOC(of_stdout_device) != 0 && i > 0
1689                    && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
1690                        for (; i > 0; --i)
1691                                RELOC(prom_display_paths[i]) = RELOC(prom_display_paths[i-1]);
1692                }
1693                RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
1694                if (RELOC(prom_num_displays) >= FB_MAX)
1695                        break;
1696        }
1697        return DOUBLEWORD_ALIGN(mem);
1698}
1699
1700void
1701virt_irq_init(void)
1702{
1703        int i;
1704        for (i = 0; i < NR_IRQS; i++)
1705                virt_irq_to_real_map[i] = UNDEFINED_IRQ;
1706        for (i = 0; i < NR_HW_IRQS; i++)
1707                real_irq_to_virt_map[i] = UNDEFINED_IRQ;
1708}
1709
1710/* Create a mapping for a real_irq if it doesn't already exist.
1711 * Return the virtual irq as a convenience.
1712 */
1713unsigned long
1714virt_irq_create_mapping(unsigned long real_irq)
1715{
1716        unsigned long virq;
1717        if (naca->interrupt_controller == IC_OPEN_PIC)
1718                return real_irq;        /* no mapping for openpic (for now) */
1719        virq = real_irq_to_virt(real_irq);
1720        if (virq == UNDEFINED_IRQ) {
1721                /* Assign a virtual IRQ number */
1722                if (real_irq < NR_IRQS && virt_irq_to_real(real_irq) == UNDEFINED_IRQ) {
1723                        /* A 1-1 mapping will work. */
1724                        virq = real_irq;
1725                } else {
1726                        while (last_virt_irq < NR_IRQS &&
1727                               virt_irq_to_real(++last_virt_irq) != UNDEFINED_IRQ)
1728                                /* skip irq's in use */;
1729                        if (last_virt_irq >= NR_IRQS)
1730                                panic("Too many IRQs are required on this system.  NR_IRQS=%d\n", NR_IRQS);
1731                        virq = last_virt_irq;
1732                }
1733                virt_irq_to_real_map[virq] = real_irq;
1734                real_irq_to_virt_map[real_irq] = virq;
1735        }
1736        return virq;
1737}
1738
1739
1740static int __init
1741prom_next_node(phandle *nodep)
1742{
1743        phandle node;
1744        unsigned long offset = reloc_offset();
1745
1746        if ((node = *nodep) != 0
1747            && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0)
1748                return 1;
1749        if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
1750                return 1;
1751        for (;;) {
1752                if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0)
1753                        return 0;
1754                if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
1755                        return 1;
1756        }
1757}
1758
1759/*
1760 * Make a copy of the device tree from the PROM.
1761 */
1762static unsigned long __init
1763copy_device_tree(unsigned long mem_start)
1764{
1765        phandle root;
1766        unsigned long new_start;
1767        struct device_node **allnextp;
1768        unsigned long offset = reloc_offset();
1769        unsigned long mem_end = mem_start + (8<<20);
1770
1771        root = call_prom(RELOC("peer"), 1, 1, (phandle)0);
1772        if (root == (phandle)0) {
1773                prom_print(RELOC("couldn't get device tree root\n"));
1774                prom_exit();
1775        }
1776        allnextp = &RELOC(allnodes);
1777        mem_start = DOUBLEWORD_ALIGN(mem_start);
1778        new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
1779        *allnextp = 0;
1780        return new_start;
1781}
1782
1783__init
1784static unsigned long
1785inspect_node(phandle node, struct device_node *dad,
1786             unsigned long mem_start, unsigned long mem_end,
1787             struct device_node ***allnextpp)
1788{
1789        int l;
1790        phandle child;
1791        struct device_node *np;
1792        struct property *pp, **prev_propp;
1793        char *prev_name, *namep;
1794        unsigned char *valp;
1795        unsigned long offset = reloc_offset();
1796
1797        np = (struct device_node *) mem_start;
1798        mem_start += sizeof(struct device_node);
1799        memset(np, 0, sizeof(*np));
1800        np->node = node;
1801        **allnextpp = PTRUNRELOC(np);
1802        *allnextpp = &np->allnext;
1803        if (dad != 0) {
1804                np->parent = PTRUNRELOC(dad);
1805                /* we temporarily use the `next' field as `last_child'. */
1806                if (dad->next == 0)
1807                        dad->child = PTRUNRELOC(np);
1808                else
1809                        dad->next->sibling = PTRUNRELOC(np);
1810                dad->next = np;
1811        }
1812
1813        /* get and store all properties */
1814        prev_propp = &np->properties;
1815        prev_name = RELOC("");
1816        for (;;) {
1817                pp = (struct property *) mem_start;
1818                namep = (char *) (pp + 1);
1819                pp->name = PTRUNRELOC(namep);
1820                if ((long) call_prom(RELOC("nextprop"), 3, 1, node, prev_name,
1821                                    namep) <= 0)
1822                        break;
1823                mem_start = DOUBLEWORD_ALIGN((unsigned long)namep + strlen(namep) + 1);
1824                prev_name = namep;
1825                valp = (unsigned char *) mem_start;
1826                pp->value = PTRUNRELOC(valp);
1827                pp->length = (int)(long)
1828                        call_prom(RELOC("getprop"), 4, 1, node, namep,
1829                                  valp, mem_end - mem_start);
1830                if (pp->length < 0)
1831                        continue;
1832                mem_start = DOUBLEWORD_ALIGN(mem_start + pp->length);
1833                *prev_propp = PTRUNRELOC(pp);
1834                prev_propp = &pp->next;
1835        }
1836        *prev_propp = 0;
1837
1838        /* get the node's full name */
1839        l = (long) call_prom(RELOC("package-to-path"), 3, 1, node,
1840                            (char *) mem_start, mem_end - mem_start);
1841        if (l >= 0) {
1842                np->full_name = PTRUNRELOC((char *) mem_start);
1843                *(char *)(mem_start + l) = 0;
1844                mem_start = DOUBLEWORD_ALIGN(mem_start + l + 1);
1845        }
1846
1847        /* do all our children */
1848        child = call_prom(RELOC("child"), 1, 1, node);
1849        while (child != (phandle)0) {
1850                mem_start = inspect_node(child, np, mem_start, mem_end,
1851                                         allnextpp);
1852                child = call_prom(RELOC("peer"), 1, 1, child);
1853        }
1854
1855        return mem_start;
1856}
1857
1858/*
1859 * finish_device_tree is called once things are running normally
1860 * (i.e. with text and data mapped to the address they were linked at).
1861 * It traverses the device tree and fills in the name, type,
1862 * {n_}addrs and {n_}intrs fields of each node.
1863 */
1864void __init
1865finish_device_tree(void)
1866{
1867        unsigned long mem = klimit;
1868
1869        virt_irq_init();
1870
1871        mem = finish_node(allnodes, mem, NULL, 0, 0);
1872        dev_tree_size = mem - (unsigned long) allnodes;
1873
1874        mem = _ALIGN(mem, PAGE_SIZE);
1875        lmb_reserve(__pa(klimit), mem-klimit);
1876
1877        klimit = mem;
1878
1879        rtas.dev = find_devices("rtas");
1880}
1881
1882static unsigned long __init
1883finish_node(struct device_node *np, unsigned long mem_start,
1884            interpret_func *ifunc, int naddrc, int nsizec)
1885{
1886        struct device_node *child;
1887        int *ip;
1888
1889        np->name = get_property(np, "name", 0);
1890        np->type = get_property(np, "device_type", 0);
1891
1892        /* get the device addresses and interrupts */
1893        if (ifunc != NULL) {
1894          mem_start = ifunc(np, mem_start, naddrc, nsizec);
1895        }
1896        mem_start = finish_node_interrupts(np, mem_start);
1897
1898        /* Look for #address-cells and #size-cells properties. */
1899        ip = (int *) get_property(np, "#address-cells", 0);
1900        if (ip != NULL)
1901                naddrc = *ip;
1902        ip = (int *) get_property(np, "#size-cells", 0);
1903        if (ip != NULL)
1904                nsizec = *ip;
1905
1906        /* the f50 sets the name to 'display' and 'compatible' to what we
1907         * expect for the name -- Cort
1908         */
1909        ifunc = NULL;
1910        if (!strcmp(np->name, "display"))
1911                np->name = get_property(np, "compatible", 0);
1912
1913        if (!strcmp(np->name, "device-tree") || np->parent == NULL)
1914                ifunc = interpret_root_props;
1915        else if (np->type == 0)
1916                ifunc = NULL;
1917        else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
1918                ifunc = interpret_pci_props;
1919        else if (!strcmp(np->type, "isa"))
1920                ifunc = interpret_isa_props;
1921
1922        for (child = np->child; child != NULL; child = child->sibling)
1923                mem_start = finish_node(child, mem_start, ifunc,
1924                                        naddrc, nsizec);
1925
1926        return mem_start;
1927}
1928
1929/* This routine walks the interrupt tree for a given device node and gather 
1930 * all necessary informations according to the draft interrupt mapping
1931 * for CHRP. The current version was only tested on Apple "Core99" machines
1932 * and may not handle cascaded controllers correctly.
1933 */
1934__init
1935static unsigned long
1936finish_node_interrupts(struct device_node *np, unsigned long mem_start)
1937{
1938        /* Finish this node */
1939        unsigned int *isizep, *asizep, *interrupts, *map, *map_mask, *reg;
1940        phandle *parent, map_parent;
1941        struct device_node *node, *parent_node;
1942        int l, isize, ipsize, asize, map_size, regpsize;
1943
1944        /* Currently, we don't look at all nodes with no "interrupts" property */
1945
1946        interrupts = (unsigned int *)get_property(np, "interrupts", &l);
1947        if (interrupts == NULL)
1948                return mem_start;
1949        ipsize = l>>2;
1950
1951        reg = (unsigned int *)get_property(np, "reg", &l);
1952        regpsize = l>>2;
1953
1954        /* We assume default interrupt cell size is 1 (bugus ?) */
1955        isize = 1;
1956        node = np;
1957        
1958        do {
1959            /* We adjust the cell size if the current parent contains an #interrupt-cells
1960             * property */
1961            isizep = (unsigned int *)get_property(node, "#interrupt-cells", &l);
1962            if (isizep)
1963                isize = *isizep;
1964
1965            /* We don't do interrupt cascade (ISA) for now, we stop on the first 
1966             * controller found
1967             */
1968            if (get_property(node, "interrupt-controller", &l)) {
1969                int i,j;
1970
1971                np->intrs = (struct interrupt_info *) mem_start;
1972                np->n_intrs = ipsize / isize;
1973                mem_start += np->n_intrs * sizeof(struct interrupt_info);
1974                for (i = 0; i < np->n_intrs; ++i) {
1975                    np->intrs[i].line = openpic_to_irq(virt_irq_create_mapping(*interrupts++));
1976                    np->intrs[i].sense = 1;
1977                    if (isize > 1)
1978                        np->intrs[i].sense = *interrupts++;
1979                    for (j=2; j<isize; j++)
1980                        interrupts++;
1981                }
1982                return mem_start;
1983            }
1984            /* We lookup for an interrupt-map. This code can only handle one interrupt
1985             * per device in the map. We also don't handle #address-cells in the parent
1986             * I skip the pci node itself here, may not be necessary but I don't like it's
1987             * reg property.
1988             */
1989            if (np != node)
1990                map = (unsigned int *)get_property(node, "interrupt-map", &l);
1991             else
1992                map = NULL;
1993            if (map && l) {
1994                int i, found, temp_isize, temp_asize;
1995                map_size = l>>2;
1996                map_mask = (unsigned int *)get_property(node, "interrupt-map-mask", &l);
1997                asizep = (unsigned int *)get_property(node, "#address-cells", &l);
1998                if (asizep && l == sizeof(unsigned int))
1999                    asize = *asizep;
2000                else
2001                    asize = 0;
2002                found = 0;
2003                while (map_size>0 && !found) {
2004                    found = 1;
2005                    for (i=0; i<asize; i++) {
2006                        unsigned int mask = map_mask ? map_mask[i] : 0xffffffff;
2007                        if (!reg || (i>=regpsize) || ((mask & *map) != (mask & reg[i])))
2008                            found = 0;
2009                        map++;
2010                        map_size--;
2011                    }
2012                    for (i=0; i<isize; i++) {
2013                        unsigned int mask = map_mask ? map_mask[i+asize] : 0xffffffff;
2014                        if ((mask & *map) != (mask & interrupts[i]))
2015                            found = 0;
2016                        map++;
2017                        map_size--;
2018                    }
2019                    map_parent = *((phandle *)map);
2020                    map+=1; map_size-=1;
2021                    parent_node = find_phandle(map_parent);
2022                    temp_isize = isize;
2023                    temp_asize = 0;
2024                    if (parent_node) {
2025                        isizep = (unsigned int *)get_property(parent_node, "#interrupt-cells", &l);
2026                        if (isizep)
2027                            temp_isize = *isizep;
2028                        asizep = (unsigned int *)get_property(parent_node, "#address-cells", &l);
2029                        if (asizep && l == sizeof(unsigned int))
2030                                temp_asize = *asizep;
2031                    }
2032                    if (!found) {
2033                        map += temp_isize + temp_asize;
2034                        map_size -= temp_isize + temp_asize;
2035                    }
2036                }
2037                if (found) {
2038                    /* Mapped to a new parent.  Use the reg and interrupts specified in
2039                     * the map as the new search parameters.  Then search from the parent.
2040                     */
2041                    node = parent_node;
2042                    reg = map;
2043                    regpsize = temp_asize;
2044                    interrupts = map + temp_asize;
2045                    ipsize = temp_isize;
2046                    continue;
2047                }
2048            }
2049            /* We look for an explicit interrupt-parent.
2050             */
2051            parent = (phandle *)get_property(node, "interrupt-parent", &l);
2052            if (parent && (l == sizeof(phandle)) &&
2053                (parent_node = find_phandle(*parent))) {
2054                node = parent_node;
2055                continue;
2056            }
2057            /* Default, get real parent */
2058            node = node->parent;
2059        } while (node);
2060
2061        return mem_start;
2062}
2063
2064int
2065prom_n_addr_cells(struct device_node* np)
2066{
2067        int* ip;
2068        do {
2069                if (np->parent)
2070                        np = np->parent;
2071                ip = (int *) get_property(np, "#address-cells", 0);
2072                if (ip != NULL)
2073                        return *ip;
2074        } while (np->parent);
2075        /* No #address-cells property for the root node, default to 1 */
2076        return 1;
2077}
2078
2079int
2080prom_n_size_cells(struct device_node* np)
2081{
2082        int* ip;
2083        do {
2084                if (np->parent)
2085                        np = np->parent;
2086                ip = (int *) get_property(np, "#size-cells", 0);
2087                if (ip != NULL)
2088                        return *ip;
2089        } while (np->parent);
2090        /* No #size-cells property for the root node, default to 1 */
2091        return 1;
2092}
2093
2094static unsigned long __init
2095interpret_pci_props(struct device_node *np, unsigned long mem_start,
2096                    int naddrc, int nsizec)
2097{
2098        struct address_range *adr;
2099        struct pci_reg_property *pci_addrs;
2100        int i, l;
2101
2102        pci_addrs = (struct pci_reg_property *)
2103                get_property(np, "assigned-addresses", &l);
2104        if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
2105                i = 0;
2106                adr = (struct address_range *) mem_start;
2107                while ((l -= sizeof(struct pci_reg_property)) >= 0) {
2108                        adr[i].space = pci_addrs[i].addr.a_hi;
2109                        adr[i].address = pci_addrs[i].addr.a_lo;
2110                        adr[i].size = pci_addrs[i].size_lo;
2111                        ++i;
2112                }
2113                np->addrs = adr;
2114                np->n_addrs = i;
2115                mem_start += i * sizeof(struct address_range);
2116        }
2117        return mem_start;
2118}
2119
2120static unsigned long __init
2121interpret_isa_props(struct device_node *np, unsigned long mem_start,
2122                    int naddrc, int nsizec)
2123{
2124        struct isa_reg_property *rp;
2125        struct address_range *adr;
2126        int i, l;
2127
2128        rp = (struct isa_reg_property *) get_property(np, "reg", &l);
2129        if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
2130                i = 0;
2131                adr = (struct address_range *) mem_start;
2132                while ((l -= sizeof(struct reg_property)) >= 0) {
2133                        adr[i].space = rp[i].space;
2134                        adr[i].address = rp[i].address
2135                                + (adr[i].space? 0: _ISA_MEM_BASE);
2136                        adr[i].size = rp[i].size;
2137                        ++i;
2138                }
2139                np->addrs = adr;
2140                np->n_addrs = i;
2141                mem_start += i * sizeof(struct address_range);
2142        }
2143
2144        return mem_start;
2145}
2146
2147static unsigned long __init
2148interpret_root_props(struct device_node *np, unsigned long mem_start,
2149                     int naddrc, int nsizec)
2150{
2151        struct address_range *adr;
2152        int i, l;
2153        unsigned int *rp;
2154        int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
2155
2156        rp = (unsigned int *) get_property(np, "reg", &l);
2157        if (rp != 0 && l >= rpsize) {
2158                i = 0;
2159                adr = (struct address_range *) mem_start;
2160                while ((l -= rpsize) >= 0) {
2161                        adr[i].space = 0;
2162                        adr[i].address = rp[naddrc - 1];
2163                        adr[i].size = rp[naddrc + nsizec - 1];
2164                        ++i;
2165                        rp += naddrc + nsizec;
2166                }
2167                np->addrs = adr;
2168                np->n_addrs = i;
2169                mem_start += i * sizeof(struct address_range);
2170        }
2171
2172        return mem_start;
2173}
2174
2175/*
2176 * Work out the sense (active-low level / active-high edge)
2177 * of each interrupt from the device tree.
2178 */
2179void __init
2180prom_get_irq_senses(unsigned char *senses, int off, int max)
2181{
2182        struct device_node *np;
2183        int i, j;
2184
2185        /* default to level-triggered */
2186        memset(senses, 1, max - off);
2187
2188        for (np = allnodes; np != 0; np = np->allnext) {
2189                for (j = 0; j < np->n_intrs; j++) {
2190                        i = np->intrs[j].line;
2191                        if (i >= off && i < max)
2192                                senses[i-off] = np->intrs[j].sense;
2193                }
2194        }
2195}
2196
2197/*
2198 * Construct and return a list of the device_nodes with a given name.
2199 */
2200struct device_node *
2201find_devices(const char *name)
2202{
2203        struct device_node *head, **prevp, *np;
2204
2205        prevp = &head;
2206        for (np = allnodes; np != 0; np = np->allnext) {
2207                if (np->name != 0 && strcasecmp(np->name, name) == 0) {
2208                        *prevp = np;
2209                        prevp = &np->next;
2210                }
2211        }
2212        *prevp = 0;
2213        return head;
2214}
2215
2216/*
2217 * Construct and return a list of the device_nodes with a given type.
2218 */
2219struct device_node *
2220find_type_devices(const char *type)
2221{
2222        struct device_node *head, **prevp, *np;
2223
2224        prevp = &head;
2225        for (np = allnodes; np != 0; np = np->allnext) {
2226                if (np->type != 0 && strcasecmp(np->type, type) == 0) {
2227                        *prevp = np;
2228                        prevp = &np->next;
2229                }
2230        }
2231        *prevp = 0;
2232        return head;
2233}
2234
2235/*
2236 * Returns all nodes linked together
2237 */
2238struct device_node * __openfirmware
2239find_all_nodes(void)
2240{
2241        struct device_node *head, **prevp, *np;
2242
2243        prevp = &head;
2244        for (np = allnodes; np != 0; np = np->allnext) {
2245                *prevp = np;
2246                prevp = &np->next;
2247        }
2248        *prevp = 0;
2249        return head;
2250}
2251
2252/* Checks if the given "compat" string matches one of the strings in
2253 * the device's "compatible" property
2254 */
2255int
2256device_is_compatible(struct device_node *device, const char *compat)
2257{
2258        const char* cp;
2259        int cplen, l;
2260
2261        cp = (char *) get_property(device, "compatible", &cplen);
2262        if (cp == NULL)
2263                return 0;
2264        while (cplen > 0) {
2265                if (strncasecmp(cp, compat, strlen(compat)) == 0)
2266                        return 1;
2267                l = strlen(cp) + 1;
2268                cp += l;
2269                cplen -= l;
2270        }
2271
2272        return 0;
2273}
2274
2275
2276/*
2277 * Indicates whether the root node has a given value in its
2278 * compatible property.
2279 */
2280int
2281machine_is_compatible(const char *compat)
2282{
2283        struct device_node *root;
2284        
2285        root = find_path_device("/");
2286        if (root == 0)
2287                return 0;
2288        return device_is_compatible(root, compat);
2289}
2290
2291/*
2292 * Construct and return a list of the device_nodes with a given type
2293 * and compatible property.
2294 */
2295struct device_node *
2296find_compatible_devices(const char *type, const char *compat)
2297{
2298        struct device_node *head, **prevp, *np;
2299
2300        prevp = &head;
2301        for (np = allnodes; np != 0; np = np->allnext) {
2302                if (type != NULL
2303                    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
2304                        continue;
2305                if (device_is_compatible(np, compat)) {
2306                        *prevp = np;
2307                        prevp = &np->next;
2308                }
2309        }
2310        *prevp = 0;
2311        return head;
2312}
2313
2314/*
2315 * Find the device_node with a given full_name.
2316 */
2317struct device_node *
2318find_path_device(const char *path)
2319{
2320        struct device_node *np;
2321
2322        for (np = allnodes; np != 0; np = np->allnext)
2323                if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
2324                        return np;
2325        return NULL;
2326}
2327
2328/*
2329 * Find the device_node with a given phandle.
2330 */
2331static struct device_node * __init
2332find_phandle(phandle ph)
2333{
2334        struct device_node *np;
2335
2336        for (np = allnodes; np != 0; np = np->allnext)
2337                if (np->node == ph)
2338                        return np;
2339        return NULL;
2340}
2341
2342/*
2343 * Find a property with a given name for a given node
2344 * and return the value.
2345 */
2346unsigned char *
2347get_property(struct device_node *np, const char *name, int *lenp)
2348{
2349        struct property *pp;
2350
2351        for (pp = np->properties; pp != 0; pp = pp->next)
2352                if (strcmp(pp->name, name) == 0) {
2353                        if (lenp != 0)
2354                                *lenp = pp->length;
2355                        return pp->value;
2356                }
2357        return 0;
2358}
2359
2360/*
2361 * Add a property to a node
2362 */
2363void __openfirmware
2364prom_add_property(struct device_node* np, struct property* prop)
2365{
2366        struct property **next = &np->properties;
2367
2368        prop->next = NULL;      
2369        while (*next)
2370                next = &(*next)->next;
2371        *next = prop;
2372}
2373
2374#if 0
2375void __openfirmware
2376print_properties(struct device_node *np)
2377{
2378        struct property *pp;
2379        char *cp;
2380        int i, n;
2381
2382        for (pp = np->properties; pp != 0; pp = pp->next) {
2383                printk(KERN_INFO "%s", pp->name);
2384                for (i = strlen(pp->name); i < 16; ++i)
2385                        printk(" ");
2386                cp = (char *) pp->value;
2387                for (i = pp->length; i > 0; --i, ++cp)
2388                        if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
2389                            || (i == 1 && *cp != 0))
2390                                break;
2391                if (i == 0 && pp->length > 1) {
2392                        /* looks like a string */
2393                        printk(" %s\n", (char *) pp->value);
2394                } else {
2395                        /* dump it in hex */
2396                        n = pp->length;
2397                        if (n > 64)
2398                                n = 64;
2399                        if (pp->length % 4 == 0) {
2400                                unsigned int *p = (unsigned int *) pp->value;
2401
2402                                n /= 4;
2403                                for (i = 0; i < n; ++i) {
2404                                        if (i != 0 && (i % 4) == 0)
2405                                                printk("\n                ");
2406                                        printk(" %08x", *p++);
2407                                }
2408                        } else {
2409                                unsigned char *bp = pp->value;
2410
2411                                for (i = 0; i < n; ++i) {
2412                                        if (i != 0 && (i % 16) == 0)
2413                                                printk("\n                ");
2414                                        printk(" %02x", *bp++);
2415                                }
2416                        }
2417                        printk("\n");
2418                        if (pp->length > 64)
2419                                printk("                 ... (length = %d)\n",
2420                                       pp->length);
2421                }
2422        }
2423}
2424#endif
2425
2426
2427void __init
2428abort()
2429{
2430#ifdef CONFIG_XMON
2431        xmon(NULL);
2432#endif
2433        for (;;)
2434                prom_exit();
2435}
2436
2437
2438/* Verify bi_recs are good */
2439static struct bi_record *
2440prom_bi_rec_verify(struct bi_record *bi_recs)
2441{
2442        struct bi_record *first, *last;
2443
2444        if ( bi_recs == NULL || bi_recs->tag != BI_FIRST )
2445                return NULL;
2446
2447        last = (struct bi_record *)bi_recs->data[0];
2448        if ( last == NULL || last->tag != BI_LAST )
2449                return NULL;
2450
2451        first = (struct bi_record *)last->data[0];
2452        if ( first == NULL || first != bi_recs )
2453                return NULL;
2454
2455        return bi_recs;
2456}
2457
2458static unsigned long
2459prom_bi_rec_reserve(unsigned long mem)
2460{
2461        unsigned long offset = reloc_offset();
2462        struct prom_t *_prom = PTRRELOC(&prom);
2463        struct bi_record *rec;
2464
2465        if ( _prom->bi_recs != NULL) {
2466
2467                for ( rec=_prom->bi_recs;
2468                      rec->tag != BI_LAST;
2469                      rec=bi_rec_next(rec) ) {
2470                        switch (rec->tag) {
2471#ifdef CONFIG_BLK_DEV_INITRD
2472                        case BI_INITRD:
2473                                lmb_reserve(rec->data[0], rec->data[1]);
2474                                break;
2475#endif /* CONFIG_BLK_DEV_INITRD */
2476                        }
2477                }
2478                /* The next use of this field will be after relocation
2479                 * is enabled, so convert this physical address into a
2480                 * virtual address.
2481                 */
2482                _prom->bi_recs = PTRUNRELOC(_prom->bi_recs);
2483        }
2484
2485        return mem;
2486}
2487
2488
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.