diff options
Diffstat (limited to 'arch')
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) |