* 2 of the License, or (at your option) any later version.
*/
-#if 0
-#define DEBUG_PROM
-#endif
+#undef DEBUG
#include <stdarg.h>
#include <linux/config.h>
#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/initrd.h>
+#include <linux/bitops.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/lmb.h>
#include <asm/system.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/naca.h>
#include <asm/pci.h>
#include <asm/iommu.h>
#include <asm/bootinfo.h>
#include <asm/btext.h>
#include <asm/sections.h>
#include <asm/machdep.h>
-#include "open_pic.h"
-#ifdef CONFIG_LOGO_LINUX_CLUT224
-#include <linux/linux_logo.h>
-extern const struct linux_logo logo_linux_clut224;
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
#endif
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree. This value does need to be big enough to
- * ensure that we don't lose things like the interrupt-map property
- * on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024)
-
-/*
- * prom_init() is called very early on, before the kernel text
- * and data have been mapped to KERNELBASE. At this point the code
- * is running at whatever address it has been loaded at, so
- * references to extern and static variables must be relocated
- * explicitly. The procedure reloc_offset() returns the address
- * we're currently running at minus the address we were linked at.
- * (Note that strings count as static variables.)
- *
- * Because OF may have mapped I/O devices into the area starting at
- * KERNELBASE, particularly on CHRP machines, we can't safely call
- * OF once the kernel has been mapped to KERNELBASE. Therefore all
- * OF calls should be done within prom_init(), and prom_init()
- * and all routines called within it must be careful to relocate
- * references as necessary.
- *
- * Note that the bss is cleared *after* prom_init runs, so we have
- * to make sure that any static or extern variables it accesses
- * are put in the data segment.
- */
-
-
-#define PROM_BUG() do { \
- prom_print(RELOC("kernel BUG at ")); \
- prom_print(RELOC(__FILE__)); \
- prom_print(RELOC(":")); \
- prom_print_hex(__LINE__); \
- prom_print(RELOC("!\n")); \
- __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
-} while (0)
-
-
-
struct pci_reg_property {
struct pci_address addr;
u32 size_hi;
u32 size_lo;
};
-
struct isa_reg_property {
u32 space;
u32 address;
u32 size;
};
-struct pci_intr_map {
- struct pci_address addr;
- u32 dunno;
- phandle int_ctrler;
- u32 intr;
-};
-
typedef unsigned long interpret_func(struct device_node *, unsigned long,
int, int, int);
-#ifndef FB_MAX /* avoid pulling in all of the fb stuff */
-#define FB_MAX 8
-#endif
-
-/* prom structure */
-struct prom_t prom;
-
-char *prom_display_paths[FB_MAX] __initdata = { 0, };
-phandle prom_display_nodes[FB_MAX] __initdata;
-unsigned int prom_num_displays = 0;
-char *of_stdout_device = 0;
-
-static int iommu_force_on;
-int ppc64_iommu_off;
-
extern struct rtas_t rtas;
-extern unsigned long klimit;
extern struct lmb lmb;
+extern unsigned long klimit;
-#define MAX_PHB (32 * 6) /* 32 drawers * 6 PHBs/drawer */
-struct of_tce_table of_tce_table[MAX_PHB + 1];
-
-char *bootpath = 0;
-char *bootdevice = 0;
-
-int boot_cpuid = 0;
-#define MAX_CPU_THREADS 2
-
-struct device_node *allnodes = 0;
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static rwlock_t devtree_lock = RW_LOCK_UNLOCKED;
-
-extern unsigned long reloc_offset(void);
-
-extern void enter_prom(struct prom_args *args);
-extern void copy_and_flush(unsigned long dest, unsigned long src,
- unsigned long size, unsigned long offset);
-
-unsigned long dev_tree_size;
-unsigned long _get_PIR(void);
-
-#ifdef CONFIG_HMT
-struct {
- unsigned int pir;
- unsigned int threadid;
-} hmt_thread_data[NR_CPUS];
-#endif /* CONFIG_HMT */
-
-char testString[] = "LINUX\n";
-
-
-/* This is the one and *ONLY* place where we actually call open
- * firmware from, since we need to make sure we're running in 32b
- * mode when we do. We switch back to 64b mode upon return.
- */
-
-#define PROM_ERROR (0x00000000fffffffful)
-
-static unsigned long __init call_prom(const char *service, int nargs, int nret, ...)
-{
- int i;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- va_list list;
-
- _prom->args.service = (u32)LONG_LSW(service);
- _prom->args.nargs = nargs;
- _prom->args.nret = nret;
- _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);
-
- va_start(list, nret);
- for (i=0; i < nargs ;i++)
- _prom->args.args[i] = (prom_arg_t)LONG_LSW(va_arg(list, unsigned long));
- va_end(list);
-
- for (i=0; i < nret ;i++)
- _prom->args.rets[i] = 0;
-
- enter_prom(&_prom->args);
-
- return (unsigned long)((nret > 0) ? _prom->args.rets[0] : 0);
-}
-
-
-static void __init prom_print(const char *msg)
-{
- const char *p, *q;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- if (_prom->stdout == 0)
- return;
-
- for (p = msg; *p != 0; p = q) {
- for (q = p; *q != 0 && *q != '\n'; ++q)
- ;
- if (q > p)
- call_prom(RELOC("write"), 3, 1, _prom->stdout,
- p, q - p);
- if (*q != 0) {
- ++q;
- call_prom(RELOC("write"), 3, 1, _prom->stdout,
- RELOC("\r\n"), 2);
- }
- }
-}
-
-
-static void __init prom_print_hex(unsigned long val)
-{
- int i, nibbles = sizeof(val)*2;
- char buf[sizeof(val)*2+1];
-
- for (i = nibbles-1; i >= 0; i--) {
- buf[i] = (val & 0xf) + '0';
- if (buf[i] > '9')
- buf[i] += ('a'-'0'-10);
- val >>= 4;
- }
- buf[nibbles] = '\0';
- prom_print(buf);
-}
-
-
-static void __init prom_print_nl(void)
-{
- unsigned long offset = reloc_offset();
- prom_print(RELOC("\n"));
-}
-
-
-static void __init prom_panic(const char *reason)
-{
- unsigned long offset = reloc_offset();
-
- prom_print(reason);
- /* ToDo: should put up an SRC here */
- call_prom(RELOC("exit"), 0, 0);
-
- for (;;) /* should never get here */
- ;
-}
-
-
-static int __init prom_next_node(phandle *nodep)
-{
- phandle node;
- unsigned long offset = reloc_offset();
-
- if ((node = *nodep) != 0
- && (*nodep = call_prom(RELOC("child"), 1, 1, node)) != 0)
- return 1;
- if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
- return 1;
- for (;;) {
- if ((node = call_prom(RELOC("parent"), 1, 1, node)) == 0)
- return 0;
- if ((*nodep = call_prom(RELOC("peer"), 1, 1, node)) != 0)
- return 1;
- }
-}
-
-
-static void __init prom_initialize_naca(void)
-{
- phandle node;
- char type[64];
- unsigned long num_cpus = 0;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- struct naca_struct *_naca = RELOC(naca);
- struct systemcfg *_systemcfg = RELOC(systemcfg);
-
- /* NOTE: _naca->debug_switch is already initialized. */
-#ifdef DEBUG_PROM
- prom_print(RELOC("prom_initialize_naca: start...\n"));
-#endif
-
- _naca->pftSize = 0; /* ilog2 of htab size. computed below. */
-
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
-
- if (!strcmp(type, RELOC("cpu"))) {
- num_cpus += 1;
-
- /* We're assuming *all* of the CPUs have the same
- * d-cache and i-cache sizes... -Peter
- */
- if ( num_cpus == 1 ) {
- u32 size, lsize;
-
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("d-cache-size"),
- &size, sizeof(size));
-
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("d-cache-block-size"),
- &lsize, sizeof(lsize));
- else
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("d-cache-line-size"),
- &lsize, sizeof(lsize));
-
- _systemcfg->dCacheL1Size = size;
- _systemcfg->dCacheL1LineSize = lsize;
- _naca->dCacheL1LogLineSize = __ilog2(lsize);
- _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
-
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("i-cache-size"),
- &size, sizeof(size));
-
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("i-cache-block-size"),
- &lsize, sizeof(lsize));
- else
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("i-cache-line-size"),
- &lsize, sizeof(lsize));
-
- _systemcfg->iCacheL1Size = size;
- _systemcfg->iCacheL1LineSize = lsize;
- _naca->iCacheL1LogLineSize = __ilog2(lsize);
- _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
-
- if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
- u32 pft_size[2];
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("ibm,pft-size"),
- &pft_size, sizeof(pft_size));
- /* pft_size[0] is the NUMA CEC cookie */
- _naca->pftSize = pft_size[1];
- }
- }
- } else if (!strcmp(type, RELOC("serial"))) {
- phandle isa, pci;
- struct isa_reg_property reg;
- union pci_range ranges;
-
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- continue;
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("ibm,aix-loc"), type, sizeof(type));
-
- if (strcmp(type, RELOC("S1")))
- continue;
-
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
- ®, sizeof(reg));
-
- isa = call_prom(RELOC("parent"), 1, 1, node);
- if (!isa)
- PROM_BUG();
- pci = call_prom(RELOC("parent"), 1, 1, isa);
- if (!pci)
- PROM_BUG();
-
- call_prom(RELOC("getprop"), 4, 1, pci, RELOC("ranges"),
- &ranges, sizeof(ranges));
-
- if ( _prom->encode_phys_size == 32 )
- _naca->serialPortAddr = ranges.pci32.phys+reg.address;
- else {
- _naca->serialPortAddr =
- ((((unsigned long)ranges.pci64.phys_hi) << 32) |
- (ranges.pci64.phys_lo)) + reg.address;
- }
- }
- }
-
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- _naca->interrupt_controller = IC_OPEN_PIC;
- else {
- _naca->interrupt_controller = IC_INVALID;
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
- type, sizeof(type));
- if (strcmp(type, RELOC("interrupt-controller")))
- continue;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
- type, sizeof(type));
- if (strstr(type, RELOC("open-pic")))
- _naca->interrupt_controller = IC_OPEN_PIC;
- else if (strstr(type, RELOC("ppc-xicp")))
- _naca->interrupt_controller = IC_PPC_XIC;
- else
- prom_print(RELOC("prom: failed to recognize"
- " interrupt-controller\n"));
- break;
- }
- }
-
- if (_naca->interrupt_controller == IC_INVALID) {
- prom_print(RELOC("prom: failed to find interrupt-controller\n"));
- PROM_BUG();
- }
-
- /* We gotta have at least 1 cpu... */
- if ( (_systemcfg->processorCount = num_cpus) < 1 )
- PROM_BUG();
-
- _systemcfg->physicalMemorySize = lmb_phys_mem_size();
-
- if (_systemcfg->platform == PLATFORM_PSERIES ||
- _systemcfg->platform == PLATFORM_POWERMAC) {
- unsigned long rnd_mem_size, pteg_count;
-
- /* round mem_size up to next power of 2 */
- rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
- if (rnd_mem_size < _systemcfg->physicalMemorySize)
- rnd_mem_size <<= 1;
-
- /* # pages / 2 */
- pteg_count = (rnd_mem_size >> (12 + 1));
-
- _naca->pftSize = __ilog2(pteg_count << 7);
- }
-
- if (_naca->pftSize == 0) {
- prom_print(RELOC("prom: failed to compute pftSize!\n"));
- PROM_BUG();
- }
-
- /* Add an eye catcher and the systemcfg layout version number */
- strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
- _systemcfg->version.major = SYSTEMCFG_MAJOR;
- _systemcfg->version.minor = SYSTEMCFG_MINOR;
- _systemcfg->processor = _get_PVR();
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("systemcfg->processorCount = 0x"));
- prom_print_hex(_systemcfg->processorCount);
- prom_print_nl();
-
- prom_print(RELOC("systemcfg->physicalMemorySize = 0x"));
- prom_print_hex(_systemcfg->physicalMemorySize);
- prom_print_nl();
-
- prom_print(RELOC("naca->pftSize = 0x"));
- prom_print_hex(_naca->pftSize);
- prom_print_nl();
-
- prom_print(RELOC("systemcfg->dCacheL1LineSize = 0x"));
- prom_print_hex(_systemcfg->dCacheL1LineSize);
- prom_print_nl();
-
- prom_print(RELOC("systemcfg->iCacheL1LineSize = 0x"));
- prom_print_hex(_systemcfg->iCacheL1LineSize);
- prom_print_nl();
-
- prom_print(RELOC("naca->serialPortAddr = 0x"));
- prom_print_hex(_naca->serialPortAddr);
- prom_print_nl();
-
- prom_print(RELOC("naca->interrupt_controller = 0x"));
- prom_print_hex(_naca->interrupt_controller);
- prom_print_nl();
-
- prom_print(RELOC("systemcfg->platform = 0x"));
- prom_print_hex(_systemcfg->platform);
- prom_print_nl();
-
- prom_print(RELOC("prom_initialize_naca: end...\n"));
-#endif
-}
-
-
-static void __init early_cmdline_parse(void)
-{
- unsigned long offset = reloc_offset();
- char *opt;
-#ifndef CONFIG_PMAC_DART
- struct systemcfg *_systemcfg = RELOC(systemcfg);
-#endif
-
- opt = strstr(RELOC(cmd_line), RELOC("iommu="));
- if (opt) {
- prom_print(RELOC("opt is:"));
- prom_print(opt);
- prom_print(RELOC("\n"));
- opt += 6;
- while (*opt && *opt == ' ')
- opt++;
- if (!strncmp(opt, RELOC("off"), 3))
- RELOC(ppc64_iommu_off) = 1;
- else if (!strncmp(opt, RELOC("force"), 5))
- RELOC(iommu_force_on) = 1;
- }
-
-#ifndef CONFIG_PMAC_DART
- if (_systemcfg->platform == PLATFORM_POWERMAC) {
- RELOC(ppc64_iommu_off) = 1;
- prom_print(RELOC("DART disabled on PowerMac !\n"));
- }
-#endif
-}
-
-#ifdef DEBUG_PROM
-void prom_dump_lmb(void)
-{
- unsigned long i;
- unsigned long offset = reloc_offset();
- struct lmb *_lmb = PTRRELOC(&lmb);
-
- prom_print(RELOC("\nprom_dump_lmb:\n"));
- prom_print(RELOC(" memory.cnt = 0x"));
- prom_print_hex(_lmb->memory.cnt);
- prom_print_nl();
- prom_print(RELOC(" memory.size = 0x"));
- prom_print_hex(_lmb->memory.size);
- prom_print_nl();
- for (i=0; i < _lmb->memory.cnt ;i++) {
- prom_print(RELOC(" memory.region[0x"));
- prom_print_hex(i);
- prom_print(RELOC("].base = 0x"));
- prom_print_hex(_lmb->memory.region[i].base);
- prom_print_nl();
- prom_print(RELOC(" .physbase = 0x"));
- prom_print_hex(_lmb->memory.region[i].physbase);
- prom_print_nl();
- prom_print(RELOC(" .size = 0x"));
- prom_print_hex(_lmb->memory.region[i].size);
- prom_print_nl();
- }
-
- prom_print_nl();
- prom_print(RELOC(" reserved.cnt = 0x"));
- prom_print_hex(_lmb->reserved.cnt);
- prom_print_nl();
- prom_print(RELOC(" reserved.size = 0x"));
- prom_print_hex(_lmb->reserved.size);
- prom_print_nl();
- for (i=0; i < _lmb->reserved.cnt ;i++) {
- prom_print(RELOC(" reserved.region[0x"));
- prom_print_hex(i);
- prom_print(RELOC("].base = 0x"));
- prom_print_hex(_lmb->reserved.region[i].base);
- prom_print_nl();
- prom_print(RELOC(" .physbase = 0x"));
- prom_print_hex(_lmb->reserved.region[i].physbase);
- prom_print_nl();
- prom_print(RELOC(" .size = 0x"));
- prom_print_hex(_lmb->reserved.region[i].size);
- prom_print_nl();
- }
-}
-#endif /* DEBUG_PROM */
-
-static void __init prom_initialize_lmb(void)
-{
- phandle node;
- char type[64];
- unsigned long i, offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- struct systemcfg *_systemcfg = RELOC(systemcfg);
- union lmb_reg_property reg;
- unsigned long lmb_base, lmb_size;
- unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
-
- lmb_init();
-
- /* XXX Quick HACK. Proper fix is to drop those structures and properly use
- * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2
- */
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- bytes_per_reg = 12;
-
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
-
- if (strcmp(type, RELOC("memory")))
- continue;
-
- num_regs = call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
- ®, sizeof(reg)) / bytes_per_reg;
-
- for (i=0; i < num_regs ;i++) {
- if (_systemcfg->platform == PLATFORM_POWERMAC) {
- lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32;
- lmb_base |= (unsigned long)reg.addrPM[i].address_lo;
- lmb_size = reg.addrPM[i].size;
- } else if (_prom->encode_phys_size == 32) {
- lmb_base = reg.addr32[i].address;
- lmb_size = reg.addr32[i].size;
- } else {
- lmb_base = reg.addr64[i].address;
- lmb_size = reg.addr64[i].size;
- }
-
- /* We limit memory to 2GB if the IOMMU is off */
- if (RELOC(ppc64_iommu_off)) {
- if (lmb_base >= 0x80000000UL)
- continue;
-
- if ((lmb_base + lmb_size) > 0x80000000UL)
- lmb_size = 0x80000000UL - lmb_base;
- }
-
- if (lmb_add(lmb_base, lmb_size) < 0)
- prom_print(RELOC("Too many LMB's, discarding this one...\n"));
- }
-
- }
-
- lmb_analyze();
-#ifdef DEBUG_PROM
- prom_dump_lmb();
-#endif /* DEBUG_PROM */
-}
-
-static void __init
-prom_instantiate_rtas(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- struct rtas_t *_rtas = PTRRELOC(&rtas);
- struct systemcfg *_systemcfg = RELOC(systemcfg);
- ihandle prom_rtas;
- u32 getprop_rval;
- char hypertas_funcs[4];
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("prom_instantiate_rtas: start...\n"));
-#endif
- prom_rtas = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
- if (prom_rtas != (ihandle) -1) {
- unsigned long x;
- x = call_prom(RELOC("getprop"),
- 4, 1, prom_rtas,
- RELOC("ibm,hypertas-functions"),
- hypertas_funcs,
- sizeof(hypertas_funcs));
-
- if (x != PROM_ERROR) {
- prom_print(RELOC("Hypertas detected, assuming LPAR !\n"));
- _systemcfg->platform = PLATFORM_PSERIES_LPAR;
- }
-
- call_prom(RELOC("getprop"),
- 4, 1, prom_rtas,
- RELOC("rtas-size"),
- &getprop_rval,
- sizeof(getprop_rval));
- _rtas->size = getprop_rval;
- prom_print(RELOC("instantiating rtas"));
- if (_rtas->size != 0) {
- unsigned long rtas_region = RTAS_INSTANTIATE_MAX;
-
- /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes
- * of physical memory (or within the RMO region) because RTAS
- * runs in 32-bit mode and relocate off.
- */
- if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
- struct lmb *_lmb = PTRRELOC(&lmb);
- rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
- }
-
- _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region);
-
- prom_print(RELOC(" at 0x"));
- prom_print_hex(_rtas->base);
-
- prom_rtas = (ihandle)call_prom(RELOC("open"),
- 1, 1, RELOC("/rtas"));
- prom_print(RELOC("..."));
-
- if (call_prom(RELOC("call-method"), 3, 2,
- RELOC("instantiate-rtas"),
- prom_rtas,
- _rtas->base) != PROM_ERROR) {
- _rtas->entry = (long)_prom->args.rets[1];
- }
- RELOC(rtas_rmo_buf)
- = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE,
- rtas_region);
- }
-
- if (_rtas->entry <= 0) {
- prom_print(RELOC(" failed\n"));
- } else {
- prom_print(RELOC(" done\n"));
- }
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("rtas->base = 0x"));
- prom_print_hex(_rtas->base);
- prom_print_nl();
- prom_print(RELOC("rtas->entry = 0x"));
- prom_print_hex(_rtas->entry);
- prom_print_nl();
- prom_print(RELOC("rtas->size = 0x"));
- prom_print_hex(_rtas->size);
- prom_print_nl();
-#endif
- }
-#ifdef DEBUG_PROM
- prom_print(RELOC("prom_instantiate_rtas: end...\n"));
-#endif
-}
-
-
-#ifdef CONFIG_PMAC_DART
-static void __init prom_initialize_dart_table(void)
-{
- unsigned long offset = reloc_offset();
- extern unsigned long dart_tablebase;
- extern unsigned long dart_tablesize;
-
- /* Only reserve DART space if machine has more than 2GB of RAM
- * or if requested with iommu=on on cmdline.
- */
- if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on))
- return;
-
- /* 512 pages (2MB) is max DART tablesize. */
- RELOC(dart_tablesize) = 1UL << 21;
- /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we
- * will blow up an entire large page anyway in the kernel mapping
- */
- RELOC(dart_tablebase) = (unsigned long)
- abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
-
- prom_print(RELOC("Dart at: "));
- prom_print_hex(RELOC(dart_tablebase));
- prom_print(RELOC("\n"));
-}
-#endif /* CONFIG_PMAC_DART */
-
-static void __init prom_initialize_tce_table(void)
-{
- phandle node;
- ihandle phb_node;
- unsigned long offset = reloc_offset();
- char compatible[64], path[64], type[64], model[64];
- unsigned long i, table = 0;
- unsigned long base, vbase, align;
- unsigned int minalign, minsize;
- struct of_tce_table *prom_tce_table = RELOC(of_tce_table);
- unsigned long tce_entry, *tce_entryp;
-
- if (RELOC(ppc64_iommu_off))
- return;
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("starting prom_initialize_tce_table\n"));
-#endif
-
- /* Search all nodes looking for PHBs. */
- for (node = 0; prom_next_node(&node); ) {
- if (table == MAX_PHB) {
- prom_print(RELOC("WARNING: PCI host bridge ignored, "
- "need to increase MAX_PHB\n"));
- continue;
- }
-
- compatible[0] = 0;
- type[0] = 0;
- model[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
- compatible, sizeof(compatible));
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("model"),
- model, sizeof(model));
-
- /* Keep the old logic in tack to avoid regression. */
- if (compatible[0] != 0) {
- if((strstr(compatible, RELOC("python")) == NULL) &&
- (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
- (strstr(compatible, RELOC("Winnipeg")) == NULL))
- continue;
- } else if (model[0] != 0) {
- if ((strstr(model, RELOC("ython")) == NULL) &&
- (strstr(model, RELOC("peedwagon")) == NULL) &&
- (strstr(model, RELOC("innipeg")) == NULL))
- continue;
- }
-
- if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) {
- continue;
- }
-
- if (call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("tce-table-minalign"), &minalign,
- sizeof(minalign)) == PROM_ERROR) {
- minalign = 0;
- }
-
- if (call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("tce-table-minsize"), &minsize,
- sizeof(minsize)) == PROM_ERROR) {
- minsize = 4UL << 20;
- }
-
- /*
- * Even though we read what OF wants, we just set the table
- * size to 4 MB. This is enough to map 2GB of PCI DMA space.
- * By doing this, we avoid the pitfalls of trying to DMA to
- * MMIO space and the DMA alias hole.
- *
- * On POWER4, firmware sets the TCE region by assuming
- * each TCE table is 8MB. Using this memory for anything
- * else will impact performance, so we always allocate 8MB.
- * Anton
- */
- if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
- minsize = 8UL << 20;
- else
- minsize = 4UL << 20;
-
- /* Align to the greater of the align or size */
- align = max(minalign, minsize);
-
- /* Carve out storage for the TCE table. */
- base = lmb_alloc(minsize, align);
-
- if ( !base ) {
- prom_panic(RELOC("ERROR, cannot find space for TCE table.\n"));
- }
-
- vbase = (unsigned long)abs_to_virt(base);
-
- /* Save away the TCE table attributes for later use. */
- prom_tce_table[table].node = node;
- prom_tce_table[table].base = vbase;
- prom_tce_table[table].size = minsize;
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("TCE table: 0x"));
- prom_print_hex(table);
- prom_print_nl();
-
- prom_print(RELOC("\tnode = 0x"));
- prom_print_hex(node);
- prom_print_nl();
-
- prom_print(RELOC("\tbase = 0x"));
- prom_print_hex(vbase);
- prom_print_nl();
-
- prom_print(RELOC("\tsize = 0x"));
- prom_print_hex(minsize);
- prom_print_nl();
-#endif
-
- /* Initialize the table to have a one-to-one mapping
- * over the allocated size.
- */
- tce_entryp = (unsigned long *)base;
- for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
- tce_entry = (i << PAGE_SHIFT);
- tce_entry |= 0x3;
- *tce_entryp = tce_entry;
- }
-
- /* It seems OF doesn't null-terminate the path :-( */
- memset(path, 0, sizeof(path));
- /* Call OF to setup the TCE hardware */
- if (call_prom(RELOC("package-to-path"), 3, 1, node,
- path, sizeof(path)-1) == PROM_ERROR) {
- prom_print(RELOC("package-to-path failed\n"));
- } else {
- prom_print(RELOC("opening PHB "));
- prom_print(path);
- }
-
- phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path);
- if ( (long)phb_node <= 0) {
- prom_print(RELOC("... failed\n"));
- } else {
- prom_print(RELOC("... done\n"));
- }
- call_prom(RELOC("call-method"), 6, 0,
- RELOC("set-64-bit-addressing"),
- phb_node,
- -1,
- minsize,
- base & 0xffffffff,
- (base >> 32) & 0xffffffff);
- call_prom(RELOC("close"), 1, 0, phb_node);
-
- table++;
- }
-
- /* Flag the first invalid entry */
- prom_tce_table[table].node = 0;
-#ifdef DEBUG_PROM
- prom_print(RELOC("ending prom_initialize_tce_table\n"));
-#endif
-}
-
-/*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of low memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something. The holding pattern
- * checks that address until its cpu # is there, when it is that
- * cpu jumps to __secondary_start(). smp_boot_cpus() takes care
- * of setting those values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * Fixup comment... DRENG / PPPBBB - Peter
- *
- * -- Cort
- */
-static void __init prom_hold_cpus(unsigned long mem)
-{
- unsigned long i;
- unsigned int reg;
- phandle node;
- unsigned long offset = reloc_offset();
- char type[64], *path;
- int cpuid = 0;
- unsigned int interrupt_server[MAX_CPU_THREADS];
- unsigned int cpu_threads, hw_cpu_num;
- int propsize;
- extern void __secondary_hold(void);
- extern unsigned long __secondary_hold_spinloop;
- extern unsigned long __secondary_hold_acknowledge;
- unsigned long *spinloop
- = (void *)virt_to_abs(&__secondary_hold_spinloop);
- unsigned long *acknowledge
- = (void *)virt_to_abs(&__secondary_hold_acknowledge);
- unsigned long secondary_hold
- = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold));
- struct systemcfg *_systemcfg = RELOC(systemcfg);
- struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
- struct prom_t *_prom = PTRRELOC(&prom);
-#ifdef CONFIG_SMP
- struct naca_struct *_naca = RELOC(naca);
-#endif
-
- /* On pmac, we just fill out the various global bitmasks and
- * arrays indicating our CPUs are here, they are actually started
- * later on from pmac_smp
- */
- if (_systemcfg->platform == PLATFORM_POWERMAC) {
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
- if (strcmp(type, RELOC("cpu")) != 0)
- continue;
- reg = -1;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
- ®, sizeof(reg));
- _xPaca[cpuid].xHwProcNum = reg;
-
-#ifdef CONFIG_SMP
- cpu_set(cpuid, RELOC(cpu_available_map));
- cpu_set(cpuid, RELOC(cpu_possible_map));
- cpu_set(cpuid, RELOC(cpu_present_at_boot));
- if (reg == 0)
- cpu_set(cpuid, RELOC(cpu_online_map));
-#endif /* CONFIG_SMP */
- cpuid++;
- }
- return;
- }
-
- /* Initially, we must have one active CPU. */
- _systemcfg->processorCount = 1;
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("prom_hold_cpus: start...\n"));
- prom_print(RELOC(" 1) spinloop = 0x"));
- prom_print_hex((unsigned long)spinloop);
- prom_print_nl();
- prom_print(RELOC(" 1) *spinloop = 0x"));
- prom_print_hex(*spinloop);
- prom_print_nl();
- prom_print(RELOC(" 1) acknowledge = 0x"));
- prom_print_hex((unsigned long)acknowledge);
- prom_print_nl();
- prom_print(RELOC(" 1) *acknowledge = 0x"));
- prom_print_hex(*acknowledge);
- prom_print_nl();
- prom_print(RELOC(" 1) secondary_hold = 0x"));
- prom_print_hex(secondary_hold);
- prom_print_nl();
-#endif
-
- /* Set the common spinloop variable, so all of the secondary cpus
- * will block when they are awakened from their OF spinloop.
- * This must occur for both SMP and non SMP kernels, since OF will
- * be trashed when we move the kernel.
- */
- *spinloop = 0;
-
-#ifdef CONFIG_HMT
- for (i=0; i < NR_CPUS; i++) {
- RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
- }
-#endif
- /* look for cpus */
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
- if (strcmp(type, RELOC("cpu")) != 0)
- continue;
-
- /* Skip non-configured cpus. */
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("status"),
- type, sizeof(type));
- if (strcmp(type, RELOC("okay")) != 0)
- continue;
-
- reg = -1;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
- ®, sizeof(reg));
-
- path = (char *) mem;
- memset(path, 0, 256);
- if ((long) call_prom(RELOC("package-to-path"), 3, 1,
- node, path, 255) == PROM_ERROR)
- continue;
-
-#ifdef DEBUG_PROM
- prom_print_nl();
- prom_print(RELOC("cpuid = 0x"));
- prom_print_hex(cpuid);
- prom_print_nl();
- prom_print(RELOC("cpu hw idx = 0x"));
- prom_print_hex(reg);
- prom_print_nl();
-#endif
- _xPaca[cpuid].xHwProcNum = reg;
-
- /* Init the acknowledge var which will be reset by
- * the secondary cpu when it awakens from its OF
- * spinloop.
- */
- *acknowledge = (unsigned long)-1;
-
- propsize = call_prom(RELOC("getprop"), 4, 1, node,
- RELOC("ibm,ppc-interrupt-server#s"),
- &interrupt_server,
- sizeof(interrupt_server));
- if (propsize < 0) {
- /* no property. old hardware has no SMT */
- cpu_threads = 1;
- interrupt_server[0] = reg; /* fake it with phys id */
- } else {
- /* We have a threaded processor */
- cpu_threads = propsize / sizeof(u32);
- if (cpu_threads > MAX_CPU_THREADS) {
- prom_print(RELOC("SMT: too many threads!\nSMT: found "));
- prom_print_hex(cpu_threads);
- prom_print(RELOC(", max is "));
- prom_print_hex(MAX_CPU_THREADS);
- prom_print_nl();
- cpu_threads = 1; /* ToDo: panic? */
- }
- }
-
- hw_cpu_num = interrupt_server[0];
- if (hw_cpu_num != _prom->cpu) {
- /* Primary Thread of non-boot cpu */
- prom_print_hex(cpuid);
- prom_print(RELOC(" : starting cpu "));
- prom_print(path);
- prom_print(RELOC("... "));
- call_prom(RELOC("start-cpu"), 3, 0, node,
- secondary_hold, cpuid);
-
- for ( i = 0 ; (i < 100000000) &&
- (*acknowledge == ((unsigned long)-1)); i++ ) ;
-
- if (*acknowledge == cpuid) {
- prom_print(RELOC("... done\n"));
- /* We have to get every CPU out of OF,
- * even if we never start it. */
- if (cpuid >= NR_CPUS)
- goto next;
-#ifdef CONFIG_SMP
- /* Set the number of active processors. */
- _systemcfg->processorCount++;
- cpu_set(cpuid, RELOC(cpu_available_map));
- cpu_set(cpuid, RELOC(cpu_possible_map));
- cpu_set(cpuid, RELOC(cpu_present_at_boot));
-#endif
- } else {
- prom_print(RELOC("... failed: "));
- prom_print_hex(*acknowledge);
- prom_print_nl();
- }
- }
-#ifdef CONFIG_SMP
- else {
- prom_print_hex(cpuid);
- prom_print(RELOC(" : booting cpu "));
- prom_print(path);
- prom_print_nl();
- cpu_set(cpuid, RELOC(cpu_available_map));
- cpu_set(cpuid, RELOC(cpu_possible_map));
- cpu_set(cpuid, RELOC(cpu_online_map));
- cpu_set(cpuid, RELOC(cpu_present_at_boot));
- }
-#endif
-next:
-#ifdef CONFIG_SMP
- /* Init paca for secondary threads. They start later. */
- for (i=1; i < cpu_threads; i++) {
- cpuid++;
- if (cpuid >= NR_CPUS)
- continue;
- _xPaca[cpuid].xHwProcNum = interrupt_server[i];
- prom_print_hex(interrupt_server[i]);
- prom_print(RELOC(" : preparing thread ... "));
- if (_naca->smt_state) {
- cpu_set(cpuid, RELOC(cpu_available_map));
- cpu_set(cpuid, RELOC(cpu_present_at_boot));
- prom_print(RELOC("available"));
- } else {
- prom_print(RELOC("not available"));
- }
- prom_print_nl();
- }
-#endif
- cpuid++;
- }
-#ifdef CONFIG_HMT
- /* Only enable HMT on processors that provide support. */
- if (__is_processor(PV_PULSAR) ||
- __is_processor(PV_ICESTAR) ||
- __is_processor(PV_SSTAR)) {
- prom_print(RELOC(" starting secondary threads\n"));
-
- for (i = 0; i < NR_CPUS; i += 2) {
- if (!cpu_online(i))
- continue;
-
- if (i == 0) {
- unsigned long pir = _get_PIR();
- if (__is_processor(PV_PULSAR)) {
- RELOC(hmt_thread_data)[i].pir =
- pir & 0x1f;
- } else {
- RELOC(hmt_thread_data)[i].pir =
- pir & 0x3ff;
- }
- }
-/* cpu_set(i+1, cpu_online_map); */
- cpu_set(i+1, RELOC(cpu_possible_map));
- }
- _systemcfg->processorCount *= 2;
- } else {
- prom_print(RELOC("Processor is not HMT capable\n"));
- }
-#endif
-
- if (cpuid >= NR_CPUS)
- prom_print(RELOC("WARNING: maximum CPUs (" __stringify(NR_CPUS)
- ") exceeded: ignoring extras\n"));
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("prom_hold_cpus: end...\n"));
-#endif
-}
-
-static void __init smt_setup(void)
-{
- char *p, *q;
- char my_smt_enabled = SMT_DYNAMIC;
- ihandle prom_options = NULL;
- char option[9];
- unsigned long offset = reloc_offset();
- struct naca_struct *_naca = RELOC(naca);
- char found = 0;
-
- if (strstr(RELOC(cmd_line), RELOC("smt-enabled="))) {
- for (q = RELOC(cmd_line); (p = strstr(q, RELOC("smt-enabled="))) != 0; ) {
- q = p + 12;
- if (p > RELOC(cmd_line) && p[-1] != ' ')
- continue;
- found = 1;
- if (q[0] == 'o' && q[1] == 'f' &&
- q[2] == 'f' && (q[3] == ' ' || q[3] == '\0')) {
- my_smt_enabled = SMT_OFF;
- } else if (q[0]=='o' && q[1] == 'n' &&
- (q[2] == ' ' || q[2] == '\0')) {
- my_smt_enabled = SMT_ON;
- } else {
- my_smt_enabled = SMT_DYNAMIC;
- }
- }
- }
- if (!found) {
- prom_options = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/options"));
- if (prom_options != (ihandle) -1) {
- call_prom(RELOC("getprop"),
- 4, 1, prom_options,
- RELOC("ibm,smt-enabled"),
- option,
- sizeof(option));
- if (option[0] != 0) {
- found = 1;
- if (!strcmp(option, RELOC("off")))
- my_smt_enabled = SMT_OFF;
- else if (!strcmp(option, RELOC("on")))
- my_smt_enabled = SMT_ON;
- else
- my_smt_enabled = SMT_DYNAMIC;
- }
- }
- }
-
- if (!found )
- my_smt_enabled = SMT_DYNAMIC; /* default to on */
-
- _naca->smt_state = my_smt_enabled;
-}
-
-
-#ifdef CONFIG_BOOTX_TEXT
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-static void __init setup_disp_fake_bi(ihandle dp)
-{
- int width = 640, height = 480, depth = 8, pitch;
- unsigned address;
- struct pci_reg_property addrs[8];
- int i, naddrs;
- char name[64];
- unsigned long offset = reloc_offset();
- char *getprop = RELOC("getprop");
-
- prom_print(RELOC("Initializing fake screen: "));
-
- memset(name, 0, sizeof(name));
- call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name));
- name[sizeof(name)-1] = 0;
- prom_print(name);
- prom_print(RELOC("\n"));
- call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width));
- call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height));
- call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth));
- pitch = width * ((depth + 7) / 8);
- call_prom(getprop, 4, 1, dp, RELOC("linebytes"),
- &pitch, sizeof(pitch));
- if (pitch == 1)
- pitch = 0x1000; /* for strange IBM display */
- address = 0;
-
- prom_print(RELOC("width "));
- prom_print_hex(width);
- prom_print(RELOC(" height "));
- prom_print_hex(height);
- prom_print(RELOC(" depth "));
- prom_print_hex(depth);
- prom_print(RELOC(" linebytes "));
- prom_print_hex(pitch);
- prom_print(RELOC("\n"));
-
-
- call_prom(getprop, 4, 1, dp, RELOC("address"),
- &address, sizeof(address));
- if (address == 0) {
- /* look for an assigned address with a size of >= 1MB */
- naddrs = (int) call_prom(getprop, 4, 1, dp,
- RELOC("assigned-addresses"),
- addrs, sizeof(addrs));
- naddrs /= sizeof(struct pci_reg_property);
- for (i = 0; i < naddrs; ++i) {
- if (addrs[i].size_lo >= (1 << 20)) {
- address = addrs[i].addr.a_lo;
- /* use the BE aperture if possible */
- if (addrs[i].size_lo >= (16 << 20))
- address += (8 << 20);
- break;
- }
- }
- if (address == 0) {
- prom_print(RELOC("Failed to get address of frame buffer\n"));
- return;
- }
- }
- btext_setup_display(width, height, depth, pitch, address);
- prom_print(RELOC("Addr of fb: "));
- prom_print_hex(address);
- prom_print_nl();
- RELOC(boot_text_mapped) = 0;
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-static void __init prom_init_client_services(unsigned long pp)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- /* Get a handle to the prom entry point before anything else */
- _prom->entry = pp;
-
- /* Init default value for phys size */
- _prom->encode_phys_size = 32;
-
- /* get a handle for the stdout device */
- _prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1,
- RELOC("/chosen"));
- if ((long)_prom->chosen <= 0)
- prom_panic(RELOC("cannot find chosen")); /* msg won't be printed :( */
-
- /* get device tree root */
- _prom->root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
- if ((long)_prom->root <= 0)
- prom_panic(RELOC("cannot find device tree root")); /* msg won't be printed :( */
-}
-
-static void __init prom_init_stdout(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- u32 val;
-
- if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
- RELOC("stdout"), &val,
- sizeof(val)) <= 0)
- prom_panic(RELOC("cannot find stdout"));
-
- _prom->stdout = (ihandle)(unsigned long)val;
-}
-
-static int __init prom_find_machine_type(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char compat[256];
- int len, i = 0;
-
- len = (int)(long)call_prom(RELOC("getprop"), 4, 1, _prom->root,
- RELOC("compatible"),
- compat, sizeof(compat)-1);
- if (len > 0) {
- compat[len] = 0;
- while (i < len) {
- char *p = &compat[i];
- int sl = strlen(p);
- if (sl == 0)
- break;
- if (strstr(p, RELOC("Power Macintosh")) ||
- strstr(p, RELOC("MacRISC4")))
- return PLATFORM_POWERMAC;
- i += sl + 1;
- }
- }
- /* Default to pSeries */
- return PLATFORM_PSERIES;
-}
-
-static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
-{
- unsigned long offset = reloc_offset();
-
- return (int)(long)call_prom(RELOC("call-method"), 6, 1,
- RELOC("color!"),
- ih,
- (void *)(long) i,
- (void *)(long) b,
- (void *)(long) g,
- (void *)(long) r );
-}
-
-/*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later. However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
-static unsigned long __init check_display(unsigned long mem)
-{
- phandle node;
- ihandle ih;
- int i, j;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char type[16], *path;
- static unsigned char default_colors[] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xaa,
- 0x00, 0xaa, 0x00,
- 0x00, 0xaa, 0xaa,
- 0xaa, 0x00, 0x00,
- 0xaa, 0x00, 0xaa,
- 0xaa, 0xaa, 0x00,
- 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55,
- 0x55, 0x55, 0xff,
- 0x55, 0xff, 0x55,
- 0x55, 0xff, 0xff,
- 0xff, 0x55, 0x55,
- 0xff, 0x55, 0xff,
- 0xff, 0xff, 0x55,
- 0xff, 0xff, 0xff
- };
- const unsigned char *clut;
-
- _prom->disp_node = 0;
-
- prom_print(RELOC("Looking for displays\n"));
- if (RELOC(of_stdout_device) != 0) {
- prom_print(RELOC("OF stdout is : "));
- prom_print(PTRRELOC(RELOC(of_stdout_device)));
- prom_print(RELOC("\n"));
- }
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
- type, sizeof(type));
- if (strcmp(type, RELOC("display")) != 0)
- continue;
- /* It seems OF doesn't null-terminate the path :-( */
- path = (char *) mem;
- memset(path, 0, 256);
-
- /*
- * leave some room at the end of the path for appending extra
- * arguments
- */
- if ((long) call_prom(RELOC("package-to-path"), 3, 1,
- node, path, 250) < 0)
- continue;
- prom_print(RELOC("found display : "));
- prom_print(path);
- prom_print(RELOC("\n"));
-
- /*
- * If this display is the device that OF is using for stdout,
- * move it to the front of the list.
- */
- mem += strlen(path) + 1;
- i = RELOC(prom_num_displays);
- RELOC(prom_num_displays) = i + 1;
- if (RELOC(of_stdout_device) != 0 && i > 0
- && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
- for (; i > 0; --i) {
- RELOC(prom_display_paths[i])
- = RELOC(prom_display_paths[i-1]);
- RELOC(prom_display_nodes[i])
- = RELOC(prom_display_nodes[i-1]);
- }
- _prom->disp_node = (ihandle)(unsigned long)node;
- }
- RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
- RELOC(prom_display_nodes[i]) = node;
- if (_prom->disp_node == 0)
- _prom->disp_node = (ihandle)(unsigned long)node;
- if (RELOC(prom_num_displays) >= FB_MAX)
- break;
- }
- prom_print(RELOC("Opening displays...\n"));
- for (j = RELOC(prom_num_displays) - 1; j >= 0; j--) {
- path = PTRRELOC(RELOC(prom_display_paths[j]));
- prom_print(RELOC("opening display : "));
- prom_print(path);
- ih = (ihandle)call_prom(RELOC("open"), 1, 1, path);
- if (ih == (ihandle)0 || ih == (ihandle)-1) {
- prom_print(RELOC("... failed\n"));
- continue;
- }
-
- prom_print(RELOC("... done\n"));
-
- /* Setup a useable color table when the appropriate
- * method is available. Should update this to set-colors */
- clut = RELOC(default_colors);
- for (i = 0; i < 32; i++, clut += 3)
- if (prom_set_color(ih, i, clut[0], clut[1],
- clut[2]) != 0)
- break;
-
-#ifdef CONFIG_LOGO_LINUX_CLUT224
- clut = PTRRELOC(RELOC(logo_linux_clut224.clut));
- for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3)
- if (prom_set_color(ih, i + 32, clut[0], clut[1],
- clut[2]) != 0)
- break;
-#endif /* CONFIG_LOGO_LINUX_CLUT224 */
- }
-
- return DOUBLEWORD_ALIGN(mem);
-}
-
-/* Return (relocated) pointer to this much memory: moves initrd if reqd. */
-static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end,
- unsigned long needed, unsigned long align)
-{
- void *ret;
- unsigned long offset = reloc_offset();
-
- *mem_start = ALIGN(*mem_start, align);
- if (*mem_start + needed > *mem_end) {
-#ifdef CONFIG_BLK_DEV_INITRD
- /* FIXME: Apple OF doesn't map unclaimed mem. If this
- * ever happened on G5, we'd need to fix. */
- unsigned long initrd_len;
-
- if (*mem_end != RELOC(initrd_start))
- prom_panic(RELOC("No memory for copy_device_tree"));
-
- prom_print(RELOC("Huge device_tree: moving initrd\n"));
- /* Move by 4M. */
- initrd_len = RELOC(initrd_end) - RELOC(initrd_start);
- *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024;
- memmove((void *)*mem_end, (void *)RELOC(initrd_start),
- initrd_len);
- RELOC(initrd_start) = *mem_end;
- RELOC(initrd_end) = RELOC(initrd_start) + initrd_len;
-#else
- prom_panic(RELOC("No memory for copy_device_tree"));
-#endif
- }
-
- ret = (void *)*mem_start;
- *mem_start += needed;
-
- return ret;
-}
-
-#define make_room(startp, endp, type) \
- __make_room(startp, endp, sizeof(type), __alignof__(type))
-
-static void __init
-inspect_node(phandle node, struct device_node *dad,
- unsigned long *mem_start, unsigned long *mem_end,
- struct device_node ***allnextpp)
-{
- int l;
- phandle child;
- struct device_node *np;
- struct property *pp, **prev_propp;
- char *prev_name, *namep;
- unsigned char *valp;
- unsigned long offset = reloc_offset();
- phandle ibm_phandle;
-
- np = make_room(mem_start, mem_end, struct device_node);
- memset(np, 0, sizeof(*np));
-
- np->node = node;
- **allnextpp = PTRUNRELOC(np);
- *allnextpp = &np->allnext;
- if (dad != 0) {
- np->parent = PTRUNRELOC(dad);
- /* we temporarily use the `next' field as `last_child'. */
- if (dad->next == 0)
- dad->child = PTRUNRELOC(np);
- else
- dad->next->sibling = PTRUNRELOC(np);
- dad->next = np;
- }
-
- /* get and store all properties */
- prev_propp = &np->properties;
- prev_name = RELOC("");
- for (;;) {
- /* 32 is max len of name including nul. */
- namep = make_room(mem_start, mem_end, char[32]);
- if ((long) call_prom(RELOC("nextprop"), 3, 1, node, prev_name,
- namep) <= 0) {
- /* No more nodes: unwind alloc */
- *mem_start = (unsigned long)namep;
- break;
- }
- /* Trim off some if we can */
- *mem_start = DOUBLEWORD_ALIGN((unsigned long)namep
- + strlen(namep) + 1);
- pp = make_room(mem_start, mem_end, struct property);
- pp->name = PTRUNRELOC(namep);
- prev_name = namep;
-
- pp->length = call_prom(RELOC("getproplen"), 2, 1, node, namep);
- if (pp->length < 0)
- continue;
- if (pp->length > MAX_PROPERTY_LENGTH) {
- char path[128];
-
- prom_print(RELOC("WARNING: ignoring large property "));
- /* It seems OF doesn't null-terminate the path :-( */
- memset(path, 0, sizeof(path));
- if (call_prom(RELOC("package-to-path"), 3, 1, node,
- path, sizeof(path)-1) > 0)
- prom_print(path);
- prom_print(namep);
- prom_print(RELOC(" length 0x"));
- prom_print_hex(pp->length);
- prom_print_nl();
-
- continue;
- }
- valp = __make_room(mem_start, mem_end, pp->length, 1);
- pp->value = PTRUNRELOC(valp);
- call_prom(RELOC("getprop"), 4, 1, node, namep,valp,pp->length);
- *prev_propp = PTRUNRELOC(pp);
- prev_propp = &pp->next;
- }
-
- /* Add a "linux,phandle" property. */
- namep = make_room(mem_start, mem_end, char[16]);
- strcpy(namep, RELOC("linux,phandle"));
- pp = make_room(mem_start, mem_end, struct property);
- pp->name = PTRUNRELOC(namep);
- pp->length = sizeof(phandle);
- valp = make_room(mem_start, mem_end, phandle);
- pp->value = PTRUNRELOC(valp);
- *(phandle *)valp = node;
- *prev_propp = PTRUNRELOC(pp);
- pp->next = NULL;
-
- /* Set np->linux_phandle to the value of the ibm,phandle property
- if it exists, otherwise to the phandle for this node. */
- np->linux_phandle = node;
- if ((int)call_prom(RELOC("getprop"), 4, 1, node, RELOC("ibm,phandle"),
- &ibm_phandle, sizeof(ibm_phandle)) > 0)
- np->linux_phandle = ibm_phandle;
-
- /* get the node's full name */
- namep = (char *)*mem_start;
- l = (long) call_prom(RELOC("package-to-path"), 3, 1, node,
- namep, *mem_end - *mem_start);
- if (l >= 0) {
- /* Didn't fit? Get more room. */
- if (l+1 > *mem_end - *mem_start) {
- namep = __make_room(mem_start, mem_end, l+1, 1);
- call_prom(RELOC("package-to-path"),3,1,node,namep,l);
- }
- np->full_name = PTRUNRELOC(namep);
- namep[l] = '\0';
- *mem_start = DOUBLEWORD_ALIGN(*mem_start + l + 1);
- }
-
- /* do all our children */
- child = call_prom(RELOC("child"), 1, 1, node);
- while (child != (phandle)0) {
- inspect_node(child, np, mem_start, mem_end,
- allnextpp);
- child = call_prom(RELOC("peer"), 1, 1, child);
- }
-}
-
-/*
- * Make a copy of the device tree from the PROM.
- */
-static unsigned long __init
-copy_device_tree(unsigned long mem_start)
-{
- phandle root;
- struct device_node **allnextp;
- unsigned long offset = reloc_offset();
- unsigned long mem_end;
-
- /* We pass mem_end-mem_start to OF: keep it well under 32-bit */
- mem_end = mem_start + 1024*1024*1024;
-#ifdef CONFIG_BLK_DEV_INITRD
- if (RELOC(initrd_start) && RELOC(initrd_start) > mem_start)
- mem_end = RELOC(initrd_start);
-#endif /* CONFIG_BLK_DEV_INITRD */
-
- root = call_prom(RELOC("peer"), 1, 1, (phandle)0);
- if (root == (phandle)0) {
- prom_panic(RELOC("couldn't get device tree root\n"));
- }
- allnextp = &RELOC(allnodes);
- inspect_node(root, 0, &mem_start, &mem_end, &allnextp);
- *allnextp = 0;
- return mem_start;
-}
-
-/* Verify bi_recs are good */
-static struct bi_record * __init prom_bi_rec_verify(struct bi_record *bi_recs)
-{
- struct bi_record *first, *last;
-#ifdef DEBUG_PROM
- unsigned long offset = reloc_offset();
-
- prom_print(RELOC("birec_verify: r6=0x"));
- prom_print_hex((unsigned long)bi_recs);
- prom_print_nl();
- if (bi_recs != NULL) {
- prom_print(RELOC(" tag=0x"));
- prom_print_hex(bi_recs->tag);
- prom_print_nl();
- }
-#endif /* DEBUG_PROM */
-
- if ( bi_recs == NULL || bi_recs->tag != BI_FIRST )
- return NULL;
-
- last = (struct bi_record *)(long)bi_recs->data[0];
-
-#ifdef DEBUG_PROM
- prom_print(RELOC(" last=0x"));
- prom_print_hex((unsigned long)last);
- prom_print_nl();
- if (last != NULL) {
- prom_print(RELOC(" last_tag=0x"));
- prom_print_hex(last->tag);
- prom_print_nl();
- }
-#endif /* DEBUG_PROM */
-
- if ( last == NULL || last->tag != BI_LAST )
- return NULL;
-
- first = (struct bi_record *)(long)last->data[0];
-#ifdef DEBUG_PROM
- prom_print(RELOC(" first=0x"));
- prom_print_hex((unsigned long)first);
- prom_print_nl();
-#endif /* DEBUG_PROM */
-
- if ( first == NULL || first != bi_recs )
- return NULL;
-
- return bi_recs;
-}
-
-static void __init prom_bi_rec_reserve(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- struct bi_record *rec;
-
- if ( _prom->bi_recs != NULL) {
-
- for ( rec=_prom->bi_recs;
- rec->tag != BI_LAST;
- rec=bi_rec_next(rec) ) {
-#ifdef DEBUG_PROM
- prom_print(RELOC("bi: 0x"));
- prom_print_hex(rec->tag);
- prom_print_nl();
-#endif /* DEBUG_PROM */
- switch (rec->tag) {
-#ifdef CONFIG_BLK_DEV_INITRD
- case BI_INITRD:
- RELOC(initrd_start) = (unsigned long)(rec->data[0]);
- RELOC(initrd_end) = RELOC(initrd_start) + rec->data[1];
- break;
-#endif /* CONFIG_BLK_DEV_INITRD */
- }
- }
- /* The next use of this field will be after relocation
- * is enabled, so convert this physical address into a
- * virtual address.
- */
- _prom->bi_recs = PTRUNRELOC(_prom->bi_recs);
- }
-}
-
-/*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
-
-unsigned long __init
-prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
- unsigned long r6, unsigned long r7)
-{
- unsigned long mem;
- ihandle prom_cpu;
- phandle cpu_pkg;
- unsigned long offset = reloc_offset();
- long l;
- char *p, *d;
- unsigned long phys;
- u32 getprop_rval;
- struct systemcfg *_systemcfg;
- struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
- struct prom_t *_prom = PTRRELOC(&prom);
-
- /* First zero the BSS -- use memset, some arches don't have
- * caches on yet */
- memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start);
-
- /* Setup systemcfg and NACA pointers now */
- RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset);
- RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset);
-
- /* Init interface to Open Firmware and pickup bi-recs */
- prom_init_client_services(pp);
-
- /* Init prom stdout device */
- prom_init_stdout();
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("klimit=0x"));
- prom_print_hex(RELOC(klimit));
- prom_print_nl();
- prom_print(RELOC("offset=0x"));
- prom_print_hex(offset);
- prom_print_nl();
- prom_print(RELOC("->mem=0x"));
- prom_print_hex(RELOC(klimit) - offset);
- prom_print_nl();
-#endif /* DEBUG_PROM */
-
- /* check out if we have bi_recs */
- _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6);
- if ( _prom->bi_recs != NULL ) {
- RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs +
- _prom->bi_recs->data[1]);
-#ifdef DEBUG_PROM
- prom_print(RELOC("bi_recs=0x"));
- prom_print_hex((unsigned long)_prom->bi_recs);
- prom_print_nl();
- prom_print(RELOC("new mem=0x"));
- prom_print_hex(RELOC(klimit) - offset);
- prom_print_nl();
-#endif /* DEBUG_PROM */
- }
-
- /* If we don't have birec's or didn't find them, check for an initrd
- * using the "yaboot" way
- */
-#ifdef CONFIG_BLK_DEV_INITRD
- if ( _prom->bi_recs == NULL && r3 && r4 && r4 != 0xdeadbeef) {
- RELOC(initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
- RELOC(initrd_end) = RELOC(initrd_start) + r4;
- RELOC(initrd_below_start_ok) = 1;
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
-
- /* Default machine type. */
- _systemcfg->platform = prom_find_machine_type();
-
- /* On pSeries, copy the CPU hold code */
- if (_systemcfg->platform == PLATFORM_PSERIES)
- copy_and_flush(0, KERNELBASE - offset, 0x100, 0);
-
- /* Start storing things at klimit */
- mem = RELOC(klimit) - offset;
-
- /* Get the full OF pathname of the stdout device */
- p = (char *) mem;
- memset(p, 0, 256);
- call_prom(RELOC("instance-to-path"), 3, 1, _prom->stdout, p, 255);
- RELOC(of_stdout_device) = PTRUNRELOC(p);
- mem += strlen(p) + 1;
-
- getprop_rval = 1;
- call_prom(RELOC("getprop"), 4, 1,
- _prom->root, RELOC("#size-cells"),
- &getprop_rval, sizeof(getprop_rval));
- _prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64;
-
- /* Determine which cpu is actually running right _now_ */
- if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
- RELOC("cpu"), &getprop_rval,
- sizeof(getprop_rval)) <= 0)
- prom_panic(RELOC("cannot find boot cpu"));
-
- prom_cpu = (ihandle)(unsigned long)getprop_rval;
- cpu_pkg = call_prom(RELOC("instance-to-package"), 1, 1, prom_cpu);
- call_prom(RELOC("getprop"), 4, 1,
- cpu_pkg, RELOC("reg"),
- &getprop_rval, sizeof(getprop_rval));
- _prom->cpu = (int)(unsigned long)getprop_rval;
- _xPaca[0].xHwProcNum = _prom->cpu;
-
- RELOC(boot_cpuid) = 0;
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("Booting CPU hw index = 0x"));
- prom_print_hex(_prom->cpu);
- prom_print_nl();
-#endif
-
- /* Get the boot device and translate it to a full OF pathname. */
- p = (char *) mem;
- l = (long) call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
- RELOC("bootpath"), p, 1<<20);
- if (l > 0) {
- p[l] = 0; /* should already be null-terminated */
- RELOC(bootpath) = PTRUNRELOC(p);
- mem += l + 1;
- d = (char *) mem;
- *d = 0;
- call_prom(RELOC("canon"), 3, 1, p, d, 1<<20);
- RELOC(bootdevice) = PTRUNRELOC(d);
- mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1);
- }
-
- RELOC(cmd_line[0]) = 0;
- if ((long)_prom->chosen > 0) {
- call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
- RELOC("bootargs"), p, sizeof(cmd_line));
- if (p != NULL && p[0] != 0)
- strlcpy(RELOC(cmd_line), p, sizeof(cmd_line));
- }
-
- early_cmdline_parse();
-
- prom_initialize_lmb();
-
- prom_bi_rec_reserve();
-
- mem = check_display(mem);
-
- if (_systemcfg->platform != PLATFORM_POWERMAC)
- prom_instantiate_rtas();
-
- /* Initialize some system info into the Naca early... */
- prom_initialize_naca();
-
- smt_setup();
-
- /* If we are on an SMP machine, then we *MUST* do the
- * following, regardless of whether we have an SMP
- * kernel or not.
- */
- prom_hold_cpus(mem);
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("after basic inits, mem=0x"));
- prom_print_hex(mem);
- prom_print_nl();
-#ifdef CONFIG_BLK_DEV_INITRD
- prom_print(RELOC("initrd_start=0x"));
- prom_print_hex(RELOC(initrd_start));
- prom_print_nl();
- prom_print(RELOC("initrd_end=0x"));
- prom_print_hex(RELOC(initrd_end));
- prom_print_nl();
-#endif /* CONFIG_BLK_DEV_INITRD */
- prom_print(RELOC("copying OF device tree...\n"));
-#endif /* DEBUG_PROM */
- mem = copy_device_tree(mem);
-
- RELOC(klimit) = mem + offset;
-
-#ifdef DEBUG_PROM
- prom_print(RELOC("new klimit is\n"));
- prom_print(RELOC("klimit=0x"));
- prom_print_hex(RELOC(klimit));
- prom_print(RELOC(" ->mem=0x\n"));
- prom_print(RELOC("klimit=0x"));
- prom_print_hex(mem);
- prom_print_nl();
-#endif /* DEBUG_PROM */
-
- lmb_reserve(0, __pa(RELOC(klimit)));
-
-#ifdef CONFIG_BLK_DEV_INITRD
- if (RELOC(initrd_start)) {
- unsigned long initrd_len;
- initrd_len = RELOC(initrd_end) - RELOC(initrd_start);
-
- /* Move initrd if it's where we're going to copy kernel. */
- if (RELOC(initrd_start) < __pa(RELOC(klimit))) {
- memmove((void *)mem, (void *)RELOC(initrd_start),
- initrd_len);
- RELOC(initrd_start) = mem;
- RELOC(initrd_end) = mem + initrd_len;
- }
-
- lmb_reserve(RELOC(initrd_start), initrd_len);
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
-
- if (_systemcfg->platform == PLATFORM_PSERIES)
- prom_initialize_tce_table();
+static int __initdata dt_root_addr_cells;
+static int __initdata dt_root_size_cells;
+static int __initdata iommu_is_off;
+int __initdata iommu_force_on;
+typedef u32 cell_t;
-#ifdef CONFIG_PMAC_DART
- if (_systemcfg->platform == PLATFORM_POWERMAC)
- prom_initialize_dart_table();
+#if 0
+static struct boot_param_header *initial_boot_params __initdata;
+#else
+struct boot_param_header *initial_boot_params;
#endif
-#ifdef CONFIG_BOOTX_TEXT
- if(_prom->disp_node) {
- prom_print(RELOC("Setting up bi display...\n"));
- setup_disp_fake_bi(_prom->disp_node);
- }
-#endif /* CONFIG_BOOTX_TEXT */
-
- prom_print(RELOC("Calling quiesce ...\n"));
- call_prom(RELOC("quiesce"), 0, 0);
- phys = KERNELBASE - offset;
+static struct device_node *allnodes = NULL;
-#ifdef CONFIG_BLK_DEV_INITRD
- /* If we had an initrd, we convert its address to virtual */
- if (RELOC(initrd_start)) {
- RELOC(initrd_start) = (unsigned long)__va(RELOC(initrd_start));
- RELOC(initrd_end) = (unsigned long)__va(RELOC(initrd_end));
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+static DEFINE_RWLOCK(devtree_lock);
- prom_print(RELOC("returning from prom_init\n"));
- return phys;
-}
+/* export that to outside world */
+struct device_node *of_chosen;
/*
* Find the device_node with a given phandle.
*/
-static struct device_node * __devinit
-find_phandle(phandle ph)
+static struct device_node * find_phandle(phandle ph)
{
struct device_node *np;
/*
* Find the interrupt parent of a node.
*/
-static struct device_node * __devinit
-intr_parent(struct device_node *p)
+static struct device_node * __devinit intr_parent(struct device_node *p)
{
phandle *parp;
* Find out the size of each entry of the interrupts property
* for a node.
*/
-static int __devinit
-prom_n_intr_cells(struct device_node *np)
+int __devinit prom_n_intr_cells(struct device_node *np)
{
struct device_node *p;
unsigned int *icp;
|| get_property(p, "interrupt-map", NULL) != NULL) {
printk("oops, node %s doesn't have #interrupt-cells\n",
p->full_name);
- return 1;
+ return 1;
}
}
#ifdef DEBUG_IRQ
* Map an interrupt from a device up to the platform interrupt
* descriptor.
*/
-static int __devinit
-map_interrupt(unsigned int **irq, struct device_node **ictrler,
- struct device_node *np, unsigned int *ints, int nintrc)
+static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler,
+ struct device_node *np, unsigned int *ints,
+ int nintrc)
{
struct device_node *p, *ipar;
unsigned int *imap, *imask, *ip;
int i, imaplen, match;
- int newintrc, newaddrc;
+ int newintrc = 0, newaddrc = 0;
unsigned int *reg;
int naddrc;
return nintrc;
}
-static unsigned long __init
-finish_node_interrupts(struct device_node *np, unsigned long mem_start,
- int measure_only)
+static unsigned long __init finish_node_interrupts(struct device_node *np,
+ unsigned long mem_start,
+ int measure_only)
{
unsigned int *ints;
int intlen, intrcells, intrcount;
return mem_start;
}
-static unsigned long __init
-interpret_pci_props(struct device_node *np, unsigned long mem_start,
- int naddrc, int nsizec, int measure_only)
+static unsigned long __init interpret_pci_props(struct device_node *np,
+ unsigned long mem_start,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct address_range *adr;
struct pci_reg_property *pci_addrs;
i = 0;
adr = (struct address_range *) mem_start;
while ((l -= sizeof(struct pci_reg_property)) >= 0) {
- if (!measure_only) {
+ if (!measure_only) {
adr[i].space = pci_addrs[i].addr.a_hi;
adr[i].address = pci_addrs[i].addr.a_lo;
adr[i].size = pci_addrs[i].size_lo;
return mem_start;
}
-static unsigned long __init
-interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
- int naddrc, int nsizec, int measure_only)
+static unsigned long __init interpret_dbdma_props(struct device_node *np,
+ unsigned long mem_start,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct reg_property32 *rp;
struct address_range *adr;
i = 0;
adr = (struct address_range *) mem_start;
while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
+ if (!measure_only) {
adr[i].space = 2;
adr[i].address = rp[i].address + base_address;
adr[i].size = rp[i].size;
return mem_start;
}
-static unsigned long __init
-interpret_macio_props(struct device_node *np, unsigned long mem_start,
- int naddrc, int nsizec, int measure_only)
+static unsigned long __init interpret_macio_props(struct device_node *np,
+ unsigned long mem_start,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct reg_property32 *rp;
struct address_range *adr;
i = 0;
adr = (struct address_range *) mem_start;
while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
+ if (!measure_only) {
adr[i].space = 2;
adr[i].address = rp[i].address + base_address;
adr[i].size = rp[i].size;
return mem_start;
}
-static unsigned long __init
-interpret_isa_props(struct device_node *np, unsigned long mem_start,
- int naddrc, int nsizec, int measure_only)
+static unsigned long __init interpret_isa_props(struct device_node *np,
+ unsigned long mem_start,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct isa_reg_property *rp;
struct address_range *adr;
if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
i = 0;
adr = (struct address_range *) mem_start;
- while ((l -= sizeof(struct reg_property)) >= 0) {
- if (!measure_only) {
+ while ((l -= sizeof(struct isa_reg_property)) >= 0) {
+ if (!measure_only) {
adr[i].space = rp[i].space;
adr[i].address = rp[i].address;
adr[i].size = rp[i].size;
return mem_start;
}
-static unsigned long __init
-interpret_root_props(struct device_node *np, unsigned long mem_start,
- int naddrc, int nsizec, int measure_only)
+static unsigned long __init interpret_root_props(struct device_node *np,
+ unsigned long mem_start,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct address_range *adr;
int i, l;
i = 0;
adr = (struct address_range *) mem_start;
while ((l -= rpsize) >= 0) {
- if (!measure_only) {
+ if (!measure_only) {
adr[i].space = 0;
adr[i].address = rp[naddrc - 1];
adr[i].size = rp[naddrc + nsizec - 1];
return mem_start;
}
-static unsigned long __init
-finish_node(struct device_node *np, unsigned long mem_start,
- interpret_func *ifunc, int naddrc, int nsizec, int measure_only)
+static unsigned long __init finish_node(struct device_node *np,
+ unsigned long mem_start,
+ interpret_func *ifunc,
+ int naddrc, int nsizec,
+ int measure_only)
{
struct device_node *child;
int *ip;
- np->name = get_property(np, "name", 0);
- np->type = get_property(np, "device_type", 0);
-
- if (!np->name)
- np->name = "<NULL>";
- if (!np->type)
- np->type = "<NULL>";
-
/* get the device addresses and interrupts */
if (ifunc != NULL)
mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only);
mem_start = finish_node_interrupts(np, mem_start, measure_only);
/* Look for #address-cells and #size-cells properties. */
- ip = (int *) get_property(np, "#address-cells", 0);
+ ip = (int *) get_property(np, "#address-cells", NULL);
if (ip != NULL)
naddrc = *ip;
- ip = (int *) get_property(np, "#size-cells", 0);
+ ip = (int *) get_property(np, "#size-cells", NULL);
if (ip != NULL)
nsizec = *ip;
* expect for the name -- Cort
*/
if (!strcmp(np->name, "display"))
- np->name = get_property(np, "compatible", 0);
+ np->name = get_property(np, "compatible", NULL);
if (!strcmp(np->name, "device-tree") || np->parent == NULL)
ifunc = interpret_root_props;
return mem_start;
}
-/*
+/**
* finish_device_tree is called once things are running normally
* (i.e. with text and data mapped to the address they were linked at).
- * It traverses the device tree and fills in the name, type,
- * {n_}addrs and {n_}intrs fields of each node.
+ * It traverses the device tree and fills in some of the additional,
+ * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt
+ * mapping is also initialized at this point.
*/
-void __init
-finish_device_tree(void)
+void __init finish_device_tree(void)
{
- unsigned long mem = klimit;
+ unsigned long mem, size;
+ DBG(" -> finish_device_tree\n");
+
+ if (ppc64_interrupt_controller == IC_INVALID) {
+ DBG("failed to configure interrupt controller type\n");
+ panic("failed to configure interrupt controller type\n");
+ }
+
+ /* Initialize virtual IRQ map */
virt_irq_init();
- dev_tree_size = finish_node(allnodes, 0, NULL, 0, 0, 1);
- mem = (long)abs_to_virt(lmb_alloc(dev_tree_size,
- __alignof__(struct device_node)));
- if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + dev_tree_size)
+ /* Finish device-tree (pre-parsing some properties etc...) */
+ size = finish_node(allnodes, 0, NULL, 0, 0, 1);
+ mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128));
+ if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size)
BUG();
- rtas.dev = of_find_node_by_name(NULL, "rtas");
+
+ DBG(" <- finish_device_tree\n");
+}
+
+#ifdef DEBUG
+#define printk udbg_printf
+#endif
+
+static inline char *find_flat_dt_string(u32 offset)
+{
+ return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings
+ + offset;
+}
+
+/**
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory informations at boot before we can
+ * unflatten the tree
+ */
+static int __init scan_flat_dt(int (*it)(unsigned long node,
+ const char *full_path, void *data),
+ void *data)
+{
+ unsigned long p = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+ int rc = 0;
+
+ do {
+ u32 tag = *((u32 *)p);
+ char *pathp;
+
+ p += 4;
+ if (tag == OF_DT_END_NODE)
+ continue;
+ if (tag == OF_DT_END)
+ break;
+ if (tag == OF_DT_PROP) {
+ u32 sz = *((u32 *)p);
+ p += 8;
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+ p += sz;
+ p = _ALIGN(p, 4);
+ continue;
+ }
+ if (tag != OF_DT_BEGIN_NODE) {
+ printk(KERN_WARNING "Invalid tag %x scanning flattened"
+ " device tree !\n", tag);
+ return -EINVAL;
+ }
+ pathp = (char *)p;
+ p = _ALIGN(p + strlen(pathp) + 1, 4);
+ rc = it(p, pathp, data);
+ if (rc != 0)
+ break;
+ } while(1);
+
+ return rc;
+}
+
+/**
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+static void* __init get_flat_dt_prop(unsigned long node, const char *name,
+ unsigned long *size)
+{
+ unsigned long p = node;
+
+ do {
+ u32 tag = *((u32 *)p);
+ u32 sz, noff;
+ const char *nstr;
+
+ p += 4;
+ if (tag != OF_DT_PROP)
+ return NULL;
+
+ sz = *((u32 *)p);
+ noff = *((u32 *)(p + 4));
+ p += 8;
+ p = _ALIGN(p, sz >= 8 ? 8 : 4);
+
+ nstr = find_flat_dt_string(noff);
+ if (nstr == NULL) {
+ printk(KERN_WARNING "Can't find property index name !\n");
+ return NULL;
+ }
+ if (strcmp(name, nstr) == 0) {
+ if (size)
+ *size = sz;
+ return (void *)p;
+ }
+ p += sz;
+ p = _ALIGN(p, 4);
+ } while(1);
+}
+
+static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+ unsigned long align)
+{
+ void *res;
+
+ *mem = _ALIGN(*mem, align);
+ res = (void *)*mem;
+ *mem += size;
+
+ return res;
+}
+
+static unsigned long __init unflatten_dt_node(unsigned long mem,
+ unsigned long *p,
+ struct device_node *dad,
+ struct device_node ***allnextpp)
+{
+ struct device_node *np;
+ struct property *pp, **prev_pp = NULL;
+ char *pathp;
+ u32 tag;
+ unsigned int l;
+
+ tag = *((u32 *)(*p));
+ if (tag != OF_DT_BEGIN_NODE) {
+ printk("Weird tag at start of node: %x\n", tag);
+ return mem;
+ }
+ *p += 4;
+ pathp = (char *)*p;
+ l = strlen(pathp) + 1;
+ *p = _ALIGN(*p + l, 4);
+
+ np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l,
+ __alignof__(struct device_node));
+ if (allnextpp) {
+ memset(np, 0, sizeof(*np));
+ np->full_name = ((char*)np) + sizeof(struct device_node);
+ memcpy(np->full_name, pathp, l);
+ prev_pp = &np->properties;
+ **allnextpp = np;
+ *allnextpp = &np->allnext;
+ if (dad != NULL) {
+ np->parent = dad;
+ /* we temporarily use the `next' field as `last_child'. */
+ if (dad->next == 0)
+ dad->child = np;
+ else
+ dad->next->sibling = np;
+ dad->next = np;
+ }
+ kref_init(&np->kref);
+ }
+ while(1) {
+ u32 sz, noff;
+ char *pname;
+
+ tag = *((u32 *)(*p));
+ if (tag != OF_DT_PROP)
+ break;
+ *p += 4;
+ sz = *((u32 *)(*p));
+ noff = *((u32 *)((*p) + 4));
+ *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4);
+
+ pname = find_flat_dt_string(noff);
+ if (pname == NULL) {
+ printk("Can't find property name in list !\n");
+ break;
+ }
+ l = strlen(pname) + 1;
+ pp = unflatten_dt_alloc(&mem, sizeof(struct property),
+ __alignof__(struct property));
+ if (allnextpp) {
+ if (strcmp(pname, "linux,phandle") == 0) {
+ np->node = *((u32 *)*p);
+ if (np->linux_phandle == 0)
+ np->linux_phandle = np->node;
+ }
+ if (strcmp(pname, "ibm,phandle") == 0)
+ np->linux_phandle = *((u32 *)*p);
+ pp->name = pname;
+ pp->length = sz;
+ pp->value = (void *)*p;
+ *prev_pp = pp;
+ prev_pp = &pp->next;
+ }
+ *p = _ALIGN((*p) + sz, 4);
+ }
+ if (allnextpp) {
+ *prev_pp = NULL;
+ np->name = get_property(np, "name", NULL);
+ np->type = get_property(np, "device_type", NULL);
+
+ if (!np->name)
+ np->name = "<NULL>";
+ if (!np->type)
+ np->type = "<NULL>";
+ }
+ while (tag == OF_DT_BEGIN_NODE) {
+ mem = unflatten_dt_node(mem, p, np, allnextpp);
+ tag = *((u32 *)(*p));
+ }
+ if (tag != OF_DT_END_NODE) {
+ printk("Weird tag at start of node: %x\n", tag);
+ return mem;
+ }
+ *p += 4;
+ return mem;
+}
+
+
+/**
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used (this used to be done by finish_device_tree)
+ */
+void __init unflatten_device_tree(void)
+{
+ unsigned long start, mem, size;
+ struct device_node **allnextp = &allnodes;
+ char *p;
+ int l = 0;
+
+ DBG(" -> unflatten_device_tree()\n");
+
+ /* First pass, scan for size */
+ start = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+ size = unflatten_dt_node(0, &start, NULL, NULL);
+
+ DBG(" size is %lx, allocating...\n", size);
+
+ /* Allocate memory for the expanded device tree */
+ mem = (unsigned long)abs_to_virt(lmb_alloc(size,
+ __alignof__(struct device_node)));
+ DBG(" unflattening...\n", mem);
+
+ /* Second pass, do actual unflattening */
+ start = ((unsigned long)initial_boot_params) +
+ initial_boot_params->off_dt_struct;
+ unflatten_dt_node(mem, &start, NULL, &allnextp);
+ if (*((u32 *)start) != OF_DT_END)
+ printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start));
+ *allnextp = NULL;
+
+ /* Get pointer to OF "/chosen" node for use everywhere */
+ of_chosen = of_find_node_by_path("/chosen");
+
+ /* Retreive command line */
+ if (of_chosen != NULL) {
+ p = (char *)get_property(of_chosen, "bootargs", &l);
+ if (p != NULL && l > 0)
+ strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE));
+ }
+#ifdef CONFIG_CMDLINE
+ if (l == 0 || (l == 1 && (*p) == 0))
+ strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+#endif /* CONFIG_CMDLINE */
+
+ DBG("Command line is: %s\n", cmd_line);
+
+ DBG(" <- unflatten_device_tree()\n");
+}
+
+
+static int __init early_init_dt_scan_cpus(unsigned long node,
+ const char *full_path, void *data)
+{
+ char *type = get_flat_dt_prop(node, "device_type", NULL);
+
+ /* We are scanning "cpu" nodes only */
+ if (type == NULL || strcmp(type, "cpu") != 0)
+ return 0;
+
+ /* On LPAR, look for the first ibm,pft-size property for the hash table size
+ */
+ if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) {
+ u32 *pft_size;
+ pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL);
+ if (pft_size != NULL) {
+ /* pft_size[0] is the NUMA CEC cookie */
+ ppc64_pft_size = pft_size[1];
+ }
+ }
+
+ if (initial_boot_params && initial_boot_params->version >= 2) {
+ /* version 2 of the kexec param format adds the phys cpuid
+ * of booted proc.
+ */
+ boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
+ boot_cpuid = 0;
+ } else {
+ /* Check if it's the boot-cpu, set it's hw index in paca now */
+ if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {
+ u32 *prop = get_flat_dt_prop(node, "reg", NULL);
+ set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);
+ boot_cpuid_phys = get_hard_smp_processor_id(0);
+ }
+ }
+
+ return 0;
+}
+
+static int __init early_init_dt_scan_chosen(unsigned long node,
+ const char *full_path, void *data)
+{
+ u32 *prop;
+
+ if (strcmp(full_path, "/chosen") != 0)
+ return 0;
+
+ /* get platform type */
+ prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL);
+ if (prop == NULL)
+ return 0;
+ systemcfg->platform = *prop;
+
+ /* check if iommu is forced on or off */
+ if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
+ iommu_is_off = 1;
+ if (get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)
+ iommu_force_on = 1;
+
+#ifdef CONFIG_PPC_PSERIES
+ /* To help early debugging via the front panel, we retreive a minimal
+ * set of RTAS infos now if available
+ */
+ {
+ u64 *basep, *entryp;
+
+ basep = (u64*)get_flat_dt_prop(node, "linux,rtas-base", NULL);
+ entryp = (u64*)get_flat_dt_prop(node, "linux,rtas-entry", NULL);
+ prop = (u32*)get_flat_dt_prop(node, "linux,rtas-size", NULL);
+ if (basep && entryp && prop) {
+ rtas.base = *basep;
+ rtas.entry = *entryp;
+ rtas.size = *prop;
+ }
+ }
+#endif /* CONFIG_PPC_PSERIES */
+
+ /* break now */
+ return 1;
+}
+
+static int __init early_init_dt_scan_root(unsigned long node,
+ const char *full_path, void *data)
+{
+ u32 *prop;
+
+ if (strcmp(full_path, "/") != 0)
+ return 0;
+
+ prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL);
+ dt_root_size_cells = (prop == NULL) ? 1 : *prop;
+
+ prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL);
+ dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
+
+ /* break now */
+ return 1;
+}
+
+static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
+{
+ cell_t *p = *cellp;
+ unsigned long r = 0;
+
+ /* Ignore more than 2 cells */
+ while (s > 2) {
+ p++;
+ s--;
+ }
+ while (s) {
+ r <<= 32;
+ r |= *(p++);
+ s--;
+ }
+
+ *cellp = p;
+ return r;
+}
+
+
+static int __init early_init_dt_scan_memory(unsigned long node,
+ const char *full_path, void *data)
+{
+ char *type = get_flat_dt_prop(node, "device_type", NULL);
+ cell_t *reg, *endp;
+ unsigned long l;
+
+ /* We are scanning "memory" nodes only */
+ if (type == NULL || strcmp(type, "memory") != 0)
+ return 0;
+
+ reg = (cell_t *)get_flat_dt_prop(node, "reg", &l);
+ if (reg == NULL)
+ return 0;
+
+ endp = reg + (l / sizeof(cell_t));
+
+ DBG("memory scan node %s ...\n", full_path);
+ while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
+ unsigned long base, size;
+
+ base = dt_mem_next_cell(dt_root_addr_cells, ®);
+ size = dt_mem_next_cell(dt_root_size_cells, ®);
+
+ if (size == 0)
+ continue;
+ DBG(" - %lx , %lx\n", base, size);
+ if (iommu_is_off) {
+ if (base >= 0x80000000ul)
+ continue;
+ if ((base + size) > 0x80000000ul)
+ size = 0x80000000ul - base;
+ }
+ lmb_add(base, size);
+ }
+ return 0;
+}
+
+static void __init early_reserve_mem(void)
+{
+ u64 base, size;
+ u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) +
+ initial_boot_params->off_mem_rsvmap);
+ while (1) {
+ base = *(reserve_map++);
+ size = *(reserve_map++);
+ if (size == 0)
+ break;
+ DBG("reserving: %lx -> %lx\n", base, size);
+ lmb_reserve(base, size);
+ }
+
+#if 0
+ DBG("memory reserved, lmbs :\n");
+ lmb_dump_all();
+#endif
+}
+
+void __init early_init_devtree(void *params)
+{
+ DBG(" -> early_init_devtree()\n");
+
+ /* Setup flat device-tree pointer */
+ initial_boot_params = params;
+
+ /* By default, hash size is not set */
+ ppc64_pft_size = 0;
+
+ /* Retreive various informations from the /chosen node of the
+ * device-tree, including the platform type, initrd location and
+ * size, TCE reserve, and more ...
+ */
+ scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+ /* Scan memory nodes and rebuild LMBs */
+ lmb_init();
+ scan_flat_dt(early_init_dt_scan_root, NULL);
+ scan_flat_dt(early_init_dt_scan_memory, NULL);
+ lmb_analyze();
+ systemcfg->physicalMemorySize = lmb_phys_mem_size();
+ lmb_reserve(0, __pa(klimit));
+
+ DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize);
+
+ /* Reserve LMB regions used by kernel, initrd, dt, etc... */
+ early_reserve_mem();
+
+ DBG("Scanning CPUs ...\n");
+
+ /* Retreive hash table size from flattened tree */
+ scan_flat_dt(early_init_dt_scan_cpus, NULL);
+
+ /* If hash size wasn't obtained above, we calculate it now based on
+ * the total RAM size
+ */
+ if (ppc64_pft_size == 0) {
+ unsigned long rnd_mem_size, pteg_count;
+
+ /* round mem_size up to next power of 2 */
+ rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize);
+ if (rnd_mem_size < systemcfg->physicalMemorySize)
+ rnd_mem_size <<= 1;
+
+ /* # pages / 2 */
+ pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11);
+
+ ppc64_pft_size = __ilog2(pteg_count << 7);
+ }
+
+ DBG("Hash pftSize: %x\n", (int)ppc64_pft_size);
+ DBG(" <- early_init_devtree()\n");
}
+#undef printk
+
int
prom_n_addr_cells(struct device_node* np)
{
do {
if (np->parent)
np = np->parent;
- ip = (int *) get_property(np, "#address-cells", 0);
+ ip = (int *) get_property(np, "#address-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
do {
if (np->parent)
np = np->parent;
- ip = (int *) get_property(np, "#size-cells", 0);
+ ip = (int *) get_property(np, "#size-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
return 1;
}
-/*
+/**
* Work out the sense (active-low level / active-high edge)
* of each interrupt from the device tree.
*/
-void __init
-prom_get_irq_senses(unsigned char *senses, int off, int max)
+void __init prom_get_irq_senses(unsigned char *senses, int off, int max)
{
struct device_node *np;
int i, j;
for (j = 0; j < np->n_intrs; j++) {
i = np->intrs[j].line;
if (i >= off && i < max)
- senses[i-off] = np->intrs[j].sense;
+ senses[i-off] = np->intrs[j].sense ?
+ IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE :
+ IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE;
}
}
}
-/*
+/**
* Construct and return a list of the device_nodes with a given name.
*/
struct device_node *
prevp = &np->next;
}
}
- *prevp = 0;
+ *prevp = NULL;
return head;
}
-/*
+/**
* Construct and return a list of the device_nodes with a given type.
*/
struct device_node *
prevp = &np->next;
}
}
- *prevp = 0;
+ *prevp = NULL;
return head;
}
-/*
+/**
* Returns all nodes linked together
*/
struct device_node *
*prevp = np;
prevp = &np->next;
}
- *prevp = 0;
+ *prevp = NULL;
return head;
}
-/* Checks if the given "compat" string matches one of the strings in
+/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
int
}
-/*
+/**
* Indicates whether the root node has a given value in its
* compatible property.
*/
{
struct device_node *root;
int rc = 0;
-
+
root = of_find_node_by_path("/");
if (root) {
rc = device_is_compatible(root, compat);
return rc;
}
-/*
+/**
* Construct and return a list of the device_nodes with a given type
* and compatible property.
*/
prevp = &np->next;
}
}
- *prevp = 0;
+ *prevp = NULL;
return head;
}
-/*
+/**
* Find the device_node with a given full_name.
*/
struct device_node *
}
EXPORT_SYMBOL(of_find_node_by_path);
+/**
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle: phandle of the node to find
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->linux_phandle == handle)
+ break;
+ if (np)
+ of_node_get(np);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
/**
* of_find_all_nodes - Get next node in global list
* @prev: Previous node or NULL to start iteration
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
*
- * Returns the node itself or NULL if gone.
+ * Returns node.
*/
struct device_node *of_node_get(struct device_node *node)
{
- if (node && !OF_IS_STALE(node)) {
- atomic_inc(&node->_users);
- return node;
- }
- return NULL;
+ if (node)
+ kref_get(&node->kref);
+ return node;
}
EXPORT_SYMBOL(of_node_get);
+static inline struct device_node * kref_to_device_node(struct kref *kref)
+{
+ return container_of(kref, struct device_node, kref);
+}
+
/**
- * of_node_cleanup - release a dynamically allocated node
- * @arg: Node to be released
+ * of_node_release - release a dynamically allocated node
+ * @kref: kref element of the node to be released
+ *
+ * In of_node_put() this function is passed to kref_put()
+ * as the destructor.
*/
-static void of_node_cleanup(struct device_node *node)
+static void of_node_release(struct kref *kref)
{
+ struct device_node *node = kref_to_device_node(kref);
struct property *prop = node->properties;
if (!OF_IS_DYNAMIC(node))
*/
void of_node_put(struct device_node *node)
{
- if (!node)
- return;
-
- WARN_ON(0 == atomic_read(&node->_users));
-
- if (OF_IS_STALE(node)) {
- if (atomic_dec_and_test(&node->_users)) {
- of_node_cleanup(node);
- return;
- }
- }
- else
- atomic_dec(&node->_users);
+ if (node)
+ kref_put(&node->kref, of_node_release);
}
EXPORT_SYMBOL(of_node_put);
return 0;
}
+
/*
* Fix up the uninitialized fields in a new device node:
* name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
u32 *regs;
int err = 0;
phandle *ibm_phandle;
-
- node->name = get_property(node, "name", 0);
- node->type = get_property(node, "device_type", 0);
+
+ node->name = get_property(node, "name", NULL);
+ node->type = get_property(node, "device_type", NULL);
if (!parent) {
err = -ENODEV;
}
/* now do the work of finish_node_interrupts */
- if (get_property(node, "interrupts", 0)) {
+ if (get_property(node, "interrupts", NULL)) {
err = of_finish_dynamic_node_interrupts(node);
if (err) goto out;
}
- /* now do the rough equivalent of update_dn_pci_info, this
- * probably is not correct for phb's, but should work for
- * IOAs and slots.
- */
-
- node->phb = parent->phb;
-
- regs = (u32 *)get_property(node, "reg", 0);
- if (regs) {
- node->busno = (regs[0] >> 16) & 0xff;
- node->devfn = (regs[0] >> 8) & 0xff;
- }
+ /* now do the rough equivalent of update_dn_pci_info, this
+ * probably is not correct for phb's, but should work for
+ * IOAs and slots.
+ */
- /* fixing up iommu_table */
+ node->phb = parent->phb;
- if(strcmp(node->name, "pci") == 0 &&
- get_property(node, "ibm,dma-window", NULL)) {
- node->bussubno = node->busno;
- iommu_devnode_init(node);
- }
- else
- node->iommu_table = parent->iommu_table;
+ regs = (u32 *)get_property(node, "reg", NULL);
+ if (regs) {
+ node->busno = (regs[0] >> 16) & 0xff;
+ node->devfn = (regs[0] >> 8) & 0xff;
+ }
out:
of_node_put(parent);
np->properties = proplist;
OF_MARK_DYNAMIC(np);
+ kref_init(&np->kref);
of_node_get(np);
np->parent = derive_parent(path);
if (!np->parent) {
}
/*
- * Remove an OF device node from the system.
- * Caller should have already "gotten" np.
+ * Prepare an OF node for removal from system
+ */
+static void of_cleanup_node(struct device_node *np)
+{
+ if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
+ iommu_free_table(np);
+}
+
+/*
+ * "Unplug" a node from the device tree. The caller must hold
+ * a reference to the node. The memory associated with the node
+ * is not freed until its refcount goes to zero.
*/
int of_remove_node(struct device_node *np)
{
return -EBUSY;
}
+ of_cleanup_node(np);
+
write_lock(&devtree_lock);
- OF_MARK_STALE(np);
remove_node_proc_entries(np);
if (allnodes == np)
allnodes = np->allnext;
}
write_unlock(&devtree_lock);
of_node_put(parent);
+ of_node_put(np); /* Must decrement the refcount */
return 0;
}
*lenp = pp->length;
return pp->value;
}
- return 0;
+ return NULL;
}
/*
}
}
#endif
+
+
+
+
+
+
+
+
+
+