aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Makefile3
-rw-r--r--arch/powerpc/boot/Makefile56
-rw-r--r--arch/powerpc/boot/bamboo.c2
-rw-r--r--arch/powerpc/boot/cuboot-52xx.c2
-rw-r--r--arch/powerpc/boot/cuboot-83xx.c2
-rw-r--r--arch/powerpc/boot/cuboot-85xx.c2
-rw-r--r--arch/powerpc/boot/cuboot-8xx.c2
-rw-r--r--arch/powerpc/boot/cuboot-hpc2.c2
-rw-r--r--arch/powerpc/boot/cuboot-pq2.c2
-rw-r--r--arch/powerpc/boot/cuboot-sequoia.c2
-rw-r--r--arch/powerpc/boot/ebony.c2
-rw-r--r--arch/powerpc/boot/ep88xc.c2
-rw-r--r--arch/powerpc/boot/flatdevtree.c1036
-rw-r--r--arch/powerpc/boot/flatdevtree.h113
-rw-r--r--arch/powerpc/boot/flatdevtree_misc.c79
-rw-r--r--arch/powerpc/boot/holly.c2
-rw-r--r--arch/powerpc/boot/libfdt-wrapper.c182
-rw-r--r--arch/powerpc/boot/libfdt/Makefile.libfdt14
-rw-r--r--arch/powerpc/boot/libfdt/fdt.c156
-rw-r--r--arch/powerpc/boot/libfdt/fdt.h60
-rw-r--r--arch/powerpc/boot/libfdt/fdt_ro.c583
-rw-r--r--arch/powerpc/boot/libfdt/fdt_rw.c447
-rw-r--r--arch/powerpc/boot/libfdt/fdt_strerror.c96
-rw-r--r--arch/powerpc/boot/libfdt/fdt_sw.c258
-rw-r--r--arch/powerpc/boot/libfdt/fdt_wip.c144
-rw-r--r--arch/powerpc/boot/libfdt/libfdt.h721
-rw-r--r--arch/powerpc/boot/libfdt/libfdt_internal.h89
-rw-r--r--arch/powerpc/boot/libfdt_env.h17
-rw-r--r--arch/powerpc/boot/main.c1
-rw-r--r--arch/powerpc/boot/ops.h2
-rw-r--r--arch/powerpc/boot/prpmc2800.c3
-rw-r--r--arch/powerpc/boot/ps3.c2
-rw-r--r--arch/powerpc/boot/treeboot-walnut.c2
-rwxr-xr-xarch/powerpc/boot/wrapper17
-rw-r--r--arch/powerpc/configs/celleb_defconfig38
-rw-r--r--arch/powerpc/kernel/iommu.c8
-rw-r--r--arch/powerpc/kernel/isa-bridge.c6
-rw-r--r--arch/powerpc/kernel/lparcfg.c12
-rw-r--r--arch/powerpc/kernel/misc.S8
-rw-r--r--arch/powerpc/kernel/misc_32.S7
-rw-r--r--arch/powerpc/kernel/misc_64.S7
-rw-r--r--arch/powerpc/kernel/of_platform.c20
-rw-r--r--arch/powerpc/kernel/pci-common.c38
-rw-r--r--arch/powerpc/kernel/pci_32.c10
-rw-r--r--arch/powerpc/kernel/pci_64.c42
-rw-r--r--arch/powerpc/kernel/pci_dn.c2
-rw-r--r--arch/powerpc/kernel/prom.c15
-rw-r--r--arch/powerpc/kernel/prom_parse.c2
-rw-r--r--arch/powerpc/kernel/rtas_pci.c2
-rw-r--r--arch/powerpc/kernel/setup-common.c78
-rw-r--r--arch/powerpc/mm/fault.c2
-rw-r--r--arch/powerpc/mm/hash_utils_64.c1
-rw-r--r--arch/powerpc/mm/slb.c3
-rw-r--r--arch/powerpc/mm/slb_low.S5
-rw-r--r--arch/powerpc/platforms/82xx/pq2.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ds.c2
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c2
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c2
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c2
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c4
-rw-r--r--arch/powerpc/platforms/cell/iommu.c4
-rw-r--r--arch/powerpc/platforms/cell/setup.c2
-rw-r--r--arch/powerpc/platforms/cell/smp.c3
-rw-r--r--arch/powerpc/platforms/celleb/Kconfig2
-rw-r--r--arch/powerpc/platforms/celleb/io-workarounds.c6
-rw-r--r--arch/powerpc/platforms/celleb/iommu.c3
-rw-r--r--arch/powerpc/platforms/celleb/pci.c13
-rw-r--r--arch/powerpc/platforms/celleb/scc_epci.c2
-rw-r--r--arch/powerpc/platforms/celleb/setup.c99
-rw-r--r--arch/powerpc/platforms/embedded6xx/holly.c2
-rw-r--r--arch/powerpc/platforms/iseries/Makefile2
-rw-r--r--arch/powerpc/platforms/iseries/pci.c648
-rw-r--r--arch/powerpc/platforms/iseries/pci.h23
-rw-r--r--arch/powerpc/platforms/iseries/setup.c24
-rw-r--r--arch/powerpc/platforms/iseries/setup.h1
-rw-r--r--arch/powerpc/platforms/iseries/vpdinfo.c275
-rw-r--r--arch/powerpc/platforms/maple/pci.c2
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig2
-rw-r--r--arch/powerpc/platforms/pasemi/cpufreq.c19
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c96
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h6
-rw-r--r--arch/powerpc/platforms/pasemi/powersave.S11
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c21
-rw-r--r--arch/powerpc/platforms/powermac/pci.c6
-rw-r--r--arch/powerpc/platforms/powermac/setup.c4
-rw-r--r--arch/powerpc/platforms/powermac/time.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c3
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c19
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c28
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h5
-rw-r--r--arch/powerpc/platforms/pseries/smp.c3
-rw-r--r--arch/powerpc/sysdev/axonram.c5
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c2
-rw-r--r--arch/powerpc/sysdev/pmi.c4
-rw-r--r--arch/powerpc/xmon/xmon.c69
-rw-r--r--arch/ppc/platforms/ev64260.c4
96 files changed, 3731 insertions, 2112 deletions
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index bd87626c1f6..f70df9b64f8 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -167,6 +167,9 @@ boot := arch/$(ARCH)/boot
$(BOOT_TARGETS): vmlinux
$(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
+bootwrapper_install:
+ $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
+
define archhelp
@echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)'
@echo ' install - Install kernel using'
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 18e32719d0e..af01b4f8ade 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -33,7 +33,7 @@ ifeq ($(call cc-option-yn, -fstack-protector),y)
BOOTCFLAGS += -fno-stack-protector
endif
-BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
+BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) -I$(srctree)/$(src)/libfdt
$(obj)/4xx.o: BOOTCFLAGS += -mcpu=440
$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
@@ -46,7 +46,9 @@ zliblinuxheader := zlib.h zconf.h zutil.h
$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
-src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+src-wlib := string.S crt0.S stdio.c main.c \
+ $(addprefix libfdt/,$(src-libfdt)) libfdt-wrapper.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
@@ -101,8 +103,10 @@ quiet_cmd_bootar = BOOTAR $@
cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
+ $(Q)mkdir -p $(dir $@)
$(call if_changed_dep,bootcc)
$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
+ $(Q)mkdir -p $(dir $@)
$(call if_changed_dep,bootas)
$(obj)/wrapper.a: $(obj-wlib) FORCE
@@ -243,3 +247,51 @@ clean-kernel := vmlinux.strip vmlinux.bin
clean-kernel += $(addsuffix .gz,$(clean-kernel))
# If not absolute clean-files are relative to $(obj).
clean-files += $(addprefix $(objtree)/, $(clean-kernel))
+
+WRAPPER_OBJDIR := /usr/lib/kernel-wrapper
+WRAPPER_DTSDIR := /usr/lib/kernel-wrapper/dts
+WRAPPER_BINDIR := /usr/sbin
+INSTALL := install
+
+extra-installed := $(patsubst $(obj)/%, $(DESTDIR)$(WRAPPER_OBJDIR)/%, $(extra-y))
+hostprogs-installed := $(patsubst %, $(DESTDIR)$(WRAPPER_BINDIR)/%, $(hostprogs-y))
+wrapper-installed := $(DESTDIR)$(WRAPPER_BINDIR)/wrapper
+dts-installed := $(patsubst $(obj)/dts/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(obj)/dts/*.dts))
+
+all-installed := $(extra-installed) $(hostprogs-installed) $(wrapper-installed) $(dts-installed)
+
+quiet_cmd_mkdir = MKDIR $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
+ cmd_mkdir = mkdir -p $@
+
+quiet_cmd_install = INSTALL $(patsubst $(DESTDIR)$(WRAPPER_OBJDIR)/%,%,$@)
+ cmd_install = $(INSTALL) -m0644 $(patsubst $(DESTDIR)$(WRAPPER_OBJDIR)/%,$(obj)/%,$@) $@
+
+quiet_cmd_install_dts = INSTALL $(patsubst $(DESTDIR)$(WRAPPER_DTSDIR)/%,dts/%,$@)
+ cmd_install_dts = $(INSTALL) -m0644 $(patsubst $(DESTDIR)$(WRAPPER_DTSDIR)/%,$(srctree)/$(obj)/dts/%,$@) $@
+
+quiet_cmd_install_exe = INSTALL $(patsubst $(DESTDIR)$(WRAPPER_BINDIR)/%,%,$@)
+ cmd_install_exe = $(INSTALL) -m0755 $(patsubst $(DESTDIR)$(WRAPPER_BINDIR)/%,$(obj)/%,$@) $@
+
+quiet_cmd_install_wrapper = INSTALL $(patsubst $(DESTDIR)$(WRAPPER_BINDIR)/%,%,$@)
+ cmd_install_wrapper = $(INSTALL) -m0755 $(patsubst $(DESTDIR)$(WRAPPER_BINDIR)/%,$(srctree)/$(obj)/%,$@) $@ ;\
+ sed -i $@ -e 's%^object=.*%object=$(WRAPPER_OBJDIR)%' \
+ -e 's%^objbin=.*%objbin=$(WRAPPER_BINDIR)%' \
+
+
+$(DESTDIR)$(WRAPPER_OBJDIR) $(DESTDIR)$(WRAPPER_DTSDIR) $(DESTDIR)$(WRAPPER_BINDIR):
+ $(call cmd,mkdir)
+
+$(extra-installed) : $(DESTDIR)$(WRAPPER_OBJDIR)/% : $(obj)/% | $(DESTDIR)$(WRAPPER_OBJDIR)
+ $(call cmd,install)
+
+$(hostprogs-installed) : $(DESTDIR)$(WRAPPER_BINDIR)/% : $(obj)/% | $(DESTDIR)$(WRAPPER_BINDIR)
+ $(call cmd,install_exe)
+
+$(dts-installed) : $(DESTDIR)$(WRAPPER_DTSDIR)/% : $(srctree)/$(obj)/dts/% | $(DESTDIR)$(WRAPPER_DTSDIR)
+ $(call cmd,install_dts)
+
+$(wrapper-installed): $(DESTDIR)$(WRAPPER_BINDIR) $(srctree)/$(obj)/wrapper | $(DESTDIR)$(WRAPPER_BINDIR)
+ $(call cmd,install_wrapper)
+
+$(obj)/bootwrapper_install: $(all-installed)
+
diff --git a/arch/powerpc/boot/bamboo.c b/arch/powerpc/boot/bamboo.c
index f61fcdab1c7..e634359d98e 100644
--- a/arch/powerpc/boot/bamboo.c
+++ b/arch/powerpc/boot/bamboo.c
@@ -42,6 +42,6 @@ void bamboo_init(void *mac0, void *mac1)
platform_ops.exit = ibm44x_dbcr_reset;
bamboo_mac0 = mac0;
bamboo_mac1 = mac1;
- ft_init(_dtb_start, 0, 32);
+ fdt_init(_dtb_start);
serial_console_init();
}
diff --git a/arch/powerpc/boot/cuboot-52xx.c b/arch/powerpc/boot/cuboot-52xx.c
index 9256a26d40e..a8611546a65 100644
--- a/arch/powerpc/boot/cuboot-52xx.c
+++ b/arch/powerpc/boot/cuboot-52xx.c
@@ -53,7 +53,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
index a0505509abc..acd860ed739 100644
--- a/arch/powerpc/boot/cuboot-83xx.c
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -52,7 +52,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
index 345dcbecef0..943779ed19b 100644
--- a/arch/powerpc/boot/cuboot-85xx.c
+++ b/arch/powerpc/boot/cuboot-85xx.c
@@ -53,7 +53,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-8xx.c b/arch/powerpc/boot/cuboot-8xx.c
index 0e82015a5f9..c202c8868bd 100644
--- a/arch/powerpc/boot/cuboot-8xx.c
+++ b/arch/powerpc/boot/cuboot-8xx.c
@@ -41,7 +41,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-hpc2.c b/arch/powerpc/boot/cuboot-hpc2.c
index d333898bca3..1b8953259d7 100644
--- a/arch/powerpc/boot/cuboot-hpc2.c
+++ b/arch/powerpc/boot/cuboot-hpc2.c
@@ -42,7 +42,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-pq2.c b/arch/powerpc/boot/cuboot-pq2.c
index 61574f3272d..f56ac6cae9f 100644
--- a/arch/powerpc/boot/cuboot-pq2.c
+++ b/arch/powerpc/boot/cuboot-pq2.c
@@ -255,7 +255,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
CUBOOT_INIT();
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
platform_ops.fixups = pq2_platform_fixups;
}
diff --git a/arch/powerpc/boot/cuboot-sequoia.c b/arch/powerpc/boot/cuboot-sequoia.c
index ec635e0bd4e..cf78260fcf3 100644
--- a/arch/powerpc/boot/cuboot-sequoia.c
+++ b/arch/powerpc/boot/cuboot-sequoia.c
@@ -51,6 +51,6 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
CUBOOT_INIT();
platform_ops.fixups = sequoia_fixups;
platform_ops.exit = ibm44x_dbcr_reset;
- ft_init(_dtb_start, 0, 32);
+ fdt_init(_dtb_start);
serial_console_init();
}
diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c
index 86c0f5df0a8..ee31be5e633 100644
--- a/arch/powerpc/boot/ebony.c
+++ b/arch/powerpc/boot/ebony.c
@@ -146,6 +146,6 @@ void ebony_init(void *mac0, void *mac1)
platform_ops.exit = ibm44x_dbcr_reset;
ebony_mac0 = mac0;
ebony_mac1 = mac1;
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
}
diff --git a/arch/powerpc/boot/ep88xc.c b/arch/powerpc/boot/ep88xc.c
index 6b87cdce3fe..a400f540715 100644
--- a/arch/powerpc/boot/ep88xc.c
+++ b/arch/powerpc/boot/ep88xc.c
@@ -45,7 +45,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
mem_size *= 1024 * 1024;
simple_alloc_init(_end, mem_size - (unsigned long)_end, 32, 64);
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
planetcore_set_stdout_path(table);
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
deleted file mode 100644
index cf30675c611..00000000000
--- a/arch/powerpc/boot/flatdevtree.c
+++ /dev/null
@@ -1,1036 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright Pantelis Antoniou 2006
- * Copyright (C) IBM Corporation 2006
- *
- * Authors: Pantelis Antoniou <pantelis@embeddedalley.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
- * Mark A. Greer <mgreer@mvista.com>
- * Paul Mackerras <paulus@samba.org>
- */
-
-#include <string.h>
-#include <stddef.h>
-#include "flatdevtree.h"
-#include "flatdevtree_env.h"
-
-#define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1))
-
-static char *ft_root_node(struct ft_cxt *cxt)
-{
- return cxt->rgn[FT_STRUCT].start;
-}
-
-/* Routines for keeping node ptrs returned by ft_find_device current */
-/* First entry not used b/c it would return 0 and be taken as NULL/error */
-static void *ft_get_phandle(struct ft_cxt *cxt, char *node)
-{
- unsigned int i;
-
- if (!node)
- return NULL;
-
- for (i = 1; i < cxt->nodes_used; i++) /* already there? */
- if (cxt->node_tbl[i] == node)
- return (void *)i;
-
- if (cxt->nodes_used < cxt->node_max) {
- cxt->node_tbl[cxt->nodes_used] = node;
- return (void *)cxt->nodes_used++;
- }
-
- return NULL;
-}
-
-static char *ft_node_ph2node(struct ft_cxt *cxt, const void *phandle)
-{
- unsigned int i = (unsigned int)phandle;
-
- if (i < cxt->nodes_used)
- return cxt->node_tbl[i];
- return NULL;
-}
-
-static void ft_node_update_before(struct ft_cxt *cxt, char *addr, int shift)
-{
- unsigned int i;
-
- if (shift == 0)
- return;
-
- for (i = 1; i < cxt->nodes_used; i++)
- if (cxt->node_tbl[i] < addr)
- cxt->node_tbl[i] += shift;
-}
-
-static void ft_node_update_after(struct ft_cxt *cxt, char *addr, int shift)
-{
- unsigned int i;
-
- if (shift == 0)
- return;
-
- for (i = 1; i < cxt->nodes_used; i++)
- if (cxt->node_tbl[i] >= addr)
- cxt->node_tbl[i] += shift;
-}
-
-/* Struct used to return info from ft_next() */
-struct ft_atom {
- u32 tag;
- const char *name;
- void *data;
- u32 size;
-};
-
-/* Set ptrs to current one's info; return addr of next one */
-static char *ft_next(struct ft_cxt *cxt, char *p, struct ft_atom *ret)
-{
- u32 sz;
-
- if (p >= cxt->rgn[FT_STRUCT].start + cxt->rgn[FT_STRUCT].size)
- return NULL;
-
- ret->tag = be32_to_cpu(*(u32 *) p);
- p += 4;
-
- switch (ret->tag) { /* Tag */
- case OF_DT_BEGIN_NODE:
- ret->name = p;
- ret->data = (void *)(p - 4); /* start of node */
- p += _ALIGN(strlen(p) + 1, 4);
- break;
- case OF_DT_PROP:
- ret->size = sz = be32_to_cpu(*(u32 *) p);
- ret->name = cxt->str_anchor + be32_to_cpu(*(u32 *) (p + 4));
- ret->data = (void *)(p + 8);
- p += 8 + _ALIGN(sz, 4);
- break;
- case OF_DT_END_NODE:
- case OF_DT_NOP:
- break;
- case OF_DT_END:
- default:
- p = NULL;
- break;
- }
-
- return p;
-}
-
-#define HDR_SIZE _ALIGN(sizeof(struct boot_param_header), 8)
-#define EXPAND_INCR 1024 /* alloc this much extra when expanding */
-
-/* Copy the tree to a newly-allocated region and put things in order */
-static int ft_reorder(struct ft_cxt *cxt, int nextra)
-{
- unsigned long tot;
- enum ft_rgn_id r;
- char *p, *pend;
- int stroff;
-
- tot = HDR_SIZE + EXPAND_INCR;
- for (r = FT_RSVMAP; r <= FT_STRINGS; ++r)
- tot += cxt->rgn[r].size;
- if (nextra > 0)
- tot += nextra;
- tot = _ALIGN(tot, 8);
-
- if (!cxt->realloc)
- return 0;
- p = cxt->realloc(NULL, tot);
- if (!p)
- return 0;
-
- memcpy(p, cxt->bph, sizeof(struct boot_param_header));
- /* offsets get fixed up later */
-
- cxt->bph = (struct boot_param_header *)p;
- cxt->max_size = tot;
- pend = p + tot;
- p += HDR_SIZE;
-
- memcpy(p, cxt->rgn[FT_RSVMAP].start, cxt->rgn[FT_RSVMAP].size);
- cxt->rgn[FT_RSVMAP].start = p;
- p += cxt->rgn[FT_RSVMAP].size;
-
- memcpy(p, cxt->rgn[FT_STRUCT].start, cxt->rgn[FT_STRUCT].size);
- ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
- p - cxt->rgn[FT_STRUCT].start);
- cxt->p += p - cxt->rgn[FT_STRUCT].start;
- cxt->rgn[FT_STRUCT].start = p;
-
- p = pend - cxt->rgn[FT_STRINGS].size;
- memcpy(p, cxt->rgn[FT_STRINGS].start, cxt->rgn[FT_STRINGS].size);
- stroff = cxt->str_anchor - cxt->rgn[FT_STRINGS].start;
- cxt->rgn[FT_STRINGS].start = p;
- cxt->str_anchor = p + stroff;
-
- cxt->isordered = 1;
- return 1;
-}
-
-static inline char *prev_end(struct ft_cxt *cxt, enum ft_rgn_id r)
-{
- if (r > FT_RSVMAP)
- return cxt->rgn[r - 1].start + cxt->rgn[r - 1].size;
- return (char *)cxt->bph + HDR_SIZE;
-}
-
-static inline char *next_start(struct ft_cxt *cxt, enum ft_rgn_id r)
-{
- if (r < FT_STRINGS)
- return cxt->rgn[r + 1].start;
- return (char *)cxt->bph + cxt->max_size;
-}
-
-/*
- * See if we can expand region rgn by nextra bytes by using up
- * free space after or before the region.
- */
-static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
- int nextra)
-{
- char *p = *pp;
- char *rgn_start, *rgn_end;
-
- rgn_start = cxt->rgn[rgn].start;
- rgn_end = rgn_start + cxt->rgn[rgn].size;
- if (nextra <= 0 || rgn_end + nextra <= next_start(cxt, rgn)) {
- /* move following stuff */
- if (p < rgn_end) {
- if (nextra < 0)
- memmove(p, p - nextra, rgn_end - p + nextra);
- else
- memmove(p + nextra, p, rgn_end - p);
- if (rgn == FT_STRUCT)
- ft_node_update_after(cxt, p, nextra);
- }
- cxt->rgn[rgn].size += nextra;
- if (rgn == FT_STRINGS)
- /* assumes strings only added at beginning */
- cxt->str_anchor += nextra;
- return 1;
- }
- if (prev_end(cxt, rgn) <= rgn_start - nextra) {
- /* move preceding stuff */
- if (p > rgn_start) {
- memmove(rgn_start - nextra, rgn_start, p - rgn_start);
- if (rgn == FT_STRUCT)
- ft_node_update_before(cxt, p, -nextra);
- }
- *pp -= nextra;
- cxt->rgn[rgn].start -= nextra;
- cxt->rgn[rgn].size += nextra;
- return 1;
- }
- return 0;
-}
-
-static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
- int nextra)
-{
- unsigned long size, ssize, tot;
- char *str, *next;
- enum ft_rgn_id r;
-
- if (!cxt->isordered) {
- unsigned long rgn_off = *pp - cxt->rgn[rgn].start;
-
- if (!ft_reorder(cxt, nextra))
- return 0;
-
- *pp = cxt->rgn[rgn].start + rgn_off;
- }
- if (ft_shuffle(cxt, pp, rgn, nextra))
- return 1;
-
- /* See if there is space after the strings section */
- ssize = cxt->rgn[FT_STRINGS].size;
- if (cxt->rgn[FT_STRINGS].start + ssize
- < (char *)cxt->bph + cxt->max_size) {
- /* move strings up as far as possible */
- str = (char *)cxt->bph + cxt->max_size - ssize;
- cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start;
- memmove(str, cxt->rgn[FT_STRINGS].start, ssize);
- cxt->rgn[FT_STRINGS].start = str;
- /* enough space now? */
- if (rgn >= FT_STRUCT && ft_shuffle(cxt, pp, rgn, nextra))
- return 1;
- }
-
- /* how much total free space is there following this region? */
- tot = 0;
- for (r = rgn; r < FT_STRINGS; ++r) {
- char *r_end = cxt->rgn[r].start + cxt->rgn[r].size;
- tot += next_start(cxt, rgn) - r_end;
- }
-
- /* cast is to shut gcc up; we know nextra >= 0 */
- if (tot < (unsigned int)nextra) {
- /* have to reallocate */
- char *newp, *new_start;
- int shift;
-
- if (!cxt->realloc)
- return 0;
- size = _ALIGN(cxt->max_size + (nextra - tot) + EXPAND_INCR, 8);
- newp = cxt->realloc(cxt->bph, size);
- if (!newp)
- return 0;
- cxt->max_size = size;
- shift = newp - (char *)cxt->bph;
-
- if (shift) { /* realloc can return same addr */
- cxt->bph = (struct boot_param_header *)newp;
- ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
- shift);
- for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) {
- new_start = cxt->rgn[r].start + shift;
- cxt->rgn[r].start = new_start;
- }
- *pp += shift;
- cxt->str_anchor += shift;
- }
-
- /* move strings up to the end */
- str = newp + size - ssize;
- cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start;
- memmove(str, cxt->rgn[FT_STRINGS].start, ssize);
- cxt->rgn[FT_STRINGS].start = str;
-
- if (ft_shuffle(cxt, pp, rgn, nextra))
- return 1;
- }
-
- /* must be FT_RSVMAP and we need to move FT_STRUCT up */
- if (rgn == FT_RSVMAP) {
- next = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size
- + nextra;
- ssize = cxt->rgn[FT_STRUCT].size;
- if (next + ssize >= cxt->rgn[FT_STRINGS].start)
- return 0; /* "can't happen" */
- memmove(next, cxt->rgn[FT_STRUCT].start, ssize);
- ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, nextra);
- cxt->rgn[FT_STRUCT].start = next;
-
- if (ft_shuffle(cxt, pp, rgn, nextra))
- return 1;
- }
-
- return 0; /* "can't happen" */
-}
-
-static void ft_put_word(struct ft_cxt *cxt, u32 v)
-{
- *(u32 *) cxt->p = cpu_to_be32(v);
- cxt->p += 4;
-}
-
-static void ft_put_bin(struct ft_cxt *cxt, const void *data, unsigned int sz)
-{
- unsigned long sza = _ALIGN(sz, 4);
-
- /* zero out the alignment gap if necessary */
- if (sz < sza)
- *(u32 *) (cxt->p + sza - 4) = 0;
-
- /* copy in the data */
- memcpy(cxt->p, data, sz);
-
- cxt->p += sza;
-}
-
-char *ft_begin_node(struct ft_cxt *cxt, const char *name)
-{
- unsigned long nlen = strlen(name) + 1;
- unsigned long len = 8 + _ALIGN(nlen, 4);
- char *ret;
-
- if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len))
- return NULL;
-
- ret = cxt->p;
-
- ft_put_word(cxt, OF_DT_BEGIN_NODE);
- ft_put_bin(cxt, name, strlen(name) + 1);
-
- return ret;
-}
-
-void ft_end_node(struct ft_cxt *cxt)
-{
- ft_put_word(cxt, OF_DT_END_NODE);
-}
-
-void ft_nop(struct ft_cxt *cxt)
-{
- if (ft_make_space(cxt, &cxt->p, FT_STRUCT, 4))
- ft_put_word(cxt, OF_DT_NOP);
-}
-
-#define NO_STRING 0x7fffffff
-
-static int lookup_string(struct ft_cxt *cxt, const char *name)
-{
- char *p, *end;
-
- p = cxt->rgn[FT_STRINGS].start;
- end = p + cxt->rgn[FT_STRINGS].size;
- while (p < end) {
- if (strcmp(p, (char *)name) == 0)
- return p - cxt->str_anchor;
- p += strlen(p) + 1;
- }
-
- return NO_STRING;
-}
-
-/* lookup string and insert if not found */
-static int map_string(struct ft_cxt *cxt, const char *name)
-{
- int off;
- char *p;
-
- off = lookup_string(cxt, name);
- if (off != NO_STRING)
- return off;
- p = cxt->rgn[FT_STRINGS].start;
- if (!ft_make_space(cxt, &p, FT_STRINGS, strlen(name) + 1))
- return NO_STRING;
- strcpy(p, name);
- return p - cxt->str_anchor;
-}
-
-int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
- unsigned int sz)
-{
- int off, len;
-
- off = map_string(cxt, name);
- if (off == NO_STRING)
- return -1;
-
- len = 12 + _ALIGN(sz, 4);
- if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len))
- return -1;
-
- ft_put_word(cxt, OF_DT_PROP);
- ft_put_word(cxt, sz);
- ft_put_word(cxt, off);
- ft_put_bin(cxt, data, sz);
- return 0;
-}
-
-int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str)
-{
- return ft_prop(cxt, name, str, strlen(str) + 1);
-}
-
-int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val)
-{
- u32 v = cpu_to_be32((u32) val);
-
- return ft_prop(cxt, name, &v, 4);
-}
-
-/* Calculate the size of the reserved map */
-static unsigned long rsvmap_size(struct ft_cxt *cxt)
-{
- struct ft_reserve *res;
-
- res = (struct ft_reserve *)cxt->rgn[FT_RSVMAP].start;
- while (res->start || res->len)
- ++res;
- return (char *)(res + 1) - cxt->rgn[FT_RSVMAP].start;
-}
-
-/* Calculate the size of the struct region by stepping through it */
-static unsigned long struct_size(struct ft_cxt *cxt)
-{
- char *p = cxt->rgn[FT_STRUCT].start;
- char *next;
- struct ft_atom atom;
-
- /* make check in ft_next happy */
- if (cxt->rgn[FT_STRUCT].size == 0)
- cxt->rgn[FT_STRUCT].size = 0xfffffffful - (unsigned long)p;
-
- while ((next = ft_next(cxt, p, &atom)) != NULL)
- p = next;
- return p + 4 - cxt->rgn[FT_STRUCT].start;
-}
-
-/* add `adj' on to all string offset values in the struct area */
-static void adjust_string_offsets(struct ft_cxt *cxt, int adj)
-{
- char *p = cxt->rgn[FT_STRUCT].start;
- char *next;
- struct ft_atom atom;
- int off;
-
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- if (atom.tag == OF_DT_PROP) {
- off = be32_to_cpu(*(u32 *) (p + 8));
- *(u32 *) (p + 8) = cpu_to_be32(off + adj);
- }
- p = next;
- }
-}
-
-/* start construction of the flat OF tree from scratch */
-void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size,
- void *(*realloc_fn) (void *, unsigned long))
-{
- struct boot_param_header *bph = blob;
- char *p;
- struct ft_reserve *pres;
-
- /* clear the cxt */
- memset(cxt, 0, sizeof(*cxt));
-
- cxt->bph = bph;
- cxt->max_size = max_size;
- cxt->realloc = realloc_fn;
- cxt->isordered = 1;
-
- /* zero everything in the header area */
- memset(bph, 0, sizeof(*bph));
-
- bph->magic = cpu_to_be32(OF_DT_HEADER);
- bph->version = cpu_to_be32(0x10);
- bph->last_comp_version = cpu_to_be32(0x10);
-
- /* start pointers */
- cxt->rgn[FT_RSVMAP].start = p = blob + HDR_SIZE;
- cxt->rgn[FT_RSVMAP].size = sizeof(struct ft_reserve);
- pres = (struct ft_reserve *)p;
- cxt->rgn[FT_STRUCT].start = p += sizeof(struct ft_reserve);
- cxt->rgn[FT_STRUCT].size = 4;
- cxt->rgn[FT_STRINGS].start = blob + max_size;
- cxt->rgn[FT_STRINGS].size = 0;
-
- /* init rsvmap and struct */
- pres->start = 0;
- pres->len = 0;
- *(u32 *) p = cpu_to_be32(OF_DT_END);
-
- cxt->str_anchor = blob;
-}
-
-/* open up an existing blob to be examined or modified */
-int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size,
- unsigned int max_find_device,
- void *(*realloc_fn) (void *, unsigned long))
-{
- struct boot_param_header *bph = blob;
-
- /* can't cope with version < 16 */
- if (be32_to_cpu(bph->version) < 16)
- return -1;
-
- /* clear the cxt */
- memset(cxt, 0, sizeof(*cxt));
-
- /* alloc node_tbl to track node ptrs returned by ft_find_device */
- ++max_find_device;
- cxt->node_tbl = realloc_fn(NULL, max_find_device * sizeof(char *));
- if (!cxt->node_tbl)
- return -1;
- memset(cxt->node_tbl, 0, max_find_device * sizeof(char *));
- cxt->node_max = max_find_device;
- cxt->nodes_used = 1; /* don't use idx 0 b/c looks like NULL */
-
- cxt->bph = bph;
- cxt->max_size = max_size;
- cxt->realloc = realloc_fn;
-
- cxt->rgn[FT_RSVMAP].start = blob + be32_to_cpu(bph->off_mem_rsvmap);
- cxt->rgn[FT_RSVMAP].size = rsvmap_size(cxt);
- cxt->rgn[FT_STRUCT].start = blob + be32_to_cpu(bph->off_dt_struct);
- cxt->rgn[FT_STRUCT].size = struct_size(cxt);
- cxt->rgn[FT_STRINGS].start = blob + be32_to_cpu(bph->off_dt_strings);
- cxt->rgn[FT_STRINGS].size = be32_to_cpu(bph->dt_strings_size);
-
- cxt->p = cxt->rgn[FT_STRUCT].start;
- cxt->str_anchor = cxt->rgn[FT_STRINGS].start;
-
- return 0;
-}
-
-/* add a reserver physical area to the rsvmap */
-int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size)
-{
- char *p;
- struct ft_reserve *pres;
-
- p = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size
- - sizeof(struct ft_reserve);
- if (!ft_make_space(cxt, &p, FT_RSVMAP, sizeof(struct ft_reserve)))
- return -1;
-
- pres = (struct ft_reserve *)p;
- pres->start = cpu_to_be64(physaddr);
- pres->len = cpu_to_be64(size);
-
- return 0;
-}
-
-void ft_begin_tree(struct ft_cxt *cxt)
-{
- cxt->p = ft_root_node(cxt);
-}
-
-void ft_end_tree(struct ft_cxt *cxt)
-{
- struct boot_param_header *bph = cxt->bph;
- char *p, *oldstr, *str, *endp;
- unsigned long ssize;
- int adj;
-
- if (!cxt->isordered)
- return; /* we haven't touched anything */
-
- /* adjust string offsets */
- oldstr = cxt->rgn[FT_STRINGS].start;
- adj = cxt->str_anchor - oldstr;
- if (adj)
- adjust_string_offsets(cxt, adj);
-
- /* make strings end on 8-byte boundary */
- ssize = cxt->rgn[FT_STRINGS].size;
- endp = (char *)_ALIGN((unsigned long)cxt->rgn[FT_STRUCT].start
- + cxt->rgn[FT_STRUCT].size + ssize, 8);
- str = endp - ssize;
-
- /* move strings down to end of structs */
- memmove(str, oldstr, ssize);
- cxt->str_anchor = str;
- cxt->rgn[FT_STRINGS].start = str;
-
- /* fill in header fields */
- p = (char *)bph;
- bph->totalsize = cpu_to_be32(endp - p);
- bph->off_mem_rsvmap = cpu_to_be32(cxt->rgn[FT_RSVMAP].start - p);
- bph->off_dt_struct = cpu_to_be32(cxt->rgn[FT_STRUCT].start - p);
- bph->off_dt_strings = cpu_to_be32(cxt->rgn[FT_STRINGS].start - p);
- bph->dt_strings_size = cpu_to_be32(ssize);
-}
-
-void *ft_find_device(struct ft_cxt *cxt, const void *top, const char *srch_path)
-{
- char *node;
-
- if (top) {
- node = ft_node_ph2node(cxt, top);
- if (node == NULL)
- return NULL;
- } else {
- node = ft_root_node(cxt);
- }
-
- node = ft_find_descendent(cxt, node, srch_path);
- return ft_get_phandle(cxt, node);
-}
-
-void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
-{
- struct ft_atom atom;
- char *p;
- const char *cp, *q;
- int cl;
- int depth = -1;
- int dmatch = 0;
- const char *path_comp[FT_MAX_DEPTH];
-
- cp = srch_path;
- cl = 0;
- p = top;
-
- while ((p = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- ++depth;
- if (depth != dmatch)
- break;
- cxt->genealogy[depth] = atom.data;
- cxt->genealogy[depth + 1] = NULL;
- if (depth && !(strncmp(atom.name, cp, cl) == 0
- && (atom.name[cl] == '/'
- || atom.name[cl] == '\0'
- || atom.name[cl] == '@')))
- break;
- path_comp[dmatch] = cp;
- /* it matches so far, advance to next path component */
- cp += cl;
- /* skip slashes */
- while (*cp == '/')
- ++cp;
- /* we're done if this is the end of the string */
- if (*cp == 0)
- return atom.data;
- /* look for end of this component */
- q = strchr(cp, '/');
- if (q)
- cl = q - cp;
- else
- cl = strlen(cp);
- ++dmatch;
- break;
- case OF_DT_END_NODE:
- if (depth == 0)
- return NULL;
- if (dmatch > depth) {
- --dmatch;
- cl = cp - path_comp[dmatch] - 1;
- cp = path_comp[dmatch];
- while (cl > 0 && cp[cl - 1] == '/')
- --cl;
- }
- --depth;
- break;
- }
- }
- return NULL;
-}
-
-void *__ft_get_parent(struct ft_cxt *cxt, void *node)
-{
- int d;
- struct ft_atom atom;
- char *p;
-
- for (d = 0; cxt->genealogy[d] != NULL; ++d)
- if (cxt->genealogy[d] == node)
- return d > 0 ? cxt->genealogy[d - 1] : NULL;
-
- /* have to do it the hard way... */
- p = ft_root_node(cxt);
- d = 0;
- while ((p = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- cxt->genealogy[d] = atom.data;
- if (node == atom.data) {
- /* found it */
- cxt->genealogy[d + 1] = NULL;
- return d > 0 ? cxt->genealogy[d - 1] : NULL;
- }
- ++d;
- break;
- case OF_DT_END_NODE:
- --d;
- break;
- }
- }
- return NULL;
-}
-
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
-{
- void *node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return NULL;
-
- node = __ft_get_parent(cxt, node);
- return ft_get_phandle(cxt, node);
-}
-
-static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
- const char *propname, unsigned int *len)
-{
- struct ft_atom atom;
- int depth = 0;
-
- while ((node = ft_next(cxt, node, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- ++depth;
- break;
-
- case OF_DT_PROP:
- if (depth != 1 || strcmp(atom.name, propname))
- break;
-
- if (len)
- *len = atom.size;
-
- return atom.data;
-
- case OF_DT_END_NODE:
- if (--depth <= 0)
- return NULL;
- }
- }
-
- return NULL;
-}
-
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- void *buf, const unsigned int buflen)
-{
- const void *data;
- unsigned int size;
-
- void *node = ft_node_ph2node(cxt, phandle);
- if (!node)
- return -1;
-
- data = __ft_get_prop(cxt, node, propname, &size);
- if (data) {
- unsigned int clipped_size = min(size, buflen);
- memcpy(buf, data, clipped_size);
- return size;
- }
-
- return -1;
-}
-
-void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
- const char *propname, const char *propval,
- unsigned int proplen)
-{
- struct ft_atom atom;
- char *p = ft_root_node(cxt);
- char *next;
- int past_prev = prev ? 0 : 1;
- int depth = -1;
-
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- const void *data;
- unsigned int size;
-
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- depth++;
-
- if (prev == p) {
- past_prev = 1;
- break;
- }
-
- if (!past_prev || depth < 1)
- break;
-
- data = __ft_get_prop(cxt, p, propname, &size);
- if (!data || size != proplen)
- break;
- if (memcmp(data, propval, size))
- break;
-
- return p;
-
- case OF_DT_END_NODE:
- if (depth-- == 0)
- return NULL;
-
- break;
- }
-
- p = next;
- }
-
- return NULL;
-}
-
-void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
- const char *propname, const char *propval,
- int proplen)
-{
- void *node = NULL;
-
- if (prev) {
- node = ft_node_ph2node(cxt, prev);
-
- if (!node)
- return NULL;
- }
-
- node = __ft_find_node_by_prop_value(cxt, node, propname,
- propval, proplen);
- return ft_get_phandle(cxt, node);
-}
-
-int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- const void *buf, const unsigned int buflen)
-{
- struct ft_atom atom;
- void *node;
- char *p, *next;
- int nextra;
-
- node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return -1;
-
- next = ft_next(cxt, node, &atom);
- if (atom.tag != OF_DT_BEGIN_NODE)
- /* phandle didn't point to a node */
- return -1;
- p = next;
-
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE: /* properties must go before subnodes */
- case OF_DT_END_NODE:
- /* haven't found the property, insert here */
- cxt->p = p;
- return ft_prop(cxt, propname, buf, buflen);
- case OF_DT_PROP:
- if (strcmp(atom.name, propname))
- break;
- /* found an existing property, overwrite it */
- nextra = _ALIGN(buflen, 4) - _ALIGN(atom.size, 4);
- cxt->p = atom.data;
- if (nextra && !ft_make_space(cxt, &cxt->p, FT_STRUCT,
- nextra))
- return -1;
- *(u32 *) (cxt->p - 8) = cpu_to_be32(buflen);
- ft_put_bin(cxt, buf, buflen);
- return 0;
- }
- p = next;
- }
- return -1;
-}
-
-int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
-{
- struct ft_atom atom;
- void *node;
- char *p, *next;
- int size;
-
- node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return -1;
-
- p = node;
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- case OF_DT_END_NODE:
- return -1;
- case OF_DT_PROP:
- if (strcmp(atom.name, propname))
- break;
- /* found the property, remove it */
- size = 12 + -_ALIGN(atom.size, 4);
- cxt->p = p;
- if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, -size))
- return -1;
- return 0;
- }
- p = next;
- }
- return -1;
-}
-
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
-{
- struct ft_atom atom;
- char *p, *next, *ret;
- int depth = 0;
-
- if (parent) {
- p = ft_node_ph2node(cxt, parent);
- if (!p)
- return NULL;
- } else {
- p = ft_root_node(cxt);
- }
-
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- ++depth;
- if (depth == 1 && strcmp(atom.name, name) == 0)
- /* duplicate node name, return error */
- return NULL;
- break;
- case OF_DT_END_NODE:
- --depth;
- if (depth > 0)
- break;
- /* end of node, insert here */
- cxt->p = p;
- ret = ft_begin_node(cxt, name);
- ft_end_node(cxt);
- return ft_get_phandle(cxt, ret);
- }
- p = next;
- }
- return NULL;
-}
-
-/* Returns the start of the path within the provided buffer, or NULL on
- * error.
- */
-char *ft_get_path(struct ft_cxt *cxt, const void *phandle,
- char *buf, int len)
-{
- const char *path_comp[FT_MAX_DEPTH];
- struct ft_atom atom;
- char *p, *next, *pos;
- int depth = 0, i;
- void *node;
-
- node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return NULL;
-
- p = ft_root_node(cxt);
-
- while ((next = ft_next(cxt, p, &atom)) != NULL) {
- switch (atom.tag) {
- case OF_DT_BEGIN_NODE:
- path_comp[depth++] = atom.name;
- if (p == node)
- goto found;
-
- break;
-
- case OF_DT_END_NODE:
- if (--depth == 0)
- return NULL;
- }
-
- p = next;
- }
-
-found:
- pos = buf;
- for (i = 1; i < depth; i++) {
- int this_len;
-
- if (len <= 1)
- return NULL;
-
- *pos++ = '/';
- len--;
-
- strncpy(pos, path_comp[i], len);
-
- if (pos[len - 1] != 0)
- return NULL;
-
- this_len = strlen(pos);
- len -= this_len;
- pos += this_len;
- }
-
- return buf;
-}
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
deleted file mode 100644
index b0957a2d967..00000000000
--- a/arch/powerpc/boot/flatdevtree.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef FLATDEVTREE_H
-#define FLATDEVTREE_H
-
-#include "flatdevtree_env.h"
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size, content */
-#define OF_DT_NOP 0x4 /* nop */
-#define OF_DT_END 0x9
-
-#define OF_DT_VERSION 0x10
-
-struct boot_param_header {
- u32 magic; /* magic word OF_DT_HEADER */
- u32 totalsize; /* total size of DT block */
- u32 off_dt_struct; /* offset to structure */
- u32 off_dt_strings; /* offset to strings */
- u32 off_mem_rsvmap; /* offset to memory reserve map */
- u32 version; /* format version */
- u32 last_comp_version; /* last compatible version */
- /* version 2 fields below */
- u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
- /* version 3 fields below */
- u32 dt_strings_size; /* size of the DT strings block */
-};
-
-struct ft_reserve {
- u64 start;
- u64 len;
-};
-
-struct ft_region {
- char *start;
- unsigned long size;
-};
-
-enum ft_rgn_id {
- FT_RSVMAP,
- FT_STRUCT,
- FT_STRINGS,
- FT_N_REGION
-};
-
-#define FT_MAX_DEPTH 50
-
-struct ft_cxt {
- struct boot_param_header *bph;
- int max_size; /* maximum size of tree */
- int isordered; /* everything in standard order */
- void *(*realloc)(void *, unsigned long);
- char *str_anchor;
- char *p; /* current insertion point in structs */
- struct ft_region rgn[FT_N_REGION];
- void *genealogy[FT_MAX_DEPTH+1];
- char **node_tbl;
- unsigned int node_max;
- unsigned int nodes_used;
-};
-
-char *ft_begin_node(struct ft_cxt *cxt, const char *name);
-void ft_end_node(struct ft_cxt *cxt);
-
-void ft_begin_tree(struct ft_cxt *cxt);
-void ft_end_tree(struct ft_cxt *cxt);
-
-void ft_nop(struct ft_cxt *cxt);
-int ft_prop(struct ft_cxt *cxt, const char *name,
- const void *data, unsigned int sz);
-int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str);
-int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val);
-void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size,
- void *(*realloc_fn)(void *, unsigned long));
-int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size,
- unsigned int max_find_device,
- void *(*realloc_fn)(void *, unsigned long));
-int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size);
-
-void ft_dump_blob(const void *bphp);
-void ft_merge_blob(struct ft_cxt *cxt, void *blob);
-void *ft_find_device(struct ft_cxt *cxt, const void *top,
- const char *srch_path);
-void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- void *buf, const unsigned int buflen);
-int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- const void *buf, const unsigned int buflen);
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle);
-void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
- const char *propname, const char *propval,
- int proplen);
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name);
-char *ft_get_path(struct ft_cxt *cxt, const void *phandle, char *buf, int len);
-
-#endif /* FLATDEVTREE_H */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
deleted file mode 100644
index b3670096fa7..00000000000
--- a/arch/powerpc/boot/flatdevtree_misc.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file does the necessary interface mapping between the bootwrapper
- * device tree operations and the interface provided by shared source
- * files flatdevicetree.[ch].
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <stddef.h>
-#include "flatdevtree.h"
-#include "ops.h"
-
-static struct ft_cxt cxt;
-
-static void *fdtm_finddevice(const char *name)
-{
- return ft_find_device(&cxt, NULL, name);
-}
-
-static int fdtm_getprop(const void *phandle, const char *propname,
- void *buf, const int buflen)
-{
- return ft_get_prop(&cxt, phandle, propname, buf, buflen);
-}
-
-static int fdtm_setprop(const void *phandle, const char *propname,
- const void *buf, const int buflen)
-{
- return ft_set_prop(&cxt, phandle, propname, buf, buflen);
-}
-
-static void *fdtm_get_parent(const void *phandle)
-{
- return ft_get_parent(&cxt, phandle);
-}
-
-static void *fdtm_create_node(const void *phandle, const char *name)
-{
- return ft_create_node(&cxt, phandle, name);
-}
-
-static void *fdtm_find_node_by_prop_value(const void *prev,
- const char *propname,
- const char *propval,
- int proplen)
-{
- return ft_find_node_by_prop_value(&cxt, prev, propname,
- propval, proplen);
-}
-
-static unsigned long fdtm_finalize(void)
-{
- ft_end_tree(&cxt);
- return (unsigned long)cxt.bph;
-}
-
-static char *fdtm_get_path(const void *phandle, char *buf, int len)
-{
- return ft_get_path(&cxt, phandle, buf, len);
-}
-
-int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
-{
- dt_ops.finddevice = fdtm_finddevice;
- dt_ops.getprop = fdtm_getprop;
- dt_ops.setprop = fdtm_setprop;
- dt_ops.get_parent = fdtm_get_parent;
- dt_ops.create_node = fdtm_create_node;
- dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value;
- dt_ops.finalize = fdtm_finalize;
- dt_ops.get_path = fdtm_get_path;
-
- return ft_open(&cxt, dt_blob, max_size, max_find_device,
- platform_ops.realloc);
-}
diff --git a/arch/powerpc/boot/holly.c b/arch/powerpc/boot/holly.c
index 199e783aea4..58013b92317 100644
--- a/arch/powerpc/boot/holly.c
+++ b/arch/powerpc/boot/holly.c
@@ -28,6 +28,6 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
u32 heapsize = 0x8000000 - (u32)_end; /* 128M */
simple_alloc_init(_end, heapsize, 32, 64);
- ft_init(_dtb_start, 0, 4);
+ fdt_init(_dtb_start);
serial_console_init();
}
diff --git a/arch/powerpc/boot/libfdt-wrapper.c b/arch/powerpc/boot/libfdt-wrapper.c
new file mode 100644
index 00000000000..002da16c97c
--- /dev/null
+++ b/arch/powerpc/boot/libfdt-wrapper.c
@@ -0,0 +1,182 @@
+/*
+ * This file does the necessary interface mapping between the bootwrapper
+ * device tree operations and the interface provided by shared source
+ * files flatdevicetree.[ch].
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <page.h>
+#include <libfdt.h>
+#include "ops.h"
+
+#define DEBUG 0
+#define BAD_ERROR(err) (((err) < 0) \
+ && ((err) != -FDT_ERR_NOTFOUND) \
+ && ((err) != -FDT_ERR_EXISTS))
+
+#define check_err(err) \
+ ({ \
+ if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \
+ printf("%s():%d %s\n\r", __FUNCTION__, __LINE__, \
+ fdt_strerror(err)); \
+ if (BAD_ERROR(err)) \
+ exit(); \
+ (err < 0) ? -1 : 0; \
+ })
+
+#define offset_devp(off) \
+ ({ \
+ int offset = (off); \
+ check_err(offset) ? NULL : (void *)(offset+1); \
+ })
+
+#define devp_offset(devp) (((int)(devp))-1)
+
+static void *fdt;
+static void *buf; /* = NULL */
+
+#define EXPAND_GRANULARITY 1024
+
+static void expand_buf(int minexpand)
+{
+ int size = fdt_totalsize(fdt);
+ int rc;
+
+ size = _ALIGN(size + minexpand, EXPAND_GRANULARITY);
+ buf = platform_ops.realloc(buf, size);
+ if (!buf)
+ fatal("Couldn't find %d bytes to expand device tree\n\r", size);
+ rc = fdt_open_into(fdt, buf, size);
+ if (rc != 0)
+ fatal("Couldn't expand fdt into new buffer: %s\n\r",
+ fdt_strerror(rc));
+
+ fdt = buf;
+}
+
+static void *fdt_wrapper_finddevice(const char *path)
+{
+ return offset_devp(fdt_path_offset(fdt, path));
+}
+
+static int fdt_wrapper_getprop(const void *devp, const char *name,
+ void *buf, const int buflen)
+{
+ const void *p;
+ int len;
+
+ p = fdt_getprop(fdt, devp_offset(devp), name, &len);
+ if (!p)
+ return check_err(len);
+ memcpy(buf, p, min(len, buflen));
+ return len;
+}
+
+static int fdt_wrapper_setprop(const void *devp, const char *name,
+ const void *buf, const int len)
+{
+ int rc;
+
+ rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
+ if (rc == -FDT_ERR_NOSPACE) {
+ expand_buf(len + 16);
+ rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len);
+ }
+
+ return check_err(rc);
+}
+
+static void *fdt_wrapper_get_parent(const void *devp)
+{
+ return offset_devp(fdt_parent_offset(fdt, devp_offset(devp)));
+}
+
+static void *fdt_wrapper_create_node(const void *devp, const char *name)
+{
+ int offset;
+
+ offset = fdt_add_subnode(fdt, devp_offset(devp), name);
+ if (offset == -FDT_ERR_NOSPACE) {
+ expand_buf(strlen(name) + 16);
+ offset = fdt_add_subnode(fdt, devp_offset(devp), name);
+ }
+
+ return offset_devp(offset);
+}
+
+static void *fdt_wrapper_find_node_by_prop_value(const void *prev,
+ const char *name,
+ const char *val,
+ int len)
+{
+ return offset_devp(fdt_node_offset_by_prop_value(fdt, devp_offset(prev),
+ name, val, len));
+}
+
+static char *fdt_wrapper_get_path(const void *devp, char *buf, int len)
+{
+ int rc;
+
+ rc = fdt_get_path(fdt, devp_offset(devp), buf, len);
+ if (check_err(rc))
+ return NULL;
+ return buf;
+}
+
+static unsigned long fdt_wrapper_finalize(void)
+{
+ int rc;
+
+ rc = fdt_pack(fdt);
+ if (rc != 0)
+ fatal("Couldn't pack flat tree: %s\n\r",
+ fdt_strerror(rc));
+ return (unsigned long)fdt;
+}
+
+void fdt_init(void *blob)
+{
+ int err;
+
+ dt_ops.finddevice = fdt_wrapper_finddevice;
+ dt_ops.getprop = fdt_wrapper_getprop;
+ dt_ops.setprop = fdt_wrapper_setprop;
+ dt_ops.get_parent = fdt_wrapper_get_parent;
+ dt_ops.create_node = fdt_wrapper_create_node;
+ dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value;
+ dt_ops.get_path = fdt_wrapper_get_path;
+ dt_ops.finalize = fdt_wrapper_finalize;
+
+ /* Make sure the dt blob is the right version and so forth */
+ fdt = blob;
+ err = fdt_open_into(fdt, fdt, fdt_totalsize(blob));
+ if (err == -FDT_ERR_NOSPACE) {
+ int bufsize = fdt_totalsize(fdt) + 4;
+ buf = malloc(bufsize);
+ err = fdt_open_into(fdt, buf, bufsize);
+ }
+
+ if (err != 0)
+ fatal("fdt_init(): %s\n\r", fdt_strerror(err));
+
+ if (buf)
+ fdt = buf;
+}
diff --git a/arch/powerpc/boot/libfdt/Makefile.libfdt b/arch/powerpc/boot/libfdt/Makefile.libfdt
new file mode 100644
index 00000000000..82f9c6a8287
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/Makefile.libfdt
@@ -0,0 +1,14 @@
+# Makefile.libfdt
+#
+# This is not a complete Makefile of itself. Instead, it is designed to
+# be easily embeddable into other systems of Makefiles.
+#
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
+LIBFDT_INCLUDES = fdt.h libfdt.h
+LIBFDT_EXTRA = libfdt_internal.h
+LIBFDT_LIB = libfdt/libfdt.a
+
+LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
+
+$(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
+
diff --git a/arch/powerpc/boot/libfdt/fdt.c b/arch/powerpc/boot/libfdt/fdt.c
new file mode 100644
index 00000000000..586a36136db
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt.c
@@ -0,0 +1,156 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+ if (fdt_magic(fdt) == FDT_MAGIC) {
+ /* Complete tree */
+ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+ return -FDT_ERR_BADVERSION;
+ } else if (fdt_magic(fdt) == SW_MAGIC) {
+ /* Unfinished sequential-write blob */
+ if (fdt_size_dt_struct(fdt) == 0)
+ return -FDT_ERR_BADSTATE;
+ } else {
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int len)
+{
+ const void *p;
+
+ if (fdt_version(fdt) >= 0x11)
+ if (((offset + len) < offset)
+ || ((offset + len) > fdt_size_dt_struct(fdt)))
+ return NULL;
+
+ p = _fdt_offset_ptr(fdt, offset);
+
+ if (p + len < p)
+ return NULL;
+ return p;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
+{
+ const uint32_t *tagp, *lenp;
+ uint32_t tag;
+ const char *p;
+
+ if (offset % FDT_TAGSIZE)
+ return -1;
+
+ tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+ if (! tagp)
+ return FDT_END; /* premature end */
+ tag = fdt32_to_cpu(*tagp);
+ offset += FDT_TAGSIZE;
+
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ /* skip name */
+ do {
+ p = fdt_offset_ptr(fdt, offset++, 1);
+ } while (p && (*p != '\0'));
+ if (! p)
+ return FDT_END;
+ break;
+ case FDT_PROP:
+ lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+ if (! lenp)
+ return FDT_END;
+ /* skip name offset, length and value */
+ offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
+ break;
+ }
+
+ if (nextoffset)
+ *nextoffset = ALIGN(offset, FDT_TAGSIZE);
+
+ return tag;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+ int len = strlen(s) + 1;
+ const char *last = strtab + tabsize - len;
+ const char *p;
+
+ for (p = strtab; p <= last; p++)
+ if (memeq(p, s, len))
+ return p;
+ return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+ int err = fdt_check_header(fdt);
+
+ if (err)
+ return err;
+
+ if (fdt_totalsize(fdt) > bufsize)
+ return -FDT_ERR_NOSPACE;
+
+ memmove(buf, fdt, fdt_totalsize(fdt));
+ return 0;
+}
diff --git a/arch/powerpc/boot/libfdt/fdt.h b/arch/powerpc/boot/libfdt/fdt.h
new file mode 100644
index 00000000000..48ccfd91000
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt.h
@@ -0,0 +1,60 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+ uint32_t magic; /* magic word FDT_MAGIC */
+ uint32_t totalsize; /* total size of DT block */
+ uint32_t off_dt_struct; /* offset to structure */
+ uint32_t off_dt_strings; /* offset to strings */
+ uint32_t off_mem_rsvmap; /* offset to memory reserve map */
+ uint32_t version; /* format version */
+ uint32_t last_comp_version; /* last compatible version */
+
+ /* version 2 fields below */
+ uint32_t boot_cpuid_phys; /* Which physical CPU id we're
+ booting on */
+ /* version 3 fields below */
+ uint32_t size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ uint32_t size_dt_struct; /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct fdt_node_header {
+ uint32_t tag;
+ char name[0];
+};
+
+struct fdt_property {
+ uint32_t tag;
+ uint32_t len;
+ uint32_t nameoff;
+ char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
+#define FDT_TAGSIZE sizeof(uint32_t)
+
+#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
+#define FDT_END_NODE 0x2 /* End node */
+#define FDT_PROP 0x3 /* Property: name off,
+ size, content */
+#define FDT_NOP 0x4 /* nop */
+#define FDT_END 0x9
+
+#define FDT_V1_SIZE (7*sizeof(uint32_t))
+#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
+#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
+#define FDT_V16_SIZE FDT_V3_SIZE
+#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
+
+#endif /* _FDT_H */
diff --git a/arch/powerpc/boot/libfdt/fdt_ro.c b/arch/powerpc/boot/libfdt/fdt_ro.c
new file mode 100644
index 00000000000..12a37d59f96
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt_ro.c
@@ -0,0 +1,583 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+#define CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static int nodename_eq(const void *fdt, int offset,
+ const char *s, int len)
+{
+ const char *p = fdt_offset_ptr(fdt, offset, len+1);
+
+ if (! p)
+ /* short match */
+ return 0;
+
+ if (memcmp(p, s, len) != 0)
+ return 0;
+
+ if (p[len] == '\0')
+ return 1;
+ else if (!memchr(s, '@', len) && (p[len] == '@'))
+ return 1;
+ else
+ return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+ return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+ CHECK_HEADER(fdt);
+ *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+ *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+ return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+ int i = 0;
+
+ while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+ i++;
+ return i;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ int level = 0;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ CHECK_HEADER(fdt);
+
+ tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADOFFSET;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_END:
+ return -FDT_ERR_TRUNCATED;
+
+ case FDT_BEGIN_NODE:
+ level++;
+ if (level != 1)
+ continue;
+ if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
+ /* Found it! */
+ return offset;
+ break;
+
+ case FDT_END_NODE:
+ level--;
+ break;
+
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (level >= 0);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+ const char *name)
+{
+ return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+ const char *end = path + strlen(path);
+ const char *p = path;
+ int offset = 0;
+
+ CHECK_HEADER(fdt);
+
+ if (*path != '/')
+ return -FDT_ERR_BADPATH;
+
+ while (*p) {
+ const char *q;
+
+ while (*p == '/')
+ p++;
+ if (! *p)
+ return offset;
+ q = strchr(p, '/');
+ if (! q)
+ q = end;
+
+ offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+ if (offset < 0)
+ return offset;
+
+ p = q;
+ }
+
+ return offset;
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+ const struct fdt_node_header *nh;
+ int err;
+
+ if ((err = fdt_check_header(fdt)) != 0)
+ goto fail;
+
+ err = -FDT_ERR_BADOFFSET;
+ nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
+ if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
+ goto fail;
+
+ if (len)
+ *len = strlen(nh->name);
+
+ return nh->name;
+
+ fail:
+ if (len)
+ *len = err;
+ return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+ int nodeoffset,
+ const char *name, int *lenp)
+{
+ uint32_t tag;
+ const struct fdt_property *prop;
+ int namestroff;
+ int offset, nextoffset;
+ int err;
+
+ if ((err = fdt_check_header(fdt)) != 0)
+ goto fail;
+
+ err = -FDT_ERR_BADOFFSET;
+ if (nodeoffset % FDT_TAGSIZE)
+ goto fail;
+
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ goto fail;
+
+ do {
+ offset = nextoffset;
+
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ err = -FDT_ERR_TRUNCATED;
+ goto fail;
+
+ case FDT_BEGIN_NODE:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ case FDT_PROP:
+ err = -FDT_ERR_BADSTRUCTURE;
+ prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+ if (! prop)
+ goto fail;
+ namestroff = fdt32_to_cpu(prop->nameoff);
+ if (streq(fdt_string(fdt, namestroff), name)) {
+ /* Found it! */
+ int len = fdt32_to_cpu(prop->len);
+ prop = fdt_offset_ptr(fdt, offset,
+ sizeof(*prop)+len);
+ if (! prop)
+ goto fail;
+
+ if (lenp)
+ *lenp = len;
+
+ return prop;
+ }
+ break;
+
+ default:
+ err = -FDT_ERR_BADSTRUCTURE;
+ goto fail;
+ }
+ } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
+
+ err = -FDT_ERR_NOTFOUND;
+ fail:
+ if (lenp)
+ *lenp = err;
+ return NULL;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property(fdt, nodeoffset, name, lenp);
+ if (! prop)
+ return NULL;
+
+ return prop->data;
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+ const uint32_t *php;
+ int len;
+
+ php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+ if (!php || (len != sizeof(*php)))
+ return 0;
+
+ return fdt32_to_cpu(*php);
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+ uint32_t tag;
+ int p = 0, overflow = 0;
+ int offset, nextoffset, namelen;
+ const char *name;
+
+ CHECK_HEADER(fdt);
+
+ tag = fdt_next_tag(fdt, 0, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (buflen < 2)
+ return -FDT_ERR_NOSPACE;
+ buf[0] = '/';
+ p = 1;
+
+ while (nextoffset <= nodeoffset) {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ return -FDT_ERR_BADOFFSET;
+
+ case FDT_BEGIN_NODE:
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if (overflow || ((p + namelen + 1) > buflen)) {
+ overflow++;
+ break;
+ }
+ memcpy(buf + p, name, namelen);
+ p += namelen;
+ buf[p++] = '/';
+ break;
+
+ case FDT_END_NODE:
+ if (overflow) {
+ overflow--;
+ break;
+ }
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ break;
+
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ }
+
+ if (overflow)
+ return -FDT_ERR_NOSPACE;
+
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return p;
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth)
+{
+ int level = -1;
+ uint32_t tag;
+ int offset, nextoffset = 0;
+ int supernodeoffset = -FDT_ERR_INTERNAL;
+
+ CHECK_HEADER(fdt);
+
+ if (supernodedepth < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ switch (tag) {
+ case FDT_END:
+ return -FDT_ERR_BADOFFSET;
+
+ case FDT_BEGIN_NODE:
+ level++;
+ if (level == supernodedepth)
+ supernodeoffset = offset;
+ break;
+
+ case FDT_END_NODE:
+ level--;
+ break;
+
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (offset < nodeoffset);
+
+ if (nodedepth)
+ *nodedepth = level;
+
+ if (supernodedepth > level)
+ return -FDT_ERR_NOTFOUND;
+ return supernodeoffset;
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+ int nodedepth;
+ int err;
+
+ err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+ if (err)
+ return (err < 0) ? err : -FDT_ERR_INTERNAL;
+ return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+ int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+ if (nodedepth < 0)
+ return nodedepth;
+ return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+ nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen)
+{
+ uint32_t tag;
+ int offset, nextoffset;
+ const void *val;
+ int len;
+
+ CHECK_HEADER(fdt);
+
+ if (startoffset >= 0) {
+ tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADOFFSET;
+ } else {
+ nextoffset = 0;
+ }
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_getprop(), then if that didn't
+ * find what we want, we scan over them again making our way
+ * to the next node. Still it's the easiest to implement
+ * approach; performance can come later. */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val
+ && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ break;
+
+ case FDT_PROP:
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_END);
+
+ return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+ if ((phandle == 0) || (phandle == -1))
+ return -FDT_ERR_BADPHANDLE;
+ phandle = cpu_to_fdt32(phandle);
+ return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
+ &phandle, sizeof(phandle));
+}
+
+int _stringlist_contains(const void *strlist, int listlen, const char *str)
+{
+ int len = strlen(str);
+ const void *p;
+
+ while (listlen >= len) {
+ if (memcmp(str, strlist, len+1) == 0)
+ return 1;
+ p = memchr(strlist, '\0', listlen);
+ if (!p)
+ return 0; /* malformed strlist.. */
+ listlen -= (p-strlist) + 1;
+ strlist = p + 1;
+ }
+ return 0;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible)
+{
+ const void *prop;
+ int len;
+
+ prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+ if (!prop)
+ return len;
+ if (_stringlist_contains(prop, len, compatible))
+ return 0;
+ else
+ return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible)
+{
+ uint32_t tag;
+ int offset, nextoffset;
+ int err;
+
+ CHECK_HEADER(fdt);
+
+ if (startoffset >= 0) {
+ tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADOFFSET;
+ } else {
+ nextoffset = 0;
+ }
+
+ /* FIXME: The algorithm here is pretty horrible: we scan each
+ * property of a node in fdt_node_check_compatible(), then if
+ * that didn't find what we want, we scan over them again
+ * making our way to the next node. Still it's the easiest to
+ * implement approach; performance can come later. */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ err = fdt_node_check_compatible(fdt, offset,
+ compatible);
+ if ((err < 0)
+ && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ break;
+
+ case FDT_PROP:
+ case FDT_END:
+ case FDT_END_NODE:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_END);
+
+ return -FDT_ERR_NOTFOUND;
+}
diff --git a/arch/powerpc/boot/libfdt/fdt_rw.c b/arch/powerpc/boot/libfdt/fdt_rw.c
new file mode 100644
index 00000000000..6673f8ec962
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt_rw.c
@@ -0,0 +1,447 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _blocks_misordered(const void *fdt,
+ int mem_rsv_size, int struct_size)
+{
+ return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
+ || (fdt_off_dt_struct(fdt) <
+ (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+ || (fdt_off_dt_strings(fdt) <
+ (fdt_off_dt_struct(fdt) + struct_size))
+ || (fdt_totalsize(fdt) <
+ (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int rw_check_header(void *fdt)
+{
+ int err;
+
+ if ((err = fdt_check_header(fdt)))
+ return err;
+ if (fdt_version(fdt) < 17)
+ return -FDT_ERR_BADVERSION;
+ if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
+ return -FDT_ERR_BADLAYOUT;
+ if (fdt_version(fdt) > 17)
+ fdt_set_version(fdt, 17);
+
+ return 0;
+}
+
+#define RW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = rw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static inline int _blob_data_size(void *fdt)
+{
+ return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
+{
+ void *end = fdt + _blob_data_size(fdt);
+
+ if (((p + oldlen) < p) || ((p + oldlen) > end))
+ return -FDT_ERR_BADOFFSET;
+ if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
+ return -FDT_ERR_NOSPACE;
+ memmove(p + newlen, p + oldlen, end - p - oldlen);
+ return 0;
+}
+
+static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
+{
+ int delta = (newn - oldn) * sizeof(*p);
+ int err;
+ err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ if (err)
+ return err;
+ fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _blob_splice_struct(void *fdt, void *p,
+ int oldlen, int newlen)
+{
+ int delta = newlen - oldlen;
+ int err;
+
+ if ((err = _blob_splice(fdt, p, oldlen, newlen)))
+ return err;
+
+ fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+ fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+ return 0;
+}
+
+static int _blob_splice_string(void *fdt, int newlen)
+{
+ void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ int err;
+
+ if ((err = _blob_splice(fdt, p, 0, newlen)))
+ return err;
+
+ fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+ return 0;
+}
+
+static int _find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+ const char *p;
+ char *new;
+ int len = strlen(s) + 1;
+ int err;
+
+ p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+ if (p)
+ /* found it */
+ return (p - strtab);
+
+ new = strtab + fdt_size_dt_strings(fdt);
+ err = _blob_splice_string(fdt, len);
+ if (err)
+ return err;
+
+ memcpy(new, s, len);
+ return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err;
+
+ if ((err = rw_check_header(fdt)))
+ return err;
+
+ re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+ err = _blob_splice_mem_rsv(fdt, re, 0, 1);
+ if (err)
+ return err;
+
+ re->address = cpu_to_fdt64(address);
+ re->size = cpu_to_fdt64(size);
+ return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+ struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+ int err;
+
+ if ((err = rw_check_header(fdt)))
+ return err;
+ if (n >= fdt_num_mem_rsv(fdt))
+ return -FDT_ERR_NOTFOUND;
+
+ err = _blob_splice_mem_rsv(fdt, re, 1, 0);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
+ struct fdt_property **prop)
+{
+ int oldlen;
+ int err;
+
+ *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+ if (! (*prop))
+ return oldlen;
+
+ if ((err = _blob_splice_struct(fdt, (*prop)->data,
+ ALIGN(oldlen, FDT_TAGSIZE),
+ ALIGN(len, FDT_TAGSIZE))))
+ return err;
+
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
+ struct fdt_property **prop)
+{
+ uint32_t tag;
+ int proplen;
+ int nextoffset;
+ int namestroff;
+ int err;
+
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADOFFSET;
+
+ namestroff = _find_add_string(fdt, name);
+ if (namestroff < 0)
+ return namestroff;
+
+ *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+ proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
+
+ err = _blob_splice_struct(fdt, *prop, 0, proplen);
+ if (err)
+ return err;
+
+ (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+ (*prop)->nameoff = cpu_to_fdt32(namestroff);
+ (*prop)->len = cpu_to_fdt32(len);
+ return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err;
+
+ if ((err = rw_check_header(fdt)))
+ return err;
+
+ err = _resize_property(fdt, nodeoffset, name, len, &prop);
+ if (err == -FDT_ERR_NOTFOUND)
+ err = _add_property(fdt, nodeoffset, name, len, &prop);
+ if (err)
+ return err;
+
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len, proplen;
+
+ RW_CHECK_HEADER(fdt);
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
+ return _blob_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen)
+{
+ struct fdt_node_header *nh;
+ int offset, nextoffset;
+ int nodelen;
+ int err;
+ uint32_t tag;
+ uint32_t *endtag;
+
+ RW_CHECK_HEADER(fdt);
+
+ offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+ if (offset >= 0)
+ return -FDT_ERR_EXISTS;
+ else if (offset != -FDT_ERR_NOTFOUND)
+ return offset;
+
+ /* Try to place the new node after the parent's properties */
+ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+ } while (tag == FDT_PROP);
+
+ nh = _fdt_offset_ptr_w(fdt, offset);
+ nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
+
+ err = _blob_splice_struct(fdt, nh, 0, nodelen);
+ if (err)
+ return err;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
+ memcpy(nh->name, name, namelen);
+ endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
+ *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+ return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+ return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ RW_CHECK_HEADER(fdt);
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
+}
+
+static void _packblocks(const void *fdt, void *buf,
+ int mem_rsv_size, int struct_size)
+{
+ int mem_rsv_off, struct_off, strings_off;
+
+ mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
+ struct_off = mem_rsv_off + mem_rsv_size;
+ strings_off = struct_off + struct_size;
+
+ memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
+
+ memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
+ fdt_set_off_dt_struct(buf, struct_off);
+ fdt_set_size_dt_struct(buf, struct_size);
+
+ memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
+ fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(buf, strings_off);
+ fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+ int err;
+ int mem_rsv_size, struct_size;
+ int newsize;
+ void *tmp;
+
+ err = fdt_check_header(fdt);
+ if (err)
+ return err;
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+
+ if (fdt_version(fdt) >= 17) {
+ struct_size = fdt_size_dt_struct(fdt);
+ } else {
+ struct_size = 0;
+ while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+ ;
+ }
+
+ if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ /* no further work necessary */
+ err = fdt_move(fdt, buf, bufsize);
+ if (err)
+ return err;
+ fdt_set_version(buf, 17);
+ fdt_set_size_dt_struct(buf, struct_size);
+ fdt_set_totalsize(buf, bufsize);
+ return 0;
+ }
+
+ /* Need to reorder */
+ newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ + struct_size + fdt_size_dt_strings(fdt);
+
+ if (bufsize < newsize)
+ return -FDT_ERR_NOSPACE;
+
+ if (((buf + newsize) <= fdt)
+ || (buf >= (fdt + fdt_totalsize(fdt)))) {
+ tmp = buf;
+ } else {
+ tmp = (void *)fdt + fdt_totalsize(fdt);
+ if ((tmp + newsize) > (buf + bufsize))
+ return -FDT_ERR_NOSPACE;
+ }
+
+ _packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ memmove(buf, tmp, newsize);
+
+ fdt_set_magic(buf, FDT_MAGIC);
+ fdt_set_totalsize(buf, bufsize);
+ fdt_set_version(buf, 17);
+ fdt_set_last_comp_version(buf, 16);
+ fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+ return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+ int mem_rsv_size;
+ int err;
+
+ err = rw_check_header(fdt);
+ if (err)
+ return err;
+
+ mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+ * sizeof(struct fdt_reserve_entry);
+ _packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, _blob_data_size(fdt));
+
+ return 0;
+}
diff --git a/arch/powerpc/boot/libfdt/fdt_strerror.c b/arch/powerpc/boot/libfdt/fdt_strerror.c
new file mode 100644
index 00000000000..f9d32ef5360
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt_strerror.c
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct errtabent {
+ const char *str;
+};
+
+#define ERRTABENT(val) \
+ [(val)] = { .str = #val, }
+
+static struct errtabent errtable[] = {
+ ERRTABENT(FDT_ERR_NOTFOUND),
+ ERRTABENT(FDT_ERR_EXISTS),
+ ERRTABENT(FDT_ERR_NOSPACE),
+
+ ERRTABENT(FDT_ERR_BADOFFSET),
+ ERRTABENT(FDT_ERR_BADPATH),
+ ERRTABENT(FDT_ERR_BADSTATE),
+
+ ERRTABENT(FDT_ERR_TRUNCATED),
+ ERRTABENT(FDT_ERR_BADMAGIC),
+ ERRTABENT(FDT_ERR_BADVERSION),
+ ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+ if (errval > 0)
+ return "<valid offset/length>";
+ else if (errval == 0)
+ return "<no error>";
+ else if (errval > -ERRTABSIZE) {
+ const char *s = errtable[-errval].str;
+
+ if (s)
+ return s;
+ }
+
+ return "<unknown error>";
+}
diff --git a/arch/powerpc/boot/libfdt/fdt_sw.c b/arch/powerpc/boot/libfdt/fdt_sw.c
new file mode 100644
index 00000000000..dda2de34b2e
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt_sw.c
@@ -0,0 +1,258 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int check_header_sw(void *fdt)
+{
+ if (fdt_magic(fdt) != SW_MAGIC)
+ return -FDT_ERR_BADMAGIC;
+ return 0;
+}
+
+static void *grab_space(void *fdt, int len)
+{
+ int offset = fdt_size_dt_struct(fdt);
+ int spaceleft;
+
+ spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+ - fdt_size_dt_strings(fdt);
+
+ if ((offset + len < offset) || (offset + len > spaceleft))
+ return NULL;
+
+ fdt_set_size_dt_struct(fdt, offset + len);
+ return fdt_offset_ptr_w(fdt, offset, len);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+ void *fdt = buf;
+
+ if (bufsize < sizeof(struct fdt_header))
+ return -FDT_ERR_NOSPACE;
+
+ memset(buf, 0, bufsize);
+
+ fdt_set_magic(fdt, SW_MAGIC);
+ fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+ fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+ fdt_set_totalsize(fdt, bufsize);
+
+ fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+ fdt_set_off_dt_strings(fdt, bufsize);
+
+ return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+ struct fdt_reserve_entry *re;
+ int err = check_header_sw(fdt);
+ int offset;
+
+ if (err)
+ return err;
+ if (fdt_size_dt_struct(fdt))
+ return -FDT_ERR_BADSTATE;
+
+ offset = fdt_off_dt_struct(fdt);
+ if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+ return -FDT_ERR_NOSPACE;
+
+ re = (struct fdt_reserve_entry *)(fdt + offset);
+ re->address = cpu_to_fdt64(addr);
+ re->size = cpu_to_fdt64(size);
+
+ fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+ return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+ return fdt_add_reservemap_entry(fdt, 0, 0);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+ struct fdt_node_header *nh;
+ int err = check_header_sw(fdt);
+ int namelen = strlen(name) + 1;
+
+ if (err)
+ return err;
+
+ nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
+ if (! nh)
+ return -FDT_ERR_NOSPACE;
+
+ nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+ memcpy(nh->name, name, namelen);
+ return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+ uint32_t *en;
+ int err = check_header_sw(fdt);
+
+ if (err)
+ return err;
+
+ en = grab_space(fdt, FDT_TAGSIZE);
+ if (! en)
+ return -FDT_ERR_NOSPACE;
+
+ *en = cpu_to_fdt32(FDT_END_NODE);
+ return 0;
+}
+
+static int find_add_string(void *fdt, const char *s)
+{
+ char *strtab = (char *)fdt + fdt_totalsize(fdt);
+ const char *p;
+ int strtabsize = fdt_size_dt_strings(fdt);
+ int len = strlen(s) + 1;
+ int struct_top, offset;
+
+ p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+ if (p)
+ return p - strtab;
+
+ /* Add it */
+ offset = -strtabsize - len;
+ struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ if (fdt_totalsize(fdt) + offset < struct_top)
+ return 0; /* no more room :( */
+
+ memcpy(strtab + offset, s, len);
+ fdt_set_size_dt_strings(fdt, strtabsize + len);
+ return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+ struct fdt_property *prop;
+ int err = check_header_sw(fdt);
+ int nameoff;
+
+ if (err)
+ return err;
+
+ nameoff = find_add_string(fdt, name);
+ if (nameoff == 0)
+ return -FDT_ERR_NOSPACE;
+
+ prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
+ if (! prop)
+ return -FDT_ERR_NOSPACE;
+
+ prop->tag = cpu_to_fdt32(FDT_PROP);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ prop->len = cpu_to_fdt32(len);
+ memcpy(prop->data, val, len);
+ return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+ int err = check_header_sw(fdt);
+ char *p = (char *)fdt;
+ uint32_t *end;
+ int oldstroffset, newstroffset;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ if (err)
+ return err;
+
+ /* Add terminator */
+ end = grab_space(fdt, sizeof(*end));
+ if (! end)
+ return -FDT_ERR_NOSPACE;
+ *end = cpu_to_fdt32(FDT_END);
+
+ /* Relocate the string table */
+ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+ newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+ memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+ fdt_set_off_dt_strings(fdt, newstroffset);
+
+ /* Walk the structure, correcting string offsets */
+ offset = 0;
+ while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+ if (tag == FDT_PROP) {
+ struct fdt_property *prop =
+ fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
+ int nameoff;
+
+ if (! prop)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ nameoff = fdt32_to_cpu(prop->nameoff);
+ nameoff += fdt_size_dt_strings(fdt);
+ prop->nameoff = cpu_to_fdt32(nameoff);
+ }
+ offset = nextoffset;
+ }
+
+ /* Finally, adjust the header */
+ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+ fdt_set_magic(fdt, FDT_MAGIC);
+ return 0;
+}
diff --git a/arch/powerpc/boot/libfdt/fdt_wip.c b/arch/powerpc/boot/libfdt/fdt_wip.c
new file mode 100644
index 00000000000..88e24b8318f
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/fdt_wip.c
@@ -0,0 +1,144 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len)
+{
+ void *propval;
+ int proplen;
+
+ propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+ if (! propval)
+ return proplen;
+
+ if (proplen != len)
+ return -FDT_ERR_NOSPACE;
+
+ memcpy(propval, val, len);
+ return 0;
+}
+
+static void nop_region(void *start, int len)
+{
+ uint32_t *p;
+
+ for (p = start; (void *)p < (start + len); p++)
+ *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+ struct fdt_property *prop;
+ int len;
+
+ prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+ if (! prop)
+ return len;
+
+ nop_region(prop, len + sizeof(*prop));
+
+ return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int nodeoffset)
+{
+ int level = 0;
+ uint32_t tag;
+ int offset, nextoffset;
+
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ if (tag != FDT_BEGIN_NODE)
+ return -FDT_ERR_BADOFFSET;
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_END:
+ return offset;
+
+ case FDT_BEGIN_NODE:
+ level++;
+ break;
+
+ case FDT_END_NODE:
+ level--;
+ break;
+
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (level >= 0);
+
+ return nextoffset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+ int endoffset;
+
+ endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+ if (endoffset < 0)
+ return endoffset;
+
+ nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
+ return 0;
+}
diff --git a/arch/powerpc/boot/libfdt/libfdt.h b/arch/powerpc/boot/libfdt/libfdt.h
new file mode 100644
index 00000000000..6b2fb92ea35
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/libfdt.h
@@ -0,0 +1,721 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION 0x10
+#define FDT_LAST_SUPPORTED_VERSION 0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND 1
+ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS 2
+ /* FDT_ERR_EXISTS: Attemped to create a node or property which
+ * already exists */
+#define FDT_ERR_NOSPACE 3
+ /* FDT_ERR_NOSPACE: Operation needed to expand the device
+ * tree, but its buffer did not have sufficient space to
+ * contain the expanded tree. Use fdt_open_into() to move the
+ * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET 4
+ /* FDT_ERR_BADOFFSET: Function was passed a structure block
+ * offset which is out-of-bounds, or which points to an
+ * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH 5
+ /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an
+ * absolute path) */
+#define FDT_ERR_BADPHANDLE 6
+ /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+ * value. phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE 7
+ /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+ * tree created by the sequential-write functions, which is
+ * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED 8
+ /* FDT_ERR_TRUNCATED: Structure block of the given device tree
+ * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC 9
+ /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+ * device tree at all - it is missing the flattened device
+ * tree magic number. */
+#define FDT_ERR_BADVERSION 10
+ /* FDT_ERR_BADVERSION: Given device tree has a version which
+ * can't be handled by the requested operation. For
+ * read-write functions, this may mean that fdt_open_into() is
+ * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE 11
+ /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+ * structure block or other serious error (e.g. misnested
+ * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT 12
+ /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+ * device tree has it's sub-blocks in an order that the
+ * function can't handle (memory reserve map, then structure,
+ * then strings). Use fdt_open_into() to reorganize the tree
+ * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL 13
+ /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+ * Should never be returned, if it is, it indicates a bug in
+ * libfdt itself. */
+
+#define FDT_ERR_MAX 13
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these) */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+ return (void *)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* General functions */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt) (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+ static inline void fdt_set_##name(void *fdt, uint32_t val) \
+ { \
+ struct fdt_header *fdth = fdt; \
+ fdth->name = cpu_to_fdt32(val); \
+ }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ * 0, if the buffer appears to contain a valid device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize. The buffer may overlap
+ * with the existing device tree blob at fdt. Therefore,
+ * fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions */
+/**********************************************************************/
+
+/**
+ * fdt_string - retreive a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ * a pointer to the string, on success
+ * NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retreive the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map. This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ * the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retreive one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name. This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+ const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name. name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ * structure block offset of the requested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ * structure block offset of the node with the requested path (>=0), on success
+ * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ * -FDT_ERR_NOTFOUND, if the requested node does not exist
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retreive the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset. If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ * pointer to the node's name, on success
+ * If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ * NULL, on error
+ * if lenp is non-NULL *lenp contains an error code (<0):
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset. If lenp is
+ * non-NULL, the length of the property value also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the structure representing the property
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+ const char *name,
+ int *lenp)
+{
+ return (struct fdt_property *)fdt_get_property(fdt, nodeoffset,
+ name, lenp);
+}
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ * pointer to the property's value
+ * if lenp is non-NULL, *lenp contains the length of the property
+ * value (>=0)
+ * NULL, on error
+ * if lenp is non-NULL, *lenp contains an error code (<0):
+ * -FDT_ERR_NOTFOUND, node does not have named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+ const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+ const char *name, int *lenp)
+{
+ return (void *)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retreive the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ * the phandle of the node at nodeoffset, on succes (!= 0, != -1)
+ * 0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * 0, on success
+ * buf contains the absolute path of the node at
+ * nodeoffset, as a NUL-terminated string.
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ * characters and will not fit in the given buffer.
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth). So
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node. If the node at
+ * nodeoffset has depth D, then:
+ * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ * structure block offset of the node at node offset's ancestor
+ * of depth supernodedepth (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+ int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node. The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ * depth of the node at nodeoffset (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ * stucture block offset of the parent of the node at nodeoffset
+ * (>=0), on success
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ * propval, proplen);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ * propval, proplen);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+ const char *propname,
+ const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the node
+ * which has the given phandle value. If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0), on success
+ * -FDT_ERR_NOTFOUND, no node with that phandle exists
+ * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ * 0, if the node has a 'compatible' property listing the given string
+ * 1, if the node has a 'compatible' property, but it does not list
+ * the given string
+ * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+ const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ * offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ * while (offset != -FDT_ERR_NOTFOUND) {
+ * // other code here
+ * offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ * }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ * structure block offset of the located node (>= 0, >startoffset),
+ * on success
+ * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ * tree after startoffset
+ * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+ const char *compatible);
+
+/**********************************************************************/
+/* Write-in-place functions */
+/**********************************************************************/
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+ const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_property(fdt, name, &val, sizeof(val));
+}
+#define fdt_property_string(fdt, name, str) \
+ fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions */
+/**********************************************************************/
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+int fdt_del_mem_rsv(void *fdt, int n);
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+ const void *val, int len);
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+ uint32_t val)
+{
+ val = cpu_to_fdt32(val);
+ return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
+}
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+ const char *name, int namelen);
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/arch/powerpc/boot/libfdt/libfdt_internal.h b/arch/powerpc/boot/libfdt/libfdt_internal.h
new file mode 100644
index 00000000000..1e60936beb5
--- /dev/null
+++ b/arch/powerpc/boot/libfdt/libfdt_internal.h
@@ -0,0 +1,89 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ * b) Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
+
+#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
+#define streq(p, q) (strcmp((p), (q)) == 0)
+
+uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+ return fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+ return (void *)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+ const struct fdt_reserve_entry *rsv_table =
+ fdt + fdt_off_mem_rsvmap(fdt);
+
+ return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+ return (void *)_fdt_mem_rsv(fdt, n);
+}
+
+#define SW_MAGIC (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/arch/powerpc/boot/libfdt_env.h b/arch/powerpc/boot/libfdt_env.h
new file mode 100644
index 00000000000..a4b0fc959ec
--- /dev/null
+++ b/arch/powerpc/boot/libfdt_env.h
@@ -0,0 +1,17 @@
+#ifndef _ARCH_POWERPC_BOOT_LIBFDT_ENV_H
+#define _ARCH_POWERPC_BOOT_LIBFDT_ENV_H
+
+#include <types.h>
+#include <string.h>
+
+typedef u32 uint32_t;
+typedef u64 uint64_t;
+
+#define fdt16_to_cpu(x) (x)
+#define cpu_to_fdt16(x) (x)
+#define fdt32_to_cpu(x) (x)
+#define cpu_to_fdt32(x) (x)
+#define fdt64_to_cpu(x) (x)
+#define cpu_to_fdt64(x) (x)
+
+#endif /* _ARCH_POWERPC_BOOT_LIBFDT_ENV_H */
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 1b496b37eca..9e7f3ddd991 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -16,7 +16,6 @@
#include "stdio.h"
#include "ops.h"
#include "gunzip_util.h"
-#include "flatdevtree.h"
#include "reg.h"
static struct gunzip_state gzstate;
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index a180b6505f4..6036a98e646 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -79,7 +79,7 @@ struct loader_info {
extern struct loader_info loader_info;
void start(void);
-int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
+void fdt_init(void *blob);
int serial_console_init(void);
int ns16550_console_init(void *devp, struct serial_console_data *scdp);
int mpsc_console_init(void *devp, struct serial_console_data *scdp);
diff --git a/arch/powerpc/boot/prpmc2800.c b/arch/powerpc/boot/prpmc2800.c
index 9614e1db9da..05c3245b30d 100644
--- a/arch/powerpc/boot/prpmc2800.c
+++ b/arch/powerpc/boot/prpmc2800.c
@@ -547,8 +547,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
if (!dtb)
exit();
memmove(dtb, _dtb_start, dt_size);
- if (ft_init(dtb, dt_size, 16))
- exit();
+ fdt_init(dtb);
bridge_base = mv64x60_get_bridge_base();
diff --git a/arch/powerpc/boot/ps3.c b/arch/powerpc/boot/ps3.c
index d6661151b49..3b0ac4d006e 100644
--- a/arch/powerpc/boot/ps3.c
+++ b/arch/powerpc/boot/ps3.c
@@ -131,7 +131,7 @@ void platform_init(void)
printf("\n-- PS3 bootwrapper --\n");
simple_alloc_init(_end, heapsize, 32, 64);
- ft_init(_dtb_start, 0, 4);
+ fdt_init(_dtb_start);
chosen = finddevice("/chosen");
diff --git a/arch/powerpc/boot/treeboot-walnut.c b/arch/powerpc/boot/treeboot-walnut.c
index bb2c309d70f..70ffce343c0 100644
--- a/arch/powerpc/boot/treeboot-walnut.c
+++ b/arch/powerpc/boot/treeboot-walnut.c
@@ -128,6 +128,6 @@ void platform_init(void)
simple_alloc_init(_end, avail_ram, 32, 32);
platform_ops.fixups = walnut_fixups;
platform_ops.exit = ibm40x_dbcr_reset;
- ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ fdt_init(_dtb_start);
serial_console_init();
}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 31147a03772..a591ced4787 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -45,6 +45,7 @@ CROSS=
# directory for object and other files used by this script
object=arch/powerpc/boot
+objbin=$object
# directory for working files
tmpdir=.
@@ -95,6 +96,7 @@ while [ "$#" -gt 0 ]; do
shift
[ "$#" -gt 0 ] || usage
object="$1"
+ objbin="$1"
;;
-W)
shift
@@ -116,6 +118,9 @@ while [ "$#" -gt 0 ]; do
done
if [ -n "$dts" ]; then
+ if [ ! -r "$dts" -a -r "$object/dts/$dts" ]; then
+ dts="$object/dts/$dts"
+ fi
if [ -z "$dtb" ]; then
dtb="$platform.dtb"
fi
@@ -246,11 +251,11 @@ fi
# post-processing needed for some platforms
case "$platform" in
pseries|chrp)
- $object/addnote "$ofile"
+ $objbin/addnote "$ofile"
;;
coff)
${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
- $object/hack-coff "$ofile"
+ $objbin/hack-coff "$ofile"
;;
cuboot*)
gzip -f -9 "$ofile"
@@ -259,7 +264,7 @@ cuboot*)
;;
treeboot*)
mv "$ofile" "$ofile.elf"
- $object/mktree "$ofile.elf" "$ofile" "$base" "$entry"
+ $objbin/mktree "$ofile.elf" "$ofile" "$base" "$entry"
if [ -z "$cacheit" ]; then
rm -f "$ofile.elf"
fi
@@ -287,8 +292,6 @@ ps3)
overlay_dest="256"
overlay_size="256"
- rm -f "$object/otheros.bld"
-
${CROSS}objcopy -O binary "$ofile" "$ofile.bin"
dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \
@@ -299,6 +302,8 @@ ps3)
skip=$system_reset_overlay seek=$overlay_dest \
count=$overlay_size bs=1
- gzip --force -9 --stdout "$ofile.bin" > "$object/otheros.bld"
+ odir="$(dirname "$ofile.bin")"
+ rm -f "$odir/otheros.bld"
+ gzip --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld"
;;
esac
diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig
index 421e08ee857..9ed2e098f96 100644
--- a/arch/powerpc/configs/celleb_defconfig
+++ b/arch/powerpc/configs/celleb_defconfig
@@ -50,7 +50,8 @@ CONFIG_AUDIT_ARCH=y
CONFIG_GENERIC_BUG=y
# CONFIG_DEFAULT_UIMAGE is not set
# CONFIG_PPC_DCR_NATIVE is not set
-# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR_MMIO=y
+CONFIG_PPC_DCR=y
CONFIG_PPC_OF_PLATFORM_PCI=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -148,7 +149,7 @@ CONFIG_PPC_MULTIPLATFORM=y
CONFIG_PPC_CELLEB=y
# CONFIG_PPC_PS3 is not set
CONFIG_PPC_CELL=y
-# CONFIG_PPC_CELL_NATIVE is not set
+CONFIG_PPC_CELL_NATIVE=y
# CONFIG_PPC_IBM_CELL_BLADE is not set
#
@@ -157,13 +158,19 @@ CONFIG_PPC_CELL=y
CONFIG_SPU_FS=y
CONFIG_SPU_FS_64K_LS=y
CONFIG_SPU_BASE=y
+CONFIG_CBE_RAS=y
+# CONFIG_CBE_THERM is not set
# CONFIG_PQ2ADS is not set
+CONFIG_PPC_NATIVE=y
+CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_PPC_UDBG_BEAT=y
-# CONFIG_MPIC is not set
+CONFIG_MPIC=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
# CONFIG_U3_DART is not set
-# CONFIG_PPC_RTAS is not set
+CONFIG_PPC_RTAS=y
+# CONFIG_RTAS_ERROR_LOGGING is not set
+# CONFIG_RTAS_PROC is not set
# CONFIG_MMIO_NVRAM is not set
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
@@ -593,10 +600,11 @@ CONFIG_MII=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
-# CONFIG_IBM_NEW_EMAC_ZMII is not set
-# CONFIG_IBM_NEW_EMAC_RGMII is not set
-# CONFIG_IBM_NEW_EMAC_TAH is not set
-# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+CONFIG_IBM_NEW_EMAC_RGMII=y
+CONFIG_IBM_NEW_EMAC_TAH=y
+CONFIG_IBM_NEW_EMAC_EMAC4=y
# CONFIG_NET_PCI is not set
# CONFIG_B44 is not set
CONFIG_NETDEV_1000=y
@@ -741,6 +749,7 @@ CONFIG_SERIAL_TXX9_CONSOLE=y
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_HVC_DRIVER=y
+CONFIG_HVC_RTAS=y
CONFIG_HVC_BEAT=y
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
@@ -822,6 +831,7 @@ CONFIG_WATCHDOG=y
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_WATCHDOG_RTAS is not set
#
# PCI-based Watchdog Cards
@@ -1245,17 +1255,7 @@ CONFIG_XMON_DISASSEMBLY=y
CONFIG_IRQSTACKS=y
# CONFIG_VIRQ_DEBUG is not set
# CONFIG_BOOTX_TEXT is not set
-CONFIG_PPC_EARLY_DEBUG=y
-# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
-# CONFIG_PPC_EARLY_DEBUG_G5 is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
-# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
-# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
-# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
-CONFIG_PPC_EARLY_DEBUG_BEAT=y
-# CONFIG_PPC_EARLY_DEBUG_44x is not set
-# CONFIG_PPC_EARLY_DEBUG_CPM is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 2d0c9ef555e..47c3fe55242 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -526,16 +526,14 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
return tbl;
}
-void iommu_free_table(struct device_node *dn)
+void iommu_free_table(struct iommu_table *tbl, const char *node_name)
{
- struct pci_dn *pdn = dn->data;
- struct iommu_table *tbl = pdn->iommu_table;
unsigned long bitmap_sz, i;
unsigned int order;
if (!tbl || !tbl->it_map) {
printk(KERN_ERR "%s: expected TCE map for %s\n", __FUNCTION__,
- dn->full_name);
+ node_name);
return;
}
@@ -544,7 +542,7 @@ void iommu_free_table(struct device_node *dn)
for (i = 0; i < (tbl->it_size/64); i++) {
if (tbl->it_map[i] != 0) {
printk(KERN_WARNING "%s: Unexpected TCEs for %s\n",
- __FUNCTION__, dn->full_name);
+ __FUNCTION__, node_name);
break;
}
}
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c
index f0f49d1be3d..ee172aa42aa 100644
--- a/arch/powerpc/kernel/isa-bridge.c
+++ b/arch/powerpc/kernel/isa-bridge.c
@@ -108,7 +108,7 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
if (size > 0x10000)
size = 0x10000;
- printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range, "
"mapping 64k\n");
__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
@@ -116,7 +116,7 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
return;
inval_range:
- printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range, "
"mapping 64k\n");
__ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);
@@ -145,7 +145,7 @@ void __init isa_bridge_find_early(struct pci_controller *hose)
for_each_node_by_type(np, "isa") {
/* Look for our hose being a parent */
for (parent = of_get_parent(np); parent;) {
- if (parent == hose->arch_data) {
+ if (parent == hose->dn) {
of_node_put(parent);
break;
}
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index ff781b2edde..dcb89a88df4 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -41,7 +41,6 @@
/* #define LPARCFG_DEBUG */
static struct proc_dir_entry *proc_ppc64_lparcfg;
-#define LPARCFG_BUFF_SIZE 4096
/*
* Track sum of all purrs across all processors. This is used to further
@@ -595,13 +594,6 @@ int __init lparcfg_init(void)
ent = create_proc_entry("ppc64/lparcfg", mode, NULL);
if (ent) {
ent->proc_fops = &lparcfg_fops;
- ent->data = kmalloc(LPARCFG_BUFF_SIZE, GFP_KERNEL);
- if (!ent->data) {
- printk(KERN_ERR
- "Failed to allocate buffer for lparcfg\n");
- remove_proc_entry("lparcfg", ent->parent);
- return -ENOMEM;
- }
} else {
printk(KERN_ERR "Failed to create ppc64/lparcfg\n");
return -EIO;
@@ -613,10 +605,8 @@ int __init lparcfg_init(void)
void __exit lparcfg_cleanup(void)
{
- if (proc_ppc64_lparcfg) {
- kfree(proc_ppc64_lparcfg->data);
+ if (proc_ppc64_lparcfg)
remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent);
- }
}
module_init(lparcfg_init);
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index 330c9dc7db8..74ce0c7a7b1 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -14,6 +14,7 @@
* 2 of the License, or (at your option) any later version.
*/
#include <asm/ppc_asm.h>
+#include <asm/unistd.h>
.text
@@ -43,3 +44,10 @@ _GLOBAL(add_reloc_offset)
add r3,r3,r5
mtlr r0
blr
+
+_GLOBAL(kernel_execve)
+ li r0,__NR_execve
+ sc
+ bnslr
+ neg r3,r3
+ blr
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 8b642ab26d3..ea1137851a4 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -793,13 +793,6 @@ _GLOBAL(kernel_thread)
addi r1,r1,16
blr
-_GLOBAL(kernel_execve)
- li r0,__NR_execve
- sc
- bnslr
- neg r3,r3
- blr
-
/*
* This routine is just here to keep GCC happy - sigh...
*/
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index bbb3ba54c51..a3c491e88a7 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -518,13 +518,6 @@ _GLOBAL(giveup_altivec)
#endif /* CONFIG_ALTIVEC */
-_GLOBAL(kernel_execve)
- li r0,__NR_execve
- sc
- bnslr
- neg r3,r3
- blr
-
/* kexec_wait(phys_cpu)
*
* wait for the flag to change, indicating this kernel is going away but
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index aeaa20268ce..79c04d151dd 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -64,26 +64,6 @@ static int __init of_bus_driver_init(void)
postcore_initcall(of_bus_driver_init);
-int of_register_platform_driver(struct of_platform_driver *drv)
-{
- /* initialize common driver fields */
- if (!drv->driver.name)
- drv->driver.name = drv->name;
- if (!drv->driver.owner)
- drv->driver.owner = drv->owner;
- drv->driver.bus = &of_platform_bus_type;
-
- /* register with core */
- return driver_register(&drv->driver);
-}
-EXPORT_SYMBOL(of_register_platform_driver);
-
-void of_unregister_platform_driver(struct of_platform_driver *drv)
-{
- driver_unregister(&drv->driver);
-}
-EXPORT_SYMBOL(of_unregister_platform_driver);
-
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 2ae3b6f778a..2f3f30efffe 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -48,32 +48,21 @@
static DEFINE_SPINLOCK(hose_spinlock);
/* XXX kill that some day ... */
-int global_phb_number; /* Global phb counter */
+static int global_phb_number; /* Global phb counter */
-extern struct list_head hose_list;
-/*
- * pci_controller(phb) initialized common variables.
- */
-static void __devinit pci_setup_pci_controller(struct pci_controller *hose)
-{
- memset(hose, 0, sizeof(struct pci_controller));
-
- spin_lock(&hose_spinlock);
- hose->global_number = global_phb_number++;
- list_add_tail(&hose->list_node, &hose_list);
- spin_unlock(&hose_spinlock);
-}
-
-struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
+struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
{
struct pci_controller *phb;
- phb = alloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
+ phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL);
if (phb == NULL)
return NULL;
- pci_setup_pci_controller(phb);
- phb->arch_data = dev;
+ spin_lock(&hose_spinlock);
+ phb->global_number = global_phb_number++;
+ list_add_tail(&phb->list_node, &hose_list);
+ spin_unlock(&hose_spinlock);
+ phb->dn = dev;
phb->is_dynamic = mem_init_done;
#ifdef CONFIG_PPC64
if (dev) {
@@ -126,15 +115,10 @@ int pcibios_vaddr_is_ioport(void __iomem *address)
*/
int pci_domain_nr(struct pci_bus *bus)
{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
- else {
- struct pci_controller *hose = pci_bus_to_host(bus);
+ struct pci_controller *hose = pci_bus_to_host(bus);
- return hose->global_number;
- }
+ return hose->global_number;
}
-
EXPORT_SYMBOL(pci_domain_nr);
#ifdef CONFIG_PPC_OF
@@ -153,7 +137,7 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
while(node) {
struct pci_controller *hose, *tmp;
list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- if (hose->arch_data == node)
+ if (hose->dn == node)
return hose;
node = node->parent;
}
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 0e2bee46304..096c97e03aa 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -662,8 +662,8 @@ pcibios_make_OF_bus_map(void)
/* For each hose, we begin searching bridges */
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- struct device_node* node;
- node = (struct device_node *)hose->arch_data;
+ struct device_node* node = hose->dn;
+
if (!node)
continue;
make_one_node_map(node, hose->first_busno);
@@ -742,7 +742,7 @@ static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
struct pci_controller *hose = pci_bus_to_host(bus);
if (hose == NULL)
return NULL;
- return of_node_get(hose->arch_data);
+ return of_node_get(hose->dn);
}
/* not a root bus, we need to get our parent */
@@ -812,9 +812,9 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
return -ENODEV;
/* Make sure it's really a PCI device */
hose = pci_find_hose_for_OF_device(node);
- if (!hose || !hose->arch_data)
+ if (!hose || !hose->dn)
return -ENODEV;
- if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
+ if (!scan_OF_pci_childs(hose->dn->child,
find_OF_pci_device_filter, (void *)node))
return -ENODEV;
reg = of_get_property(node, "reg", NULL);
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 9f63bdcb0bd..6b9a8564e73 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -31,7 +31,6 @@
#include <asm/byteorder.h>
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
-#include <asm/firmware.h>
#ifdef DEBUG
#include <asm/udbg.h>
@@ -197,9 +196,6 @@ static void __init pcibios_claim_of_setup(void)
{
struct pci_bus *b;
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return;
-
list_for_each_entry(b, &pci_root_buses, node)
pcibios_claim_one_bus(b);
}
@@ -462,7 +458,7 @@ EXPORT_SYMBOL(of_scan_pci_bridge);
void __devinit scan_phb(struct pci_controller *hose)
{
struct pci_bus *bus;
- struct device_node *node = hose->arch_data;
+ struct device_node *node = hose->dn;
int i, mode;
struct resource *res;
@@ -477,8 +473,7 @@ void __devinit scan_phb(struct pci_controller *hose)
bus->secondary = hose->first_busno;
hose->bus = bus;
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- pcibios_map_io_space(bus);
+ pcibios_map_io_space(bus);
bus->resource[0] = res = &hose->io_resource;
if (res->flags && request_resource(&ioport_resource, res)) {
@@ -519,9 +514,6 @@ static int __init pcibios_init(void)
*/
ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- iSeries_pcibios_init();
-
printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
/* Scan all of the recorded PCI controllers. */
@@ -530,15 +522,13 @@ static int __init pcibios_init(void)
pci_bus_add_devices(hose->bus);
}
- if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
- if (pci_probe_only)
- pcibios_claim_of_setup();
- else
- /* FIXME: `else' will be removed when
- pci_assign_unassigned_resources() is able to work
- correctly with [partially] allocated PCI tree. */
- pci_assign_unassigned_resources();
- }
+ if (pci_probe_only)
+ pcibios_claim_of_setup();
+ else
+ /* FIXME: `else' will be removed when
+ pci_assign_unassigned_resources() is able to work
+ correctly with [partially] allocated PCI tree. */
+ pci_assign_unassigned_resources();
/* Call machine dependent final fixup */
if (ppc_md.pcibios_fixup)
@@ -584,12 +574,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
/* Decide whether to display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
- else {
- struct pci_controller *hose = pci_bus_to_host(bus);
- return hose->buid != 0;
- }
+ struct pci_controller *hose = pci_bus_to_host(bus);
+ return hose->buid != 0;
}
void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
@@ -719,8 +705,7 @@ int pcibios_unmap_io_space(struct pci_bus *bus)
if (hose->io_base_alloc == 0)
return 0;
- DBG("IO unmapping for PHB %s\n",
- ((struct device_node *)hose->arch_data)->full_name);
+ DBG("IO unmapping for PHB %s\n", hose->dn->full_name);
DBG(" alloc=0x%p\n", hose->io_base_alloc);
/* This is a PHB, we fully unmap the IO area */
@@ -779,8 +764,7 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
hose->io_base_virt = (void __iomem *)(area->addr +
hose->io_base_phys - phys_page);
- DBG("IO mapping for PHB %s\n",
- ((struct device_node *)hose->arch_data)->full_name);
+ DBG("IO mapping for PHB %s\n", hose->dn->full_name);
DBG(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
DBG(" size=0x%016lx (alloc=0x%016lx)\n",
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index b4839038613..85d4d8924b5 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -133,7 +133,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
*/
void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
{
- struct device_node * dn = (struct device_node *) phb->arch_data;
+ struct device_node *dn = phb->dn;
struct pci_dn *pdn;
/* PHB nodes themselves must not match */
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index acc0d247d3c..6c2d8836f77 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -583,6 +583,20 @@ static void __init check_cpu_pa_features(unsigned long node)
ibm_pa_features, ARRAY_SIZE(ibm_pa_features));
}
+#ifdef CONFIG_PPC64
+static void __init check_cpu_slb_size(unsigned long node)
+{
+ u32 *slb_size_ptr;
+
+ slb_size_ptr = of_get_flat_dt_prop(node, "ibm,slb-size", NULL);
+ if (slb_size_ptr != NULL) {
+ mmu_slb_size = *slb_size_ptr;
+ }
+}
+#else
+#define check_cpu_slb_size(node) do { } while(0)
+#endif
+
static struct feature_property {
const char *name;
u32 min_value;
@@ -713,6 +727,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
check_cpu_feature_properties(node);
check_cpu_pa_features(node);
+ check_cpu_slb_size(node);
#ifdef CONFIG_PPC_PSERIES
if (nthreads > 1)
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index b5c96af955c..6bdfaf3f99e 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -273,7 +273,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
#else
struct pci_controller *host;
host = pci_bus_to_host(pdev->bus);
- ppnode = host ? host->arch_data : NULL;
+ ppnode = host ? host->dn : NULL;
#endif
/* No node for host bridge ? give up */
if (ppnode == NULL)
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index 21f14e57d1f..3650eb50c27 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -260,7 +260,7 @@ static int phb_set_bus_ranges(struct device_node *dev,
int __devinit rtas_setup_phb(struct pci_controller *phb)
{
- struct device_node *dev = phb->arch_data;
+ struct device_node *dev = phb->dn;
if (is_python(dev))
python_countermeasures(dev);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 2de00f870ed..6adb5a1e98b 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -33,6 +33,7 @@
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/debugfs.h>
+#include <linux/percpu.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/processor.h>
@@ -57,6 +58,7 @@
#include <asm/mmu.h>
#include <asm/lmb.h>
#include <asm/xmon.h>
+#include <asm/cputhreads.h>
#include "setup.h"
@@ -327,6 +329,31 @@ void __init check_for_initrd(void)
#ifdef CONFIG_SMP
+int threads_per_core, threads_shift;
+cpumask_t threads_core_mask;
+
+static void __init cpu_init_thread_core_maps(int tpc)
+{
+ int i;
+
+ threads_per_core = tpc;
+ threads_core_mask = CPU_MASK_NONE;
+
+ /* This implementation only supports power of 2 number of threads
+ * for simplicity and performance
+ */
+ threads_shift = ilog2(tpc);
+ BUG_ON(tpc != (1 << threads_shift));
+
+ for (i = 0; i < tpc; i++)
+ cpu_set(i, threads_core_mask);
+
+ printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n",
+ tpc, tpc > 1 ? "s" : "");
+ printk(KERN_DEBUG " (thread shift is %d)\n", threads_shift);
+}
+
+
/**
* setup_cpu_maps - initialize the following cpu maps:
* cpu_possible_map
@@ -350,22 +377,32 @@ void __init smp_setup_cpu_maps(void)
{
struct device_node *dn = NULL;
int cpu = 0;
+ int nthreads = 1;
+
+ DBG("smp_setup_cpu_maps()\n");
while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
const int *intserv;
- int j, len = sizeof(u32), nthreads = 1;
+ int j, len;
+
+ DBG(" * %s...\n", dn->full_name);
intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
&len);
- if (intserv)
+ if (intserv) {
nthreads = len / sizeof(int);
- else {
+ DBG(" ibm,ppc-interrupt-server#s -> %d threads\n",
+ nthreads);
+ } else {
+ DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n");
intserv = of_get_property(dn, "reg", NULL);
if (!intserv)
intserv = &cpu; /* assume logical == phys */
}
for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
+ DBG(" thread %d -> cpu %d (hard id %d)\n",
+ j, cpu, intserv[j]);
cpu_set(cpu, cpu_present_map);
set_hard_smp_processor_id(cpu, intserv[j]);
cpu_set(cpu, cpu_possible_map);
@@ -373,6 +410,12 @@ void __init smp_setup_cpu_maps(void)
}
}
+ /* If no SMT supported, nthreads is forced to 1 */
+ if (!cpu_has_feature(CPU_FTR_SMT)) {
+ DBG(" SMT disabled ! nthreads forced to 1\n");
+ nthreads = 1;
+ }
+
#ifdef CONFIG_PPC64
/*
* On pSeries LPAR, we need to know how many cpus
@@ -395,7 +438,7 @@ void __init smp_setup_cpu_maps(void)
/* Double maxcpus for processors which have SMT capability */
if (cpu_has_feature(CPU_FTR_SMT))
- maxcpus *= 2;
+ maxcpus *= nthreads;
if (maxcpus > NR_CPUS) {
printk(KERN_WARNING
@@ -412,9 +455,16 @@ void __init smp_setup_cpu_maps(void)
out:
of_node_put(dn);
}
-
vdso_data->processorCount = num_present_cpus();
#endif /* CONFIG_PPC64 */
+
+ /* Initialize CPU <=> thread mapping/
+ *
+ * WARNING: We assume that the number of threads is the same for
+ * every CPU in the system. If that is not the case, then some code
+ * here will have to be reworked
+ */
+ cpu_init_thread_core_maps(nthreads);
}
/*
@@ -424,17 +474,19 @@ void __init smp_setup_cpu_maps(void)
*/
void __init smp_setup_cpu_sibling_map(void)
{
-#if defined(CONFIG_PPC64)
- int cpu;
+#ifdef CONFIG_PPC64
+ int i, cpu, base;
- /*
- * Do the sibling map; assume only two threads per processor.
- */
for_each_possible_cpu(cpu) {
- cpu_set(cpu, per_cpu(cpu_sibling_map, cpu));
- if (cpu_has_feature(CPU_FTR_SMT))
- cpu_set(cpu ^ 0x1, per_cpu(cpu_sibling_map, cpu));
+ DBG("Sibling map for CPU %d:", cpu);
+ base = cpu_first_thread_in_core(cpu);
+ for (i = 0; i < threads_per_core; i++) {
+ cpu_set(base + i, per_cpu(cpu_sibling_map, cpu));
+ DBG(" %d", base + i);
+ }
+ DBG("\n");
}
+
#endif /* CONFIG_PPC64 */
}
#endif /* CONFIG_SMP */
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 8135da06e0a..10dda224a36 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -189,7 +189,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
return SIGSEGV;
/* in_atomic() in user mode is really bad,
as is current->mm == NULL. */
- printk(KERN_EMERG "Page fault in user mode with"
+ printk(KERN_EMERG "Page fault in user mode with "
"in_atomic() = %d mm = %p\n", in_atomic(), mm);
printk(KERN_EMERG "NIP = %lx MSR = %lx\n",
regs->nip, regs->msr);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index f09730bf3a3..cbbd8b0bc8f 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -96,6 +96,7 @@ int mmu_vmalloc_psize = MMU_PAGE_4K;
int mmu_io_psize = MMU_PAGE_4K;
int mmu_kernel_ssize = MMU_SEGSIZE_256M;
int mmu_highuser_ssize = MMU_SEGSIZE_256M;
+u16 mmu_slb_size = 64;
#ifdef CONFIG_HUGETLB_PAGE
int mmu_huge_psize = MMU_PAGE_16M;
unsigned int HPAGE_SHIFT;
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 27922dff8b9..3cf0802cd2b 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -256,6 +256,7 @@ void slb_initialize(void)
static int slb_encoding_inited;
extern unsigned int *slb_miss_kernel_load_linear;
extern unsigned int *slb_miss_kernel_load_io;
+ extern unsigned int *slb_compare_rr_to_size;
/* Prepare our SLB miss handler based on our page size */
linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
@@ -269,6 +270,8 @@ void slb_initialize(void)
SLB_VSID_KERNEL | linear_llp);
patch_slb_encoding(slb_miss_kernel_load_io,
SLB_VSID_KERNEL | io_llp);
+ patch_slb_encoding(slb_compare_rr_to_size,
+ mmu_slb_size);
DBG("SLB: linear LLP = %04x\n", linear_llp);
DBG("SLB: io LLP = %04x\n", io_llp);
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 1328a81a84a..657f6b37e9d 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -227,8 +227,9 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
7: ld r10,PACASTABRR(r13)
addi r10,r10,1
- /* use a cpu feature mask if we ever change our slb size */
- cmpldi r10,SLB_NUM_ENTRIES
+ /* This gets soft patched on boot. */
+_GLOBAL(slb_compare_rr_to_size)
+ cmpldi r10,0
blt+ 4f
li r10,SLB_NUM_BOLTED
diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c
index a497cbaa1ac..11d1db8bb09 100644
--- a/arch/powerpc/platforms/82xx/pq2.c
+++ b/arch/powerpc/platforms/82xx/pq2.c
@@ -59,7 +59,7 @@ static void __init pq2_pci_add_bridge(struct device_node *np)
if (!hose)
return;
- hose->arch_data = np;
+ hose->dn = np;
setup_indirect_pci(hose, r.start + 0x100, r.start + 0x104, 0);
pci_process_bridge_OF_ranges(hose, np, 1);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 59c121a97ac..bdb3d0b38cd 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -123,7 +123,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose,
struct device_node* node;
struct resource rsrc;
- node = (struct device_node *)hose->arch_data;
+ node = hose->dn;
of_address_to_resource(node, 0, &rsrc);
if ((rsrc.start & 0xfffff) == primary_phb_addr) {
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 6390895e5e9..c6d2f48f8f3 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -124,7 +124,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev)
static void __devinit final_uli5288(struct pci_dev *dev)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- struct device_node *hosenode = hose ? hose->arch_data : NULL;
+ struct device_node *hosenode = hose ? hose->dn : NULL;
struct of_irq oirq;
int virq, pin = 2;
u32 laddr[3];
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 32a531aebcb..14f4e527e7a 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -116,7 +116,7 @@ static int mpc86xx_exclude_device(struct pci_controller *hose,
struct device_node* node;
struct resource rsrc;
- node = (struct device_node *)hose->arch_data;
+ node = hose->dn;
of_address_to_resource(node, 0, &rsrc);
if ((rsrc.start & 0xfffff) == 0x8000) {
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index d35eda80e9e..ba645c2b63f 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -120,7 +120,7 @@ void __init mpc8xx_calibrate_decr(void)
ppc_tb_freq /= 16;
ppc_proc_freq = 50000000;
if (!get_freq("clock-frequency", &ppc_proc_freq))
- printk(KERN_ERR "WARNING: Estimating processor frequency"
+ printk(KERN_ERR "WARNING: Estimating processor frequency "
"(not found)\n");
printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 9d7c2ef940a..b86076e3c09 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -238,7 +238,7 @@ static void __init spider_pci_setup_chip(struct spider_pci_bus *bus)
static void __init spider_pci_add_one(struct pci_controller *phb)
{
struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count];
- struct device_node *np = phb->arch_data;
+ struct device_node *np = phb->dn;
struct resource rsrc;
void __iomem *regs;
@@ -317,7 +317,7 @@ static int __init spider_pci_workaround_init(void)
* update this code to cope with dynamically added busses
*/
list_for_each_entry(phb, &hose_list, list_node) {
- struct device_node *np = phb->arch_data;
+ struct device_node *np = phb->dn;
const char *model = of_get_property(np, "model", NULL);
/* If no model property or name isn't exactly "pci", skip */
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index faabc3fdc13..b465494cc24 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -34,6 +34,7 @@
#include <asm/udbg.h>
#include <asm/of_platform.h>
#include <asm/lmb.h>
+#include <asm/firmware.h>
#include <asm/cell-regs.h>
#include "interrupt.h"
@@ -699,7 +700,8 @@ static int __init cell_iommu_init(void)
{
struct device_node *np;
- if (!machine_is(cell))
+ if ((!machine_is(cell) && !machine_is(celleb)) ||
+ firmware_has_feature(FW_FEATURE_LPAR))
return -ENODEV;
/* If IOMMU is disabled or we have little enough RAM to not need
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 98e7ef8e6fc..6a56b6474f5 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -179,7 +179,9 @@ static void __init cell_setup_arch(void)
conswitchp = &dummy_con;
#endif
+#ifdef CONFIG_MMIO_NVRAM
mmio_nvram_init();
+#endif
}
static int __init cell_probe(void)
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index e4438456c86..efb3964457b 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -42,6 +42,7 @@
#include <asm/firmware.h>
#include <asm/system.h>
#include <asm/rtas.h>
+#include <asm/cputhreads.h>
#include "interrupt.h"
#include <asm/udbg.h>
@@ -182,7 +183,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
*/
if (system_state < SYSTEM_RUNNING &&
cpu_has_feature(CPU_FTR_SMT) &&
- !smt_enabled_at_boot && nr % 2 != 0)
+ !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
return 1;
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig
index 04748d410fc..372891edcdd 100644
--- a/arch/powerpc/platforms/celleb/Kconfig
+++ b/arch/powerpc/platforms/celleb/Kconfig
@@ -2,6 +2,8 @@ config PPC_CELLEB
bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
depends on PPC_MULTIPLATFORM && PPC64
select PPC_CELL
+ select PPC_CELL_NATIVE
+ select PPC_RTAS
select PPC_INDIRECT_IO
select PPC_OF_PLATFORM_PCI
select HAS_TXX9_SERIAL
diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c
index 2b912140bcb..b939c0e98af 100644
--- a/arch/powerpc/platforms/celleb/io-workarounds.c
+++ b/arch/powerpc/platforms/celleb/io-workarounds.c
@@ -222,7 +222,7 @@ void __init celleb_pci_add_one(struct pci_controller *phb,
void (*dummy_read)(struct pci_controller *))
{
struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count];
- struct device_node *np = phb->arch_data;
+ struct device_node *np = phb->dn;
if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) {
printk(KERN_ERR "Too many pci bridges, workarounds"
@@ -256,13 +256,13 @@ int __init celleb_pci_workaround_init(void)
celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!celleb_dummy_page_va) {
- printk(KERN_ERR "Celleb: dummy read disabled."
+ printk(KERN_ERR "Celleb: dummy read disabled. "
"Alloc celleb_dummy_page_va failed\n");
return 1;
}
list_for_each_entry(phb, &hose_list, list_node) {
- node = phb->arch_data;
+ node = phb->dn;
match = of_match_node(celleb_pci_workaround_match, node);
if (match) {
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
index 755d869d855..287450a07c4 100644
--- a/arch/powerpc/platforms/celleb/iommu.c
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -24,6 +24,7 @@
#include <linux/pci.h>
#include <asm/of_platform.h>
+#include <asm/firmware.h>
#include "beat_wrapper.h"
@@ -91,7 +92,7 @@ static struct notifier_block celleb_of_bus_notifier = {
static int __init celleb_init_iommu(void)
{
- if (!machine_is(celleb))
+ if (!firmware_has_feature(FW_FEATURE_BEAT))
return -ENODEV;
celleb_init_direct_mapping();
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index 6bc32fda7a6..5d399e038c2 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -138,8 +138,6 @@ static void celleb_config_read_fake(unsigned char *config, int where,
*val = celleb_fake_config_readl(p);
break;
}
-
- return;
}
static void celleb_config_write_fake(unsigned char *config, int where,
@@ -158,7 +156,6 @@ static void celleb_config_write_fake(unsigned char *config, int where,
celleb_fake_config_writel(val, p);
break;
}
- return;
}
static int celleb_fake_pci_read_config(struct pci_bus *bus,
@@ -351,6 +348,10 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
wi1 = of_get_property(node, "vendor-id", NULL);
wi2 = of_get_property(node, "class-code", NULL);
wi3 = of_get_property(node, "revision-id", NULL);
+ if (!wi0 || !wi1 || !wi2 || !wi3) {
+ printk(KERN_ERR "PCI: Missing device tree properties.\n");
+ goto error;
+ }
celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
@@ -372,6 +373,10 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
li = of_get_property(node, "interrupts", &rlen);
+ if (!li) {
+ printk(KERN_ERR "PCI: interrupts not found.\n");
+ goto error;
+ }
val = li[0];
celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
@@ -475,7 +480,7 @@ static struct of_device_id celleb_phb_match[] __initdata = {
int __init celleb_setup_phb(struct pci_controller *phb)
{
- struct device_node *dev = phb->arch_data;
+ struct device_node *dev = phb->dn;
const struct of_device_id *match;
int (*setup_func)(struct device_node *, struct pci_controller *);
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
index 9d076426676..a3c7cfbcb32 100644
--- a/arch/powerpc/platforms/celleb/scc_epci.c
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -95,7 +95,7 @@ void __init epci_workaround_init(struct pci_controller *hose)
private->dummy_page_da = dma_map_single(hose->parent,
celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE);
if (private->dummy_page_da == DMA_ERROR_CODE) {
- printk(KERN_ERR "EPCI: dummy read disabled."
+ printk(KERN_ERR "EPCI: dummy read disabled. "
"Map dummy page failed.\n");
return;
}
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index ddfb35ae741..5a3f73478f4 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -53,11 +53,16 @@
#include <asm/spu_priv1.h>
#include <asm/firmware.h>
#include <asm/of_platform.h>
+#include <asm/rtas.h>
+#include <asm/cell-regs.h>
#include "interrupt.h"
#include "beat_wrapper.h"
#include "beat.h"
#include "pci.h"
+#include "../cell/interrupt.h"
+#include "../cell/pervasive.h"
+#include "../cell/ras.h"
static char celleb_machine_type[128] = "Celleb";
@@ -88,16 +93,74 @@ static void celleb_progress(char *s, unsigned short hex)
printk("*** %04x : %s\n", hex, s ? s : "");
}
-static void __init celleb_setup_arch(void)
+static void __init celleb_init_IRQ_native(void)
+{
+ iic_init_IRQ();
+ spider_init_IRQ();
+}
+
+static void __init celleb_setup_arch_beat(void)
{
+ ppc_md.restart = beat_restart;
+ ppc_md.power_off = beat_power_off;
+ ppc_md.halt = beat_halt;
+ ppc_md.get_rtc_time = beat_get_rtc_time;
+ ppc_md.set_rtc_time = beat_set_rtc_time;
+ ppc_md.power_save = beat_power_save;
+ ppc_md.nvram_size = beat_nvram_get_size;
+ ppc_md.nvram_read = beat_nvram_read;
+ ppc_md.nvram_write = beat_nvram_write;
+ ppc_md.set_dabr = beat_set_xdabr;
+ ppc_md.init_IRQ = beatic_init_IRQ;
+ ppc_md.get_irq = beatic_get_irq;
+#ifdef CONFIG_KEXEC
+ ppc_md.kexec_cpu_down = beat_kexec_cpu_down;
+#endif
+
#ifdef CONFIG_SPU_BASE
- spu_priv1_ops = &spu_priv1_beat_ops;
- spu_management_ops = &spu_management_of_ops;
+ spu_priv1_ops = &spu_priv1_beat_ops;
+ spu_management_ops = &spu_management_of_ops;
#endif
#ifdef CONFIG_SMP
smp_init_celleb();
#endif
+}
+
+static void __init celleb_setup_arch_native(void)
+{
+ ppc_md.restart = rtas_restart;
+ ppc_md.power_off = rtas_power_off;
+ ppc_md.halt = rtas_halt;
+ ppc_md.get_boot_time = rtas_get_boot_time;
+ ppc_md.get_rtc_time = rtas_get_rtc_time;
+ ppc_md.set_rtc_time = rtas_set_rtc_time;
+ ppc_md.init_IRQ = celleb_init_IRQ_native;
+
+#ifdef CONFIG_SPU_BASE
+ spu_priv1_ops = &spu_priv1_mmio_ops;
+ spu_management_ops = &spu_management_of_ops;
+#endif
+
+ cbe_regs_init();
+
+#ifdef CONFIG_CBE_RAS
+ cbe_ras_init();
+#endif
+
+#ifdef CONFIG_SMP
+ smp_init_cell();
+#endif
+
+ cbe_pervasive_init();
+}
+
+static void __init celleb_setup_arch(void)
+{
+ if (firmware_has_feature(FW_FEATURE_BEAT))
+ celleb_setup_arch_beat();
+ else
+ celleb_setup_arch_native();
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000;
@@ -111,12 +174,19 @@ static int __init celleb_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- if (!of_flat_dt_is_compatible(root, "Beat"))
- return 0;
+ if (of_flat_dt_is_compatible(root, "Beat")) {
+ powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS
+ | FW_FEATURE_BEAT | FW_FEATURE_LPAR;
+ hpte_init_beat_v3();
+ return 1;
+ }
+ if (of_flat_dt_is_compatible(root, "TOSHIBA,Celleb")) {
+ powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS;
+ hpte_init_native();
+ return 1;
+ }
- powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE;
- hpte_init_beat_v3();
- return 1;
+ return 0;
}
static struct of_device_id celleb_bus_ids[] __initdata = {
@@ -144,24 +214,11 @@ define_machine(celleb) {
.probe = celleb_probe,
.setup_arch = celleb_setup_arch,
.show_cpuinfo = celleb_show_cpuinfo,
- .restart = beat_restart,
- .power_off = beat_power_off,
- .halt = beat_halt,
- .get_rtc_time = beat_get_rtc_time,
- .set_rtc_time = beat_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = celleb_progress,
- .power_save = beat_power_save,
- .nvram_size = beat_nvram_get_size,
- .nvram_read = beat_nvram_read,
- .nvram_write = beat_nvram_write,
- .set_dabr = beat_set_xdabr,
- .init_IRQ = beatic_init_IRQ,
- .get_irq = beatic_get_irq,
.pci_probe_mode = celleb_pci_probe_mode,
.pci_setup_phb = celleb_setup_phb,
#ifdef CONFIG_KEXEC
- .kexec_cpu_down = beat_kexec_cpu_down,
.machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
.machine_crash_shutdown = default_machine_crash_shutdown,
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
index b6de2b5223d..ce91787f3c7 100644
--- a/arch/powerpc/platforms/embedded6xx/holly.c
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -26,6 +26,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/of_platform.h>
#include <asm/system.h>
#include <asm/time.h>
@@ -39,7 +40,6 @@
#include <asm/tsi108_irq.h>
#include <asm/tsi108_pci.h>
#include <asm/mpic.h>
-#include <asm/of_platform.h>
#undef DEBUG
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
index a65f1b44abf..cc7161ff166 100644
--- a/arch/powerpc/platforms/iseries/Makefile
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -5,7 +5,7 @@ extra-y += dt.o
obj-y += exception.o
obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \
hvcall.o proc.o htab.o iommu.o misc.o irq.o
-obj-$(CONFIG_PCI) += pci.o vpdinfo.o
+obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_VIOPATH) += viopath.o vio.o
obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index da87162000f..68f248b4c69 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2001 Allan Trautman, IBM Corporation
+ * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp
*
* iSeries specific routines for PCI.
*
@@ -26,6 +27,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <asm/types.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
@@ -35,6 +37,7 @@
#include <asm/abs_addr.h>
#include <asm/firmware.h>
+#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/mf.h>
#include <asm/iseries/iommu.h>
@@ -45,15 +48,8 @@
#include "pci.h"
#include "call_pci.h"
-/*
- * Forward declares of prototypes.
- */
-static struct device_node *find_Device_Node(int bus, int devfn);
-
-static int Pci_Retry_Max = 3; /* Only retry 3 times */
-static int Pci_Error_Flag = 1; /* Set Retry Error on. */
-
-static struct pci_ops iSeries_pci_ops;
+#define PCI_RETRY_MAX 3
+static int limit_pci_retries = 1; /* Set Retry Error on. */
/*
* Table defines
@@ -76,6 +72,232 @@ static const char pci_io_text[] = "iSeries PCI I/O";
static DEFINE_SPINLOCK(iomm_table_lock);
/*
+ * Generate a Direct Select Address for the Hypervisor
+ */
+static inline u64 iseries_ds_addr(struct device_node *node)
+{
+ struct pci_dn *pdn = PCI_DN(node);
+
+ return ((u64)pdn->busno << 48) + ((u64)pdn->bussubno << 40)
+ + ((u64)0x10 << 32);
+}
+
+/*
+ * Size of Bus VPD data
+ */
+#define BUS_VPDSIZE 1024
+
+/*
+ * Bus Vpd Tags
+ */
+#define VPD_END_OF_AREA 0x79
+#define VPD_ID_STRING 0x82
+#define VPD_VENDOR_AREA 0x84
+
+/*
+ * Mfg Area Tags
+ */
+#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */
+#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */
+#define VPD_SLOT_MAP 0x534D /* "SM" */
+
+/*
+ * Structures of the areas
+ */
+struct mfg_vpd_area {
+ u16 tag;
+ u8 length;
+ u8 data1;
+ u8 data2;
+};
+#define MFG_ENTRY_SIZE 3
+
+struct slot_map {
+ u8 agent;
+ u8 secondary_agent;
+ u8 phb;
+ char card_location[3];
+ char parms[8];
+ char reserved[2];
+};
+#define SLOT_ENTRY_SIZE 16
+
+/*
+ * Parse the Slot Area
+ */
+static void __init iseries_parse_slot_area(struct slot_map *map, int len,
+ HvAgentId agent, u8 *phb, char card[4])
+{
+ /*
+ * Parse Slot label until we find the one requested
+ */
+ while (len > 0) {
+ if (map->agent == agent) {
+ /*
+ * If Phb wasn't found, grab the entry first one found.
+ */
+ if (*phb == 0xff)
+ *phb = map->phb;
+ /* Found it, extract the data. */
+ if (map->phb == *phb) {
+ memcpy(card, &map->card_location, 3);
+ card[3] = 0;
+ break;
+ }
+ }
+ /* Point to the next Slot */
+ map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
+ len -= SLOT_ENTRY_SIZE;
+ }
+}
+
+/*
+ * Parse the Mfg Area
+ */
+static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
+ HvAgentId agent, u8 *phb, u8 *frame, char card[4])
+{
+ u16 slot_map_fmt = 0;
+
+ /* Parse Mfg Data */
+ while (len > 0) {
+ int mfg_tag_len = area->length;
+ /* Frame ID (FI 4649020310 ) */
+ if (area->tag == VPD_FRU_FRAME_ID)
+ *frame = area->data1;
+ /* Slot Map Format (MF 4D46020004 ) */
+ else if (area->tag == VPD_SLOT_MAP_FORMAT)
+ slot_map_fmt = (area->data1 * 256)
+ + area->data2;
+ /* Slot Map (SM 534D90 */
+ else if (area->tag == VPD_SLOT_MAP) {
+ struct slot_map *slot_map;
+
+ if (slot_map_fmt == 0x1004)
+ slot_map = (struct slot_map *)((char *)area
+ + MFG_ENTRY_SIZE + 1);
+ else
+ slot_map = (struct slot_map *)((char *)area
+ + MFG_ENTRY_SIZE);
+ iseries_parse_slot_area(slot_map, mfg_tag_len,
+ agent, phb, card);
+ }
+ /*
+ * Point to the next Mfg Area
+ * Use defined size, sizeof give wrong answer
+ */
+ area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
+ + MFG_ENTRY_SIZE);
+ len -= (mfg_tag_len + MFG_ENTRY_SIZE);
+ }
+}
+
+/*
+ * Look for "BUS".. Data is not Null terminated.
+ * PHBID of 0xFF indicates PHB was not found in VPD Data.
+ */
+static u8 __init iseries_parse_phbid(u8 *area, int len)
+{
+ while (len > 0) {
+ if ((*area == 'B') && (*(area + 1) == 'U')
+ && (*(area + 2) == 'S')) {
+ area += 3;
+ while (*area == ' ')
+ area++;
+ return *area & 0x0F;
+ }
+ area++;
+ len--;
+ }
+ return 0xff;
+}
+
+/*
+ * Parse out the VPD Areas
+ */
+static void __init iseries_parse_vpd(u8 *data, int data_len,
+ HvAgentId agent, u8 *frame, char card[4])
+{
+ u8 phb = 0xff;
+
+ while (data_len > 0) {
+ int len;
+ u8 tag = *data;
+
+ if (tag == VPD_END_OF_AREA)
+ break;
+ len = *(data + 1) + (*(data + 2) * 256);
+ data += 3;
+ data_len -= 3;
+ if (tag == VPD_ID_STRING)
+ phb = iseries_parse_phbid(data, len);
+ else if (tag == VPD_VENDOR_AREA)
+ iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
+ agent, &phb, frame, card);
+ /* Point to next Area. */
+ data += len;
+ data_len -= len;
+ }
+}
+
+static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
+ u8 *frame, char card[4])
+{
+ int status = 0;
+ int bus_vpd_len = 0;
+ u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
+
+ if (bus_vpd == NULL) {
+ printk("PCI: Bus VPD Buffer allocation failure.\n");
+ return 0;
+ }
+ bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
+ BUS_VPDSIZE);
+ if (bus_vpd_len == 0) {
+ printk("PCI: Bus VPD Buffer zero length.\n");
+ goto out_free;
+ }
+ /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
+ /* Make sure this is what I think it is */
+ if (*bus_vpd != VPD_ID_STRING) {
+ printk("PCI: Bus VPD Buffer missing starting tag.\n");
+ goto out_free;
+ }
+ iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
+ status = 1;
+out_free:
+ kfree(bus_vpd);
+ return status;
+}
+
+/*
+ * Prints the device information.
+ * - Pass in pci_dev* pointer to the device.
+ * - Pass in the device count
+ *
+ * Format:
+ * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
+ * controller
+ */
+static void __init iseries_device_information(struct pci_dev *pdev, int count,
+ u16 bus, HvSubBusNumber subbus)
+{
+ u8 frame = 0;
+ char card[4];
+ HvAgentId agent;
+
+ agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
+ ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
+
+ if (iseries_get_location_code(bus, agent, &frame, card)) {
+ printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
+ "Card %4s 0x%04X\n", count, bus,
+ PCI_SLOT(pdev->devfn), pdev->vendor, frame,
+ card, (int)(pdev->class >> 8));
+ }
+}
+
+/*
* iomm_table_allocate_entry
*
* Adds pci_dev entry in address translation table
@@ -87,7 +309,7 @@ static DEFINE_SPINLOCK(iomm_table_lock);
* - CurrentIndex is incremented to keep track of the last entry.
* - Builds the resource entry for allocated BARs.
*/
-static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
+static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
{
struct resource *bar_res = &dev->resource[bar_num];
long bar_size = pci_resource_len(dev, bar_num);
@@ -130,7 +352,7 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
* - Loops through The Bar resources(0 - 5) including the ROM
* is resource(6).
*/
-static void allocate_device_bars(struct pci_dev *dev)
+static void __init allocate_device_bars(struct pci_dev *dev)
{
int bar_num;
@@ -145,79 +367,19 @@ static void allocate_device_bars(struct pci_dev *dev)
* PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
* PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
*/
-static void pci_Log_Error(char *Error_Text, int Bus, int SubBus,
- int AgentId, int HvRc)
+static void pci_log_error(char *error, int bus, int subbus,
+ int agent, int hv_res)
{
- if (HvRc == 0x0302)
+ if (hv_res == 0x0302)
return;
printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
- Error_Text, Bus, SubBus, AgentId, HvRc);
-}
-
-/*
- * iSeries_pci_final_fixup(void)
- */
-void __init iSeries_pci_final_fixup(void)
-{
- struct pci_dev *pdev = NULL;
- struct device_node *node;
- int DeviceCount = 0;
-
- /* Fix up at the device node and pci_dev relationship */
- mf_display_src(0xC9000100);
-
- printk("pcibios_final_fixup\n");
- for_each_pci_dev(pdev) {
- node = find_Device_Node(pdev->bus->number, pdev->devfn);
- printk("pci dev %p (%x.%x), node %p\n", pdev,
- pdev->bus->number, pdev->devfn, node);
-
- if (node != NULL) {
- struct pci_dn *pdn = PCI_DN(node);
- const u32 *agent;
-
- agent = of_get_property(node, "linux,agent-id", NULL);
- if ((pdn != NULL) && (agent != NULL)) {
- u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
- pdn->bussubno);
- int err;
-
- err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno,
- *agent, irq);
- if (err)
- pci_Log_Error("Connect Bus Unit",
- pdn->busno, pdn->bussubno, *agent, err);
- else {
- err = HvCallPci_configStore8(pdn->busno, pdn->bussubno,
- *agent,
- PCI_INTERRUPT_LINE,
- irq);
- if (err)
- pci_Log_Error("PciCfgStore Irq Failed!",
- pdn->busno, pdn->bussubno, *agent, err);
- }
- if (!err)
- pdev->irq = irq;
- }
-
- ++DeviceCount;
- pdev->sysdata = (void *)node;
- PCI_DN(node)->pcidev = pdev;
- allocate_device_bars(pdev);
- iSeries_Device_Information(pdev, DeviceCount);
- iommu_devnode_init_iSeries(pdev, node);
- } else
- printk("PCI: Device Tree not found for 0x%016lX\n",
- (unsigned long)pdev);
- }
- iSeries_activate_IRQs();
- mf_display_src(0xC9000200);
+ error, bus, subbus, agent, hv_res);
}
/*
* Look down the chain to find the matching Device Device
*/
-static struct device_node *find_Device_Node(int bus, int devfn)
+static struct device_node *find_device_node(int bus, int devfn)
{
struct device_node *node;
@@ -230,22 +392,65 @@ static struct device_node *find_Device_Node(int bus, int devfn)
return NULL;
}
-#if 0
/*
- * Returns the device node for the passed pci_dev
- * Sanity Check Node PciDev to passed pci_dev
- * If none is found, returns a NULL which the client must handle.
+ * iSeries_pci_final_fixup(void)
*/
-static struct device_node *get_Device_Node(struct pci_dev *pdev)
+void __init iSeries_pci_final_fixup(void)
{
+ struct pci_dev *pdev = NULL;
struct device_node *node;
+ int num_dev = 0;
+
+ /* Fix up at the device node and pci_dev relationship */
+ mf_display_src(0xC9000100);
+
+ printk("pcibios_final_fixup\n");
+ for_each_pci_dev(pdev) {
+ const u32 *agent;
+ const u32 *sub_bus;
+ unsigned char bus = pdev->bus->number;
+
+ node = find_device_node(bus, pdev->devfn);
+ printk("pci dev %p (%x.%x), node %p\n", pdev, bus,
+ pdev->devfn, node);
+ if (!node) {
+ printk("PCI: Device Tree not found for 0x%016lX\n",
+ (unsigned long)pdev);
+ continue;
+ }
+
+ agent = of_get_property(node, "linux,agent-id", NULL);
+ sub_bus = of_get_property(node, "linux,subbus", NULL);
+ if (agent && sub_bus) {
+ u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
+ int err;
+
+ err = HvCallXm_connectBusUnit(bus, *sub_bus,
+ *agent, irq);
+ if (err)
+ pci_log_error("Connect Bus Unit",
+ bus, *sub_bus, *agent, err);
+ else {
+ err = HvCallPci_configStore8(bus, *sub_bus,
+ *agent, PCI_INTERRUPT_LINE, irq);
+ if (err)
+ pci_log_error("PciCfgStore Irq Failed!",
+ bus, *sub_bus, *agent, err);
+ else
+ pdev->irq = irq;
+ }
+ }
- node = pdev->sysdata;
- if (node == NULL || PCI_DN(node)->pcidev != pdev)
- node = find_Device_Node(pdev->bus->number, pdev->devfn);
- return node;
+ num_dev++;
+ pdev->sysdata = node;
+ PCI_DN(node)->pcidev = pdev;
+ allocate_device_bars(pdev);
+ iseries_device_information(pdev, num_dev, bus, *sub_bus);
+ iommu_devnode_init_iSeries(pdev, node);
+ }
+ iSeries_activate_IRQs();
+ mf_display_src(0xC9000200);
}
-#endif
/*
* Config space read and write functions.
@@ -269,7 +474,7 @@ static u64 hv_cfg_write_func[4] = {
static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 *val)
{
- struct device_node *node = find_Device_Node(bus->number, devfn);
+ struct device_node *node = find_device_node(bus->number, devfn);
u64 fn;
struct HvCallPci_LoadReturn ret;
@@ -299,7 +504,7 @@ static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int size, u32 val)
{
- struct device_node *node = find_Device_Node(bus->number, devfn);
+ struct device_node *node = find_device_node(bus->number, devfn);
u64 fn;
u64 ret;
@@ -331,22 +536,22 @@ static struct pci_ops iSeries_pci_ops = {
* PCI: Device 23.90 ReadL Retry( 1)
* PCI: Device 23.90 ReadL Retry Successful(1)
*/
-static int CheckReturnCode(char *TextHdr, struct device_node *DevNode,
+static int check_return_code(char *type, struct device_node *dn,
int *retry, u64 ret)
{
if (ret != 0) {
- struct pci_dn *pdn = PCI_DN(DevNode);
+ struct pci_dn *pdn = PCI_DN(dn);
(*retry)++;
printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
- TextHdr, pdn->busno, pdn->devfn,
+ type, pdn->busno, pdn->devfn,
*retry, (int)ret);
/*
* Bump the retry and check for retry count exceeded.
* If, Exceeded, panic the system.
*/
- if (((*retry) > Pci_Retry_Max) &&
- (Pci_Error_Flag > 0)) {
+ if (((*retry) > PCI_RETRY_MAX) &&
+ (limit_pci_retries > 0)) {
mf_display_src(0xB6000103);
panic_timeout = 0;
panic("PCI: Hardware I/O Error, SRC B6000103, "
@@ -363,28 +568,40 @@ static int CheckReturnCode(char *TextHdr, struct device_node *DevNode,
* the exposure of being device global.
*/
static inline struct device_node *xlate_iomm_address(
- const volatile void __iomem *IoAddress,
- u64 *dsaptr, u64 *BarOffsetPtr)
+ const volatile void __iomem *addr,
+ u64 *dsaptr, u64 *bar_offset, const char *func)
{
- unsigned long OrigIoAddr;
- unsigned long BaseIoAddr;
- unsigned long TableIndex;
- struct device_node *DevNode;
+ unsigned long orig_addr;
+ unsigned long base_addr;
+ unsigned long ind;
+ struct device_node *dn;
+
+ orig_addr = (unsigned long __force)addr;
+ if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {
+ static unsigned long last_jiffies;
+ static int num_printed;
- OrigIoAddr = (unsigned long __force)IoAddress;
- if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory))
+ if ((jiffies - last_jiffies) > 60 * HZ) {
+ last_jiffies = jiffies;
+ num_printed = 0;
+ }
+ if (num_printed++ < 10)
+ printk(KERN_ERR
+ "iSeries_%s: invalid access at IO address %p\n",
+ func, addr);
return NULL;
- BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY;
- TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE;
- DevNode = iomm_table[TableIndex];
-
- if (DevNode != NULL) {
- int barnum = iobar_table[TableIndex];
- *dsaptr = iseries_ds_addr(DevNode) | (barnum << 24);
- *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE;
+ }
+ base_addr = orig_addr - BASE_IO_MEMORY;
+ ind = base_addr / IOMM_TABLE_ENTRY_SIZE;
+ dn = iomm_table[ind];
+
+ if (dn != NULL) {
+ int barnum = iobar_table[ind];
+ *dsaptr = iseries_ds_addr(dn) | (barnum << 24);
+ *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
} else
- panic("PCI: Invalid PCI IoAddress detected!\n");
- return DevNode;
+ panic("PCI: Invalid PCI IO address detected!\n");
+ return dn;
}
/*
@@ -392,91 +609,58 @@ static inline struct device_node *xlate_iomm_address(
* On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
* else, data is returned in Big Endian format.
*/
-static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress)
+static u8 iseries_readb(const volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
struct HvCallPci_LoadReturn ret;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
-
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n",
- IoAddress);
+ if (dn == NULL)
return 0xff;
- }
do {
- HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0);
- } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0);
+ HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);
+ } while (check_return_code("RDB", dn, &retry, ret.rc) != 0);
return ret.value;
}
-static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress)
+static u16 iseries_readw_be(const volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
struct HvCallPci_LoadReturn ret;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
-
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n",
- IoAddress);
+ if (dn == NULL)
return 0xffff;
- }
do {
HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
- BarOffset, 0);
- } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0);
+ bar_offset, 0);
+ } while (check_return_code("RDW", dn, &retry, ret.rc) != 0);
return ret.value;
}
-static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
+static u32 iseries_readl_be(const volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
struct HvCallPci_LoadReturn ret;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
-
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n",
- IoAddress);
+ if (dn == NULL)
return 0xffffffff;
- }
do {
HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
- BarOffset, 0);
- } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0);
+ bar_offset, 0);
+ } while (check_return_code("RDL", dn, &retry, ret.rc) != 0);
return ret.value;
}
@@ -485,134 +669,72 @@ static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress)
* Write MM I/O Instructions for the iSeries
*
*/
-static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress)
+static void iseries_writeb(u8 data, volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
u64 rc;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
-
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress);
+ if (dn == NULL)
return;
- }
do {
- rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0);
- } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0);
+ rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);
+ } while (check_return_code("WWB", dn, &retry, rc) != 0);
}
-static void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress)
+static void iseries_writew_be(u16 data, volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
u64 rc;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
-
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n",
- IoAddress);
+ if (dn == NULL)
return;
- }
do {
- rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, data, 0);
- } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0);
+ rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);
+ } while (check_return_code("WWW", dn, &retry, rc) != 0);
}
-static void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress)
+static void iseries_writel_be(u32 data, volatile void __iomem *addr)
{
- u64 BarOffset;
+ u64 bar_offset;
u64 dsa;
int retry = 0;
u64 rc;
- struct device_node *DevNode =
- xlate_iomm_address(IoAddress, &dsa, &BarOffset);
+ struct device_node *dn =
+ xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");
- if (DevNode == NULL) {
- static unsigned long last_jiffies;
- static int num_printed;
-
- if ((jiffies - last_jiffies) > 60 * HZ) {
- last_jiffies = jiffies;
- num_printed = 0;
- }
- if (num_printed++ < 10)
- printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n",
- IoAddress);
+ if (dn == NULL)
return;
- }
do {
- rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, data, 0);
- } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0);
-}
-
-static u8 iseries_readb(const volatile void __iomem *addr)
-{
- return iSeries_Read_Byte(addr);
+ rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);
+ } while (check_return_code("WWL", dn, &retry, rc) != 0);
}
static u16 iseries_readw(const volatile void __iomem *addr)
{
- return le16_to_cpu(iSeries_Read_Word(addr));
+ return le16_to_cpu(iseries_readw_be(addr));
}
static u32 iseries_readl(const volatile void __iomem *addr)
{
- return le32_to_cpu(iSeries_Read_Long(addr));
-}
-
-static u16 iseries_readw_be(const volatile void __iomem *addr)
-{
- return iSeries_Read_Word(addr);
-}
-
-static u32 iseries_readl_be(const volatile void __iomem *addr)
-{
- return iSeries_Read_Long(addr);
-}
-
-static void iseries_writeb(u8 data, volatile void __iomem *addr)
-{
- iSeries_Write_Byte(data, addr);
+ return le32_to_cpu(iseries_readl_be(addr));
}
static void iseries_writew(u16 data, volatile void __iomem *addr)
{
- iSeries_Write_Word(cpu_to_le16(data), addr);
+ iseries_writew_be(cpu_to_le16(data), addr);
}
static void iseries_writel(u32 data, volatile void __iomem *addr)
{
- iSeries_Write_Long(cpu_to_le32(data), addr);
-}
-
-static void iseries_writew_be(u16 data, volatile void __iomem *addr)
-{
- iSeries_Write_Word(data, addr);
-}
-
-static void iseries_writel_be(u32 data, volatile void __iomem *addr)
-{
- iSeries_Write_Long(data, addr);
+ iseries_writel(cpu_to_le32(data), addr);
}
static void iseries_readsb(const volatile void __iomem *addr, void *buf,
@@ -620,7 +742,7 @@ static void iseries_readsb(const volatile void __iomem *addr, void *buf,
{
u8 *dst = buf;
while(count-- > 0)
- *(dst++) = iSeries_Read_Byte(addr);
+ *(dst++) = iseries_readb(addr);
}
static void iseries_readsw(const volatile void __iomem *addr, void *buf,
@@ -628,7 +750,7 @@ static void iseries_readsw(const volatile void __iomem *addr, void *buf,
{
u16 *dst = buf;
while(count-- > 0)
- *(dst++) = iSeries_Read_Word(addr);
+ *(dst++) = iseries_readw_be(addr);
}
static void iseries_readsl(const volatile void __iomem *addr, void *buf,
@@ -636,7 +758,7 @@ static void iseries_readsl(const volatile void __iomem *addr, void *buf,
{
u32 *dst = buf;
while(count-- > 0)
- *(dst++) = iSeries_Read_Long(addr);
+ *(dst++) = iseries_readl_be(addr);
}
static void iseries_writesb(volatile void __iomem *addr, const void *buf,
@@ -644,7 +766,7 @@ static void iseries_writesb(volatile void __iomem *addr, const void *buf,
{
const u8 *src = buf;
while(count-- > 0)
- iSeries_Write_Byte(*(src++), addr);
+ iseries_writeb(*(src++), addr);
}
static void iseries_writesw(volatile void __iomem *addr, const void *buf,
@@ -652,7 +774,7 @@ static void iseries_writesw(volatile void __iomem *addr, const void *buf,
{
const u16 *src = buf;
while(count-- > 0)
- iSeries_Write_Word(*(src++), addr);
+ iseries_writew_be(*(src++), addr);
}
static void iseries_writesl(volatile void __iomem *addr, const void *buf,
@@ -660,7 +782,7 @@ static void iseries_writesl(volatile void __iomem *addr, const void *buf,
{
const u32 *src = buf;
while(count-- > 0)
- iSeries_Write_Long(*(src++), addr);
+ iseries_writel_be(*(src++), addr);
}
static void iseries_memset_io(volatile void __iomem *addr, int c,
@@ -669,7 +791,7 @@ static void iseries_memset_io(volatile void __iomem *addr, int c,
volatile char __iomem *d = addr;
while (n-- > 0)
- iSeries_Write_Byte(c, d++);
+ iseries_writeb(c, d++);
}
static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
@@ -679,7 +801,7 @@ static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
const volatile char __iomem *s = src;
while (n-- > 0)
- *d++ = iSeries_Read_Byte(s++);
+ *d++ = iseries_readb(s++);
}
static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
@@ -689,7 +811,7 @@ static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
volatile char __iomem *d = dest;
while (n-- > 0)
- iSeries_Write_Byte(*s++, d++);
+ iseries_writeb(*s++, d++);
}
/* We only set MMIO ops. The default PIO ops will be default
@@ -742,6 +864,8 @@ void __init iSeries_pcibios_init(void)
/* Install IO hooks */
ppc_pci_io = iseries_pci_io;
+ pci_probe_only = 1;
+
/* iSeries has no IO space in the common sense, it needs to set
* the IO base to 0
*/
@@ -767,6 +891,8 @@ void __init iSeries_pcibios_init(void)
phb = pcibios_alloc_controller(node);
if (phb == NULL)
continue;
+ /* All legacy iSeries PHBs are in domain zero */
+ phb->global_number = 0;
phb->pci_mem_offset = bus;
phb->first_busno = bus;
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h
index 33a8489fde5..180aa74afb2 100644
--- a/arch/powerpc/platforms/iseries/pci.h
+++ b/arch/powerpc/platforms/iseries/pci.h
@@ -30,10 +30,6 @@
* End Change Activity
*/
-#include <asm/pci-bridge.h>
-
-struct pci_dev; /* For Forward Reference */
-
/*
* Decodes Linux DevFn to iSeries DevFn, bridge device, or function.
* For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h
@@ -47,17 +43,12 @@ struct pci_dev; /* For Forward Reference */
#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
-/*
- * Generate a Direct Select Address for the Hypervisor
- */
-static inline u64 iseries_ds_addr(struct device_node *node)
-{
- struct pci_dn *pdn = PCI_DN(node);
-
- return ((u64)pdn->busno << 48) + ((u64)pdn->bussubno << 40)
- + ((u64)0x10 << 32);
-}
-
-extern void iSeries_Device_Information(struct pci_dev*, int);
+#ifdef CONFIG_PCI
+extern void iSeries_pcibios_init(void);
+extern void iSeries_pci_final_fixup(void);
+#else
+static inline void iSeries_pcibios_init(void) { }
+static inline void iSeries_pci_final_fixup(void) { }
+#endif
#endif /* _PLATFORMS_ISERIES_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 0877a883411..5616219a20d 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -63,6 +63,7 @@
#include "main_store.h"
#include "call_sm.h"
#include "call_hpt.h"
+#include "pci.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -74,11 +75,6 @@
static unsigned long build_iSeries_Memory_Map(void);
static void iseries_shared_idle(void);
static void iseries_dedicated_idle(void);
-#ifdef CONFIG_PCI
-extern void iSeries_pci_final_fixup(void);
-#else
-static void iSeries_pci_final_fixup(void) { }
-#endif
struct MemoryBlock {
@@ -112,13 +108,13 @@ static unsigned long iSeries_process_Condor_mainstore_vpd(
* correctly.
*/
mb_array[0].logicalStart = 0;
- mb_array[0].logicalEnd = 0x100000000;
+ mb_array[0].logicalEnd = 0x100000000UL;
mb_array[0].absStart = 0;
- mb_array[0].absEnd = 0x100000000;
+ mb_array[0].absEnd = 0x100000000UL;
if (holeSize) {
numMemoryBlocks = 2;
- holeStart = holeStart & 0x000fffffffffffff;
+ holeStart = holeStart & 0x000fffffffffffffUL;
holeStart = addr_to_chunk(holeStart);
holeFirstChunk = holeStart;
holeSize = addr_to_chunk(holeSize);
@@ -128,9 +124,9 @@ static unsigned long iSeries_process_Condor_mainstore_vpd(
mb_array[0].logicalEnd = holeFirstChunk;
mb_array[0].absEnd = holeFirstChunk;
mb_array[1].logicalStart = holeFirstChunk;
- mb_array[1].logicalEnd = 0x100000000 - holeSizeChunks;
+ mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;
mb_array[1].absStart = holeFirstChunk + holeSizeChunks;
- mb_array[1].absEnd = 0x100000000;
+ mb_array[1].absEnd = 0x100000000UL;
}
return numMemoryBlocks;
}
@@ -234,9 +230,9 @@ static unsigned long iSeries_process_Regatta_mainstore_vpd(
mb_array[i].logicalEnd,
mb_array[i].absStart, mb_array[i].absEnd);
mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
- 0x000fffffffffffff);
+ 0x000fffffffffffffUL);
mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &
- 0x000fffffffffffff);
+ 0x000fffffffffffffUL);
mb_array[i].logicalStart =
addr_to_chunk(mb_array[i].logicalStart);
mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);
@@ -320,7 +316,7 @@ struct mschunks_map mschunks_map = {
};
EXPORT_SYMBOL(mschunks_map);
-void mschunks_alloc(unsigned long num_chunks)
+static void mschunks_alloc(unsigned long num_chunks)
{
klimit = _ALIGN(klimit, sizeof(u32));
mschunks_map.mapping = (u32 *)klimit;
@@ -499,6 +495,8 @@ static void __init iSeries_setup_arch(void)
itVpdAreas.xSlicMaxLogicalProcs);
printk("Max physical processors = %d\n",
itVpdAreas.xSlicMaxPhysicalProcs);
+
+ iSeries_pcibios_init();
}
static void iSeries_show_cpuinfo(struct seq_file *m)
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
index 0a47ac53c95..729754bbb01 100644
--- a/arch/powerpc/platforms/iseries/setup.h
+++ b/arch/powerpc/platforms/iseries/setup.h
@@ -17,6 +17,7 @@
#ifndef __ISERIES_SETUP_H__
#define __ISERIES_SETUP_H__
+extern void *iSeries_early_setup(void);
extern unsigned long iSeries_get_boot_time(void);
extern int iSeries_set_rtc_time(struct rtc_time *tm);
extern void iSeries_get_rtc_time(struct rtc_time *tm);
diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c
deleted file mode 100644
index 9f83878a0c2..00000000000
--- a/arch/powerpc/platforms/iseries/vpdinfo.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * This code gets the card location of the hardware
- * Copyright (C) 2001 <Allan H Trautman> <IBM Corp>
- * Copyright (C) 2005 Stephen Rothwel, IBM Corp
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the:
- * Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- *
- * Change Activity:
- * Created, Feb 2, 2001
- * Ported to ppc64, August 20, 2001
- * End Change Activity
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-
-#include <asm/types.h>
-#include <asm/resource.h>
-#include <asm/abs_addr.h>
-#include <asm/pci-bridge.h>
-#include <asm/iseries/hv_types.h>
-
-#include "pci.h"
-#include "call_pci.h"
-
-/*
- * Size of Bus VPD data
- */
-#define BUS_VPDSIZE 1024
-
-/*
- * Bus Vpd Tags
- */
-#define VpdEndOfAreaTag 0x79
-#define VpdIdStringTag 0x82
-#define VpdVendorAreaTag 0x84
-
-/*
- * Mfg Area Tags
- */
-#define VpdFruFrameId 0x4649 // "FI"
-#define VpdSlotMapFormat 0x4D46 // "MF"
-#define VpdSlotMap 0x534D // "SM"
-
-/*
- * Structures of the areas
- */
-struct MfgVpdAreaStruct {
- u16 Tag;
- u8 TagLength;
- u8 AreaData1;
- u8 AreaData2;
-};
-typedef struct MfgVpdAreaStruct MfgArea;
-#define MFG_ENTRY_SIZE 3
-
-struct SlotMapStruct {
- u8 AgentId;
- u8 SecondaryAgentId;
- u8 PhbId;
- char CardLocation[3];
- char Parms[8];
- char Reserved[2];
-};
-typedef struct SlotMapStruct SlotMap;
-#define SLOT_ENTRY_SIZE 16
-
-/*
- * Parse the Slot Area
- */
-static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen,
- HvAgentId agent, u8 *PhbId, char card[4])
-{
- int SlotMapLen = MapLen;
- SlotMap *SlotMapPtr = MapPtr;
-
- /*
- * Parse Slot label until we find the one requested
- */
- while (SlotMapLen > 0) {
- if (SlotMapPtr->AgentId == agent) {
- /*
- * If Phb wasn't found, grab the entry first one found.
- */
- if (*PhbId == 0xff)
- *PhbId = SlotMapPtr->PhbId;
- /* Found it, extract the data. */
- if (SlotMapPtr->PhbId == *PhbId) {
- memcpy(card, &SlotMapPtr->CardLocation, 3);
- card[3] = 0;
- break;
- }
- }
- /* Point to the next Slot */
- SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE);
- SlotMapLen -= SLOT_ENTRY_SIZE;
- }
-}
-
-/*
- * Parse the Mfg Area
- */
-static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen,
- HvAgentId agent, u8 *PhbId,
- u8 *frame, char card[4])
-{
- MfgArea *MfgAreaPtr = (MfgArea *)AreaData;
- int MfgAreaLen = AreaLen;
- u16 SlotMapFmt = 0;
-
- /* Parse Mfg Data */
- while (MfgAreaLen > 0) {
- int MfgTagLen = MfgAreaPtr->TagLength;
- /* Frame ID (FI 4649020310 ) */
- if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */
- *frame = MfgAreaPtr->AreaData1;
- /* Slot Map Format (MF 4D46020004 ) */
- else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */
- SlotMapFmt = (MfgAreaPtr->AreaData1 * 256)
- + MfgAreaPtr->AreaData2;
- /* Slot Map (SM 534D90 */
- else if (MfgAreaPtr->Tag == VpdSlotMap) { /* SM */
- SlotMap *SlotMapPtr;
-
- if (SlotMapFmt == 0x1004)
- SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
- + MFG_ENTRY_SIZE + 1);
- else
- SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr
- + MFG_ENTRY_SIZE);
- iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen,
- agent, PhbId, card);
- }
- /*
- * Point to the next Mfg Area
- * Use defined size, sizeof give wrong answer
- */
- MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen
- + MFG_ENTRY_SIZE);
- MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE);
- }
-}
-
-/*
- * Look for "BUS".. Data is not Null terminated.
- * PHBID of 0xFF indicates PHB was not found in VPD Data.
- */
-static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength)
-{
- u8 *PhbPtr = AreaPtr;
- int DataLen = AreaLength;
- char PhbId = 0xFF;
-
- while (DataLen > 0) {
- if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U')
- && (*(PhbPtr + 2) == 'S')) {
- PhbPtr += 3;
- while (*PhbPtr == ' ')
- ++PhbPtr;
- PhbId = (*PhbPtr & 0x0F);
- break;
- }
- ++PhbPtr;
- --DataLen;
- }
- return PhbId;
-}
-
-/*
- * Parse out the VPD Areas
- */
-static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen,
- HvAgentId agent, u8 *frame, char card[4])
-{
- u8 *TagPtr = VpdData;
- int DataLen = VpdDataLen - 3;
- u8 PhbId = 0xff;
-
- while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) {
- int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256);
- u8 *AreaData = TagPtr + 3;
-
- if (*TagPtr == VpdIdStringTag)
- PhbId = iSeries_Parse_PhbId(AreaData, AreaLen);
- else if (*TagPtr == VpdVendorAreaTag)
- iSeries_Parse_MfgArea(AreaData, AreaLen,
- agent, &PhbId, frame, card);
- /* Point to next Area. */
- TagPtr = AreaData + AreaLen;
- DataLen -= AreaLen;
- }
-}
-
-static int __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent,
- u8 *frame, char card[4])
-{
- int status = 0;
- int BusVpdLen = 0;
- u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
-
- if (BusVpdPtr == NULL) {
- printk("PCI: Bus VPD Buffer allocation failure.\n");
- return 0;
- }
- BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr),
- BUS_VPDSIZE);
- if (BusVpdLen == 0) {
- printk("PCI: Bus VPD Buffer zero length.\n");
- goto out_free;
- }
- /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */
- /* Make sure this is what I think it is */
- if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */
- printk("PCI: Bus VPD Buffer missing starting tag.\n");
- goto out_free;
- }
- iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card);
- status = 1;
-out_free:
- kfree(BusVpdPtr);
- return status;
-}
-
-/*
- * Prints the device information.
- * - Pass in pci_dev* pointer to the device.
- * - Pass in the device count
- *
- * Format:
- * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
- * controller
- */
-void __init iSeries_Device_Information(struct pci_dev *PciDev, int count)
-{
- struct device_node *DevNode = PciDev->sysdata;
- struct pci_dn *pdn;
- u16 bus;
- u8 frame = 0;
- char card[4];
- HvSubBusNumber subbus;
- HvAgentId agent;
-
- if (DevNode == NULL) {
- printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n",
- count);
- return;
- }
-
- pdn = PCI_DN(DevNode);
- bus = pdn->busno;
- subbus = pdn->bussubno;
- agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
- ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
-
- if (iSeries_Get_Location_Code(bus, agent, &frame, card)) {
- printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
- "Card %4s 0x%04X\n", count, bus,
- PCI_SLOT(PciDev->devfn), PciDev->vendor, frame,
- card, (int)(PciDev->class >> 8));
- }
-}
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 771ed0cf29a..3ffa0ac170e 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -558,7 +558,7 @@ void __init maple_pci_init(void)
* safe assumptions hopefully.
*/
if (u3_agp) {
- struct device_node *np = u3_agp->arch_data;
+ struct device_node *np = u3_agp->dn;
PCI_DN(np)->busno = 0xf0;
for (np = np->child; np; np = np->sibling)
PCI_DN(np)->busno = 0xf0;
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 735e1536cbf..2f4dd6e4aac 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -17,7 +17,7 @@ config PPC_PASEMI_IOMMU
bool "PA Semi IOMMU support"
depends on PPC_PASEMI
help
- IOMMU support for PA6T-1682M
+ IOMMU support for PA Semi PWRficient
config PPC_PASEMI_IOMMU_DMA_FORCE
bool "Force DMA engine to use IOMMU"
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
index 1cfb8b0c8fe..58556b028a4 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/time.h>
+#include <asm/smp.h>
#define SDCASR_REG 0x0100
#define SDCASR_REG_STRIDE 0x1000
@@ -124,6 +125,11 @@ static void set_astate(int cpu, unsigned int astate)
local_irq_restore(flags);
}
+int check_astate(void)
+{
+ return get_cur_astate(hard_smp_processor_id());
+}
+
void restore_astate(int cpu)
{
set_astate(cpu, current_astate);
@@ -147,7 +153,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (!cpu)
goto out;
- dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc");
+ dn = of_find_compatible_node(NULL, NULL, "1682m-sdc");
+ if (!dn)
+ dn = of_find_compatible_node(NULL, NULL,
+ "pasemi,pwrficient-sdc");
if (!dn)
goto out;
err = of_address_to_resource(dn, 0, &res);
@@ -160,7 +169,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto out;
}
- dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo");
+ dn = of_find_compatible_node(NULL, NULL, "1682m-gizmo");
+ if (!dn)
+ dn = of_find_compatible_node(NULL, NULL,
+ "pasemi,pwrficient-gizmo");
if (!dn) {
err = -ENODEV;
goto out_unmap_sdcasr;
@@ -292,7 +304,8 @@ static struct cpufreq_driver pas_cpufreq_driver = {
static int __init pas_cpufreq_init(void)
{
- if (!machine_is_compatible("PA6T-1682M"))
+ if (!machine_is_compatible("PA6T-1682M") &&
+ !machine_is_compatible("pasemi,pwrficient"))
return -ENODEV;
return cpufreq_register_driver(&pas_cpufreq_driver);
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
index dae9f658122..b46542990cf 100644
--- a/arch/powerpc/platforms/pasemi/gpio_mdio.c
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -30,7 +30,7 @@
#include <linux/interrupt.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
-#include <asm/of_platform.h>
+#include <linux/of_platform.h>
#define DELAY 1
@@ -218,45 +218,27 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
struct device *dev = &ofdev->dev;
- struct device_node *np = ofdev->node;
- struct device_node *gpio_np;
+ struct device_node *phy_dn, *np = ofdev->node;
struct mii_bus *new_bus;
- struct resource res;
struct gpio_priv *priv;
const unsigned int *prop;
- int err = 0;
+ int err;
int i;
- gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
-
- if (!gpio_np)
- return -ENODEV;
-
- err = of_address_to_resource(gpio_np, 0, &res);
- of_node_put(gpio_np);
-
- if (err)
- return -EINVAL;
-
- if (!gpio_regs)
- gpio_regs = ioremap(res.start, 0x100);
-
- if (!gpio_regs)
- return -EPERM;
-
+ err = -ENOMEM;
priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
- if (priv == NULL)
- return -ENOMEM;
+ if (!priv)
+ goto out;
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
- if (new_bus == NULL)
- return -ENOMEM;
+ if (!new_bus)
+ goto out_free_priv;
- new_bus->name = "pasemi gpio mdio bus",
- new_bus->read = &gpio_mdio_read,
- new_bus->write = &gpio_mdio_write,
- new_bus->reset = &gpio_mdio_reset,
+ new_bus->name = "pasemi gpio mdio bus";
+ new_bus->read = &gpio_mdio_read;
+ new_bus->write = &gpio_mdio_write;
+ new_bus->reset = &gpio_mdio_reset;
prop = of_get_property(np, "reg", NULL);
new_bus->id = *prop;
@@ -265,9 +247,24 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
new_bus->phy_mask = 0;
new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
- for(i = 0; i < PHY_MAX_ADDR; ++i)
- new_bus->irq[i] = irq_create_mapping(NULL, 10);
+ if (!new_bus->irq)
+ goto out_free_bus;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = NO_IRQ;
+
+ for (phy_dn = of_get_next_child(np, NULL);
+ phy_dn != NULL;
+ phy_dn = of_get_next_child(np, phy_dn)) {
+ const unsigned int *ip, *regp;
+
+ ip = of_get_property(phy_dn, "interrupts", NULL);
+ regp = of_get_property(phy_dn, "reg", NULL);
+ if (!ip || !regp || *regp >= PHY_MAX_ADDR)
+ continue;
+ new_bus->irq[*regp] = irq_create_mapping(NULL, *ip);
+ }
prop = of_get_property(np, "mdc-pin", NULL);
priv->mdc_pin = *prop;
@@ -280,17 +277,21 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev,
err = mdiobus_register(new_bus);
- if (0 != err) {
+ if (err != 0) {
printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
new_bus->name, err);
- goto bus_register_fail;
+ goto out_free_irq;
}
return 0;
-bus_register_fail:
+out_free_irq:
+ kfree(new_bus->irq);
+out_free_bus:
kfree(new_bus);
-
+out_free_priv:
+ kfree(priv);
+out:
return err;
}
@@ -317,6 +318,7 @@ static struct of_device_id gpio_mdio_match[] =
},
{},
};
+MODULE_DEVICE_TABLE(of, gpio_mdio_match);
static struct of_platform_driver gpio_mdio_driver =
{
@@ -330,12 +332,32 @@ static struct of_platform_driver gpio_mdio_driver =
int gpio_mdio_init(void)
{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "1682m-gpio");
+ if (!np)
+ np = of_find_compatible_node(NULL, NULL,
+ "pasemi,pwrficient-gpio");
+ if (!np)
+ return -ENODEV;
+ gpio_regs = of_iomap(np, 0);
+ of_node_put(np);
+
+ if (!gpio_regs)
+ return -ENODEV;
+
return of_register_platform_driver(&gpio_mdio_driver);
}
+module_init(gpio_mdio_init);
void gpio_mdio_exit(void)
{
of_unregister_platform_driver(&gpio_mdio_driver);
+ if (gpio_regs)
+ iounmap(gpio_regs);
}
-device_initcall(gpio_mdio_init);
+module_exit(gpio_mdio_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 516acabb4e9..c96127b029b 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -16,8 +16,14 @@ extern void idle_doze(void);
/* Restore astate to last set */
#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+extern int check_astate(void);
extern void restore_astate(int cpu);
#else
+static inline int check_astate(void)
+{
+ /* Always return >0 so we never power save */
+ return 1;
+}
static inline void restore_astate(int cpu)
{
}
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S
index 6d0fba6aab1..56f45adcd08 100644
--- a/arch/powerpc/platforms/pasemi/powersave.S
+++ b/arch/powerpc/platforms/pasemi/powersave.S
@@ -62,7 +62,16 @@ sleep_common:
mflr r0
std r0, 16(r1)
stdu r1,-64(r1)
+#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+ std r3, 48(r1)
+ /* Only do power savings when in astate 0 */
+ bl .check_astate
+ cmpwi r3,0
+ bne 1f
+
+ ld r3, 48(r1)
+#endif
LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE)
mfmsr r4
andc r5,r4,r6
@@ -73,7 +82,7 @@ sleep_common:
mtmsrd r4,0
- addi r1,r1,64
+1: addi r1,r1,64
ld r0,16(r1)
mtlr r0
blr
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 3d62060498b..6d7d068ceba 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/console.h>
#include <linux/pci.h>
+#include <linux/of_platform.h>
#include <asm/prom.h>
#include <asm/system.h>
@@ -35,7 +36,7 @@
#include <asm/mpic.h>
#include <asm/smp.h>
#include <asm/time.h>
-#include <asm/of_platform.h>
+#include <asm/mmu.h>
#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
@@ -43,6 +44,10 @@
#include "pasemi.h"
+#if !defined(CONFIG_SMP)
+static void smp_send_stop(void) {}
+#endif
+
/* SDC reset register, must be pre-mapped at reset time */
static void __iomem *reset_reg;
@@ -60,6 +65,9 @@ static int num_mce_regs;
static void pas_restart(char *cmd)
{
+ /* Need to put others cpu in hold loop so they're not sleeping */
+ smp_send_stop();
+ udelay(10000);
printk("Restarting...\n");
while (1)
out_le32(reset_reg, 0x6000000);
@@ -295,7 +303,7 @@ static int pas_machine_check_handler(struct pt_regs *regs)
int i;
printk(KERN_ERR "slb contents:\n");
- for (i = 0; i < SLB_NUM_ENTRIES; i++) {
+ for (i = 0; i < mmu_slb_size; i++) {
asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i));
asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i));
printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v);
@@ -362,8 +370,12 @@ static inline void pasemi_pcmcia_init(void)
static struct of_device_id pasemi_bus_ids[] = {
+ /* Unfortunately needed for legacy firmwares */
{ .type = "localbus", },
{ .type = "sdc", },
+ /* These are the proper entries, which newer firmware uses */
+ { .compatible = "pasemi,localbus", },
+ { .compatible = "pasemi,sdc", },
{},
};
@@ -389,7 +401,8 @@ static int __init pas_probe(void)
{
unsigned long root = of_get_flat_dt_root();
- if (!of_flat_dt_is_compatible(root, "PA6T-1682M"))
+ if (!of_flat_dt_is_compatible(root, "PA6T-1682M") &&
+ !of_flat_dt_is_compatible(root, "pasemi,pwrficient"))
return 0;
hpte_init_native();
@@ -400,7 +413,7 @@ static int __init pas_probe(void)
}
define_machine(pasemi) {
- .name = "PA Semi PA6T-1682M",
+ .name = "PA Semi PWRficient",
.probe = pas_probe,
.setup_arch = pas_setup_arch,
.init_early = pas_init_early,
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index f852ae3e0ee..589c613bcd3 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -319,7 +319,7 @@ static int u3_ht_skip_device(struct pci_controller *hose,
if (bus->self)
busdn = pci_device_to_OF_node(bus->self);
else
- busdn = hose->arch_data;
+ busdn = hose->dn;
for (dn = busdn->child; dn; dn = dn->sibling)
if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn)
break;
@@ -778,7 +778,7 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
static void __init setup_u3_ht(struct pci_controller* hose)
{
- struct device_node *np = (struct device_node *)hose->arch_data;
+ struct device_node *np = hose->dn;
struct pci_controller *other = NULL;
int i, cur;
@@ -1032,7 +1032,7 @@ void __init pmac_pci_init(void)
* future though
*/
if (u3_agp) {
- struct device_node *np = u3_agp->arch_data;
+ struct device_node *np = u3_agp->dn;
PCI_DN(np)->busno = 0xf0;
for (np = np->child; np; np = np->sibling)
PCI_DN(np)->busno = 0xf0;
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 02c53309662..3acb59d5cdf 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -51,6 +51,8 @@
#include <linux/root_dev.h>
#include <linux/bitops.h>
#include <linux/suspend.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#include <asm/reg.h>
#include <asm/sections.h>
@@ -68,8 +70,6 @@
#include <asm/btext.h>
#include <asm/pmac_feature.h>
#include <asm/time.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
#include <asm/mmu_context.h>
#include <asm/iommu.h>
#include <asm/smu.h>
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index bf9da56942e..bbbefd64ab5 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -84,12 +84,14 @@ long __init pmac_time_init(void)
return delta;
}
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
static void to_rtc_time(unsigned long now, struct rtc_time *tm)
{
to_tm(now, tm);
tm->tm_year -= 1900;
tm->tm_mon -= 1;
}
+#endif
static unsigned long from_rtc_time(struct rtc_time *tm)
{
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index fb3d636e088..aa14a8559ed 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -480,6 +480,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
no_dn++;
return 0;
}
+ dn = find_device_pe(dn);
pdn = PCI_DN(dn);
/* Access to IO BARs might get this far and still not want checking. */
@@ -545,7 +546,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
/* Note that config-io to empty slots may fail;
* they are empty when they don't have children. */
- if ((rets[0] == 5) && (dn->child == NULL)) {
+ if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) {
false_positives++;
pdn->eeh_false_positives ++;
rc = 0;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 57e025e84ab..68ea5eee39a 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -310,8 +310,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
const char *location, *pci_str, *drv_str;
frozen_dn = find_device_pe(event->dn);
- frozen_bus = pcibios_find_pci_bus(frozen_dn);
-
if (!frozen_dn) {
location = of_get_property(event->dn, "ibm,loc-code", NULL);
@@ -321,6 +319,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
location, pci_name(event->dev));
return NULL;
}
+
+ frozen_bus = pcibios_find_pci_bus(frozen_dn);
location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
@@ -354,13 +354,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
- /* Get the current PCI slot state. */
- rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
- if (rc < 0) {
- printk(KERN_WARNING "EEH: Permanent failure\n");
- goto hard_fail;
- }
-
printk(KERN_WARNING
"EEH: This PCI device has failed %d times in the last hour:\n",
frozen_pdn->eeh_freeze_count);
@@ -376,6 +369,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
*/
pci_walk_bus(frozen_bus, eeh_report_error, &result);
+ /* Get the current PCI slot state. This can take a long time,
+ * sometimes over 3 seconds for certain systems. */
+ rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
+ if (rc < 0) {
+ printk(KERN_WARNING "EEH: Permanent failure\n");
+ goto hard_fail;
+ }
+
/* Since rtas may enable MMIO when posting the error log,
* don't post the error log until after all dev drivers
* have been informed.
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index be17d239507..a65c7630820 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -251,7 +251,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
const unsigned long *basep;
const u32 *sizep;
- node = (struct device_node *)phb->arch_data;
+ node = phb->dn;
basep = of_get_property(node, "linux,tce-base", NULL);
sizep = of_get_property(node, "linux,tce-size", NULL);
@@ -296,11 +296,12 @@ static void iommu_table_setparms(struct pci_controller *phb,
static void iommu_table_setparms_lpar(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl,
- const void *dma_window)
+ const void *dma_window,
+ int bussubno)
{
unsigned long offset, size;
- tbl->it_busno = PCI_DN(dn)->bussubno;
+ tbl->it_busno = bussubno;
of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
tbl->it_base = 0;
@@ -420,17 +421,10 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
pdn->full_name, ppci->iommu_table);
if (!ppci->iommu_table) {
- /* Bussubno hasn't been copied yet.
- * Do it now because iommu_table_setparms_lpar needs it.
- */
-
- ppci->bussubno = bus->number;
-
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
ppci->phb->node);
-
- iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
-
+ iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window,
+ bus->number);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
DBG(" created table: %p\n", ppci->iommu_table);
}
@@ -523,14 +517,10 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pci = PCI_DN(pdn);
if (!pci->iommu_table) {
- /* iommu_table_setparms_lpar needs bussubno. */
- pci->bussubno = pci->phb->bus->number;
-
tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
pci->phb->node);
-
- iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
-
+ iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window,
+ pci->phb->bus->number);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
DBG(" created table: %p\n", pci->iommu_table);
} else {
@@ -556,7 +546,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
case PSERIES_RECONFIG_REMOVE:
if (pci && pci->iommu_table &&
of_get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
+ iommu_free_table(pci->iommu_table, np->full_name);
break;
default:
err = NOTIFY_DONE;
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index d003c80fa31..d8680b589dc 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -8,11 +8,6 @@ static inline long poll_pending(void)
return plpar_hcall_norets(H_POLL_PENDING);
}
-static inline long prod_processor(void)
-{
- return plpar_hcall_norets(H_PROD);
-}
-
static inline long cede_processor(void)
{
return plpar_hcall_norets(H_CEDE);
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 116305b22a2..ea4c65917a6 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -46,6 +46,7 @@
#include <asm/pSeries_reconfig.h>
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
+#include <asm/cputhreads.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -202,7 +203,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
*/
if (system_state < SYSTEM_RUNNING &&
cpu_has_feature(CPU_FTR_SMT) &&
- !smt_enabled_at_boot && nr % 2 != 0)
+ !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
return 1;
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 5eaf3e3f4b8..d359d6e9297 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -42,8 +42,9 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
#include <asm/page.h>
#include <asm/prom.h>
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 33df4c347ca..87e58e09b50 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -222,7 +222,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
}
- printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx."
+ printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
"Firmware bus number: %d->%d\n",
(unsigned long long)rsrc.start, hose->first_busno,
hose->last_busno);
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index 20edd1e94ef..c858749263e 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -28,9 +28,9 @@
#include <linux/completion.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
#include <asm/io.h>
#include <asm/pmi.h>
#include <asm/prom.h>
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 121b04d165d..865e36751f2 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -153,6 +153,10 @@ static const char *getvecname(unsigned long vec);
static int do_spu_cmd(void);
+#ifdef CONFIG_44x
+static void dump_tlb_44x(void);
+#endif
+
int xmon_no_auto_backtrace;
extern void xmon_enter(void);
@@ -231,6 +235,9 @@ Commands:\n\
#ifdef CONFIG_PPC_STD_MMU_32
" u dump segment registers\n"
#endif
+#ifdef CONFIG_44x
+" u dump TLB\n"
+#endif
" ? help\n"
" zr reboot\n\
zh halt\n"
@@ -856,6 +863,11 @@ cmds(struct pt_regs *excp)
dump_segments();
break;
#endif
+#ifdef CONFIG_4xx
+ case 'u':
+ dump_tlb_44x();
+ break;
+#endif
default:
printf("Unrecognized command: ");
do {
@@ -2527,16 +2539,33 @@ static void xmon_print_symbol(unsigned long address, const char *mid,
static void dump_slb(void)
{
int i;
- unsigned long tmp;
+ unsigned long esid,vsid,valid;
+ unsigned long llp;
printf("SLB contents of cpu %x\n", smp_processor_id());
- for (i = 0; i < SLB_NUM_ENTRIES; i++) {
- asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i));
- printf("%02d %016lx ", i, tmp);
-
- asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i));
- printf("%016lx\n", tmp);
+ for (i = 0; i < mmu_slb_size; i++) {
+ asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
+ asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
+ valid = (esid & SLB_ESID_V);
+ if (valid | esid | vsid) {
+ printf("%02d %016lx %016lx", i, esid, vsid);
+ if (valid) {
+ llp = vsid & SLB_VSID_LLP;
+ if (vsid & SLB_VSID_B_1T) {
+ printf(" 1T ESID=%9lx VSID=%13lx LLP:%3lx \n",
+ GET_ESID_1T(esid),
+ (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT_1T,
+ llp);
+ } else {
+ printf(" 256M ESID=%9lx VSID=%13lx LLP:%3lx \n",
+ GET_ESID(esid),
+ (vsid & ~SLB_VSID_B) >> SLB_VSID_SHIFT,
+ llp);
+ }
+ } else
+ printf("\n");
+ }
}
}
@@ -2581,6 +2610,32 @@ void dump_segments(void)
}
#endif
+#ifdef CONFIG_44x
+static void dump_tlb_44x(void)
+{
+ int i;
+
+ for (i = 0; i < PPC44x_TLB_SIZE; i++) {
+ unsigned long w0,w1,w2;
+ asm volatile("tlbre %0,%1,0" : "=r" (w0) : "r" (i));
+ asm volatile("tlbre %0,%1,1" : "=r" (w1) : "r" (i));
+ asm volatile("tlbre %0,%1,2" : "=r" (w2) : "r" (i));
+ printf("[%02x] %08x %08x %08x ", i, w0, w1, w2);
+ if (w0 & PPC44x_TLB_VALID) {
+ printf("V %08x -> %01x%08x %c%c%c%c%c",
+ w0 & PPC44x_TLB_EPN_MASK,
+ w1 & PPC44x_TLB_ERPN_MASK,
+ w1 & PPC44x_TLB_RPN_MASK,
+ (w2 & PPC44x_TLB_W) ? 'W' : 'w',
+ (w2 & PPC44x_TLB_I) ? 'I' : 'i',
+ (w2 & PPC44x_TLB_M) ? 'M' : 'm',
+ (w2 & PPC44x_TLB_G) ? 'G' : 'g',
+ (w2 & PPC44x_TLB_E) ? 'E' : 'e');
+ }
+ printf("\n");
+ }
+}
+#endif /* CONFIG_44x */
void xmon_init(int enable)
{
#ifdef CONFIG_PPC_ISERIES
diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c
index 976270d537c..c1f77e1d368 100644
--- a/arch/ppc/platforms/ev64260.c
+++ b/arch/ppc/platforms/ev64260.c
@@ -336,7 +336,7 @@ ev64260_early_serial_map(void)
#endif
if (early_serial_setup(&port) != 0)
- printk(KERN_WARNING "Early serial init of port 0"
+ printk(KERN_WARNING "Early serial init of port 0 "
"failed\n");
first_time = 0;
@@ -388,7 +388,7 @@ ev64260_setup_arch(void)
ev64260_early_serial_map();
#endif
- printk(KERN_INFO "%s %s port (C) 2001 MontaVista Software, Inc."
+ printk(KERN_INFO "%s %s port (C) 2001 MontaVista Software, Inc. "
"(source@mvista.com)\n", BOARD_VENDOR, BOARD_MACHINE);
if (ppc_md.progress)