LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] powerpc: Instrument Hypervisor Calls: merge headers
From: Mike Kravetz @ 2006-06-14  3:50 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Bryan Rosenburg, Christopher Yeoh
In-Reply-To: <20060614034756.GA6759@monkey.ibm.com>

Move all the Hypervisor call definitions to to a single header file.

-- 
Signed-off-by: Mike Kravetz <kravetz@us.ibm.com>


diff -Naupr linux-2.6.17-rc6/drivers/net/ibmveth.h linux-2.6.17-rc6.work/drivers/net/ibmveth.h
--- linux-2.6.17-rc6/drivers/net/ibmveth.h	2006-06-06 00:57:02.000000000 +0000
+++ linux-2.6.17-rc6.work/drivers/net/ibmveth.h	2006-06-13 21:35:10.000000000 +0000
@@ -41,16 +41,6 @@
 #define IbmVethMcastRemoveFilter     0x2UL
 #define IbmVethMcastClearFilterTable 0x3UL
 
-/* hcall numbers */
-#define H_VIO_SIGNAL             0x104
-#define H_REGISTER_LOGICAL_LAN   0x114
-#define H_FREE_LOGICAL_LAN       0x118
-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
-#define H_SEND_LOGICAL_LAN       0x120
-#define H_MULTICAST_CTRL         0x130
-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
-
 /* hcall macros */
 #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
   plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
diff -Naupr linux-2.6.17-rc6/include/asm-powerpc/hvcall.h linux-2.6.17-rc6.work/include/asm-powerpc/hvcall.h
--- linux-2.6.17-rc6/include/asm-powerpc/hvcall.h	2006-06-06 00:57:02.000000000 +0000
+++ linux-2.6.17-rc6.work/include/asm-powerpc/hvcall.h	2006-06-13 21:35:10.000000000 +0000
@@ -155,9 +155,15 @@
 #define H_VIO_SIGNAL		0x104
 #define H_SEND_CRQ		0x108
 #define H_COPY_RDMA		0x110
+#define H_REGISTER_LOGICAL_LAN	0x114
+#define H_FREE_LOGICAL_LAN	0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN	0x120
+#define H_MULTICAST_CTRL	0x130
 #define H_SET_XDABR		0x134
 #define H_STUFF_TCE		0x138
 #define H_PUT_TCE_INDIRECT	0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
 #define H_VTERM_PARTNER_INFO	0x150
 #define H_REGISTER_VTERM	0x154
 #define H_FREE_VTERM		0x158
@@ -187,11 +193,14 @@
 #define H_GET_HCA_INFO          0x1B8
 #define H_GET_PERF_COUNT        0x1BC
 #define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
 #define H_QUERY_INT_STATE       0x1E4
 #define H_POLL_PENDING		0x1D8
 #define H_JOIN			0x298
 #define H_ENABLE_CRQ		0x2B0
 
+#define MAX_HCALL_OPCODES	(H_ENABLE_CRQ >> 2)
+
 #ifndef __ASSEMBLY__
 
 /* plpar_hcall() -- Generic call interface using above opcodes

^ permalink raw reply

* [PATCH 0/3] powerpc: Instrument Hypervisor Calls
From: Mike Kravetz @ 2006-06-14  3:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Bryan Rosenburg, Christopher Yeoh

This patch series adds instrumentation to Hypervisor calls.  Code and
ideas were taken from the patch set provided by Christopher Yeoh.

The idea is to put all instrumentation code behind a configuration
option so that it can easily be added/removed.  The instrumentation
code is kept to a minimum in the hopes that it's impact to performance
will not be noticed.  Statistics are made available via files in sysfs.

-- 
Mike

^ permalink raw reply

* Re: [HACK] add sandpoint + flattened dt support to arch/powerpc/boot
From: Mark A. Greer @ 2006-06-14  3:37 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1147930376.17679.72.camel@localhost.localdomain>

Ben,

[The patch below is not a patch submission, its just for comment.]

I reorged the boot stuff a bit to try to make it easier for all the different
worlds to live together.  Basically, there are 4 types of operations,
platform (platform_ops), firmware (fw_ops), device tree (dt_ops), and
console (console_ops).  ops.h defines them all.

I'm sure some ops may need to move and some may need to be added as more
platforms are added into boot dir but its a start.  I also incorporated
Michal Ostrowski's patch that puts the zImage cmdline in a separate section
(although I changed the name to zimage_cmdline to make it clear where
the cmdline came from).  I also changed 'prom.c' to 'of.c' because it
seemed more accurate.

For the sandpoint, I used sandpoint_platform_ops, dink_fw_ops,
fdt_dt_ops (flat dev tree), and ns16550_console_ops (which uses some
more generic serial ops).  The maple only uses the various of_*_ops
which are all in of.c.

Some of the fdt.c code can probably be merged with code that's in
kernel/prom.c or prom_parse.c but I'm not going to worry about that
for now.

The latest powerpc.git tree doesn't seem to build for me (32 bit) so
I haven't tested in that tree but in an older tree, I can build & boot
sandpoint and maple zImages.

I know there was a whole lot more I wanted to say but I'm tired and I
can't think right now.

Anyway, I would appreciate it you and others who care would take a
look and comment.  I would like to get the sandpoint into the powerpc
tree sometime soon so I hope its not too far off.

Thanks,

Mark
--

 arch/powerpc/boot/prom.c              |  165 ----------
 arch/powerpc/boot/prom.h              |   34 --
 b/arch/powerpc/boot/Makefile          |    9 
 b/arch/powerpc/boot/dink.c            |   57 +++
 b/arch/powerpc/boot/dts/sandpoint.dts |  206 +++++++++++++
 b/arch/powerpc/boot/fdt.c             |  525 ++++++++++++++++++++++++++++++++++
 b/arch/powerpc/boot/io.h              |  160 ++++++++++
 b/arch/powerpc/boot/main.c            |  177 +++++------
 b/arch/powerpc/boot/mpc10x.c          |   87 +++++
 b/arch/powerpc/boot/ns16550.c         |  125 ++++++++
 b/arch/powerpc/boot/of.c              |  301 +++++++++++++++++++
 b/arch/powerpc/boot/ops.h             |  117 +++++++
 b/arch/powerpc/boot/sandpoint.c       |  148 +++++++++
 b/arch/powerpc/boot/serial.c          |   90 +++++
 b/arch/powerpc/boot/stdio.c           |    4 
 b/arch/powerpc/boot/types.h           |   29 +
 b/arch/powerpc/boot/util.S            |  101 ++++++
 17 files changed, 2041 insertions(+), 294 deletions(-)

--

diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 840ae59..1e67d96 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -36,8 +36,15 @@ zliblinuxheader := zlib.h zconf.h zutil.
 $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
 
-src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
+src-boot := crt0.S string.S stdio.c main.c div64.S
 src-boot += $(zlib)
+ifneq ($(CONFIG_EMBEDDED6xx),y)
+src-boot += of.c
+endif
+ifeq ($(CONFIG_SANDPOINT),y)
+src-boot += sandpoint.c mpc10x.c dink.c fdt.c serial.c ns16550.c \
+		util.S dts/sandpoint.S
+endif
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
 
diff --git a/arch/powerpc/boot/dink.c b/arch/powerpc/boot/dink.c
new file mode 100644
index 0000000..b01efbc
--- /dev/null
+++ b/arch/powerpc/boot/dink.c
@@ -0,0 +1,57 @@
+/*
+ * Sandpoint specific fixups.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "io.h"
+#include "ops.h"
+
+#define	MB	(1024*1024)
+
+extern char _end[];
+
+static u32	cur_base;
+static u32	end_of_ram = 32 * MB; /* XXXX get from /memory */
+
+static void *
+dink_malloc(u32 size)
+{
+	void *area = NULL;
+	static u8 first_time = 1;
+
+	if (first_time) {
+		cur_base = _ALIGN_UP((unsigned long)_end, MB);
+		first_time = 0;
+	}
+
+	if ((cur_base + size) < end_of_ram) {
+		area = (void *)cur_base;
+		cur_base += _ALIGN_UP(size, MB);
+	}
+
+	return area;
+}
+
+static struct fw_ops dink_fw_ops;
+
+struct fw_ops *
+dink_init(void)
+{
+	dink_fw_ops.malloc = dink_malloc;
+	dink_fw_ops.free = NULL;
+	dink_fw_ops.exit = NULL;
+
+	return &dink_fw_ops;
+}
diff --git a/arch/powerpc/boot/dts/sandpoint.dts b/arch/powerpc/boot/dts/sandpoint.dts
new file mode 100644
index 0000000..dfd3f7d
--- /dev/null
+++ b/arch/powerpc/boot/dts/sandpoint.dts
@@ -0,0 +1,206 @@
+/*
+ * Device Tree Souce for Freescale Sandpoint
+ *
+ * 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.
+
+XXXX add flash parts, rtc, ??
+
+build with: "dtc -I dts -O asm -o sandpoint.S -V 16 sandpoint.dts"
+
+
+ */
+
+/ {
+	linux,phandle = <1000>;
+	model = "Sandpoint";
+	compatible = "classic+mpc10x";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		linux,phandle = <2000>;
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,603e { /* Really 75x, 74xx, 824x */
+			linux,phandle = <2100>;
+			linux,boot-cpu;
+			device_type = "cpu";
+			reg = <0>;
+			clock-frequency = <0>;	/* Fixed by bootwrapper */
+			timebase-frequency = <0>; /* Fixed by bootwrapper */
+			/* Following required by dtc but not used */
+			i-cache-line-size = <0>;
+			d-cache-line-size = <0>;
+			i-cache-size = <0>;
+			d-cache-size = <0>;
+		};
+	};
+
+	memory {
+		linux,phandle = <3000>;
+		device_type = "memory";
+		reg =	<00000000 00000000>;	/* Fixed by bootwrapper */
+	};
+
+	mpc10x { /* AFAICT need to make soc for 8245's uarts to be defined */
+		linux,phandle = <4000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "mpc10x-bridge";
+		compatible = "mpc10x-bridge";
+		store-gathering = <0>; /* 0 == off, !0 == on */
+		reg = <fc000000 00100000>;
+		ranges = <80000000 80000000 70000000	/* pci mem space */
+			  fc000000 fc000000 00100000	/* EUMB */
+			  fe000000 fe000000 00c00000	/* pci i/o space */
+			  fec00000 fec00000 00300000	/* pci cfg regs */
+			  fef00000 fef00000 00100000>;	/* pci iack */
+
+		dma@1100 {
+			linux,phandle = <4100>;
+			#interrupt-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			device_type = "dma";
+			compatible = "fsl-dma";
+			clock-frequency = <0>;
+			reg = <fc001100 00000024>;
+			interrupts = <33 0>;
+			interrupt-parent = <4400>;
+		};
+
+		dma@1200 {
+			linux,phandle = <4200>;
+			#interrupt-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			device_type = "dma";
+			compatible = "fsl-dma";
+			clock-frequency = <0>;
+			reg = <fc001200 00000024>;
+			interrupts = <34 0>;
+			interrupt-parent = <4400>;
+		};
+
+		i2c {
+			linux,phandle = <4300>;
+			#interrupt-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			clock-frequency = <0>;
+			reg = <fc003000 00001000>;
+			interrupts = <32 0>;
+			interrupt-parent = <4400>;
+		};
+
+		pic {
+			linux,phandle = <4400>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+			device_type = "open-pic";
+			compatible = "chrp,open-pic";
+			reg = <fc040000 00040000>;
+		};
+
+		pci {
+			linux,phandle = <4500>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+			#interrupt-cells = <1>;
+			device_type = "pci";
+			compatible = "mpc10x-pci";
+			reg = <fec00000 00400000>;
+			ranges = <01000000 0        0 fe000000 0 00c00000
+				  02000000 0 80000000 80000000 0 70000000>;
+			bus-range = <0 ff>;
+			clock-frequency = <7f28155>;
+			interrupt-pci-iack = <fef00000>; /* New - PCI IACK */
+			interrupt-parent = <4400>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x11 */
+				8800 0 0 1 4400 16 0
+				8800 0 0 2 4400  0 0
+				8800 0 0 3 4400  0 0
+				8800 0 0 4 4400  0 0
+				/* IDSEL 0x12 */
+				9000 0 0 1 4400  0 0
+				9000 0 0 2 4400  0 0
+				9000 0 0 3 4400  0 0
+				9000 0 0 4 4400  0 0
+				/* IDSEL 0x13 */
+				9800 0 0 1 4400 18 0
+				9800 0 0 2 4400 19 0
+				9800 0 0 3 4400 20 0
+				9800 0 0 4 4400 21 0
+				/* IDSEL 0x14 */
+				a000 0 0 1 4400 19 0
+				a000 0 0 2 4400 18 0
+				a000 0 0 3 4400 21 0
+				a000 0 0 4 4400 20 0
+				/* IDSEL 0x15 */
+				a800 0 0 1 4400 20 0
+				a800 0 0 2 4400 19 0
+				a800 0 0 3 4400 18 0
+				a800 0 0 4 4400 21 0
+				/* IDSEL 0x16 */
+				b000 0 0 1 4400 21 0
+				b000 0 0 2 4400 20 0
+				b000 0 0 3 4400 19 0
+				b000 0 0 4 4400 18 0
+			>;
+
+			isa {
+				linux,phandle = <4510>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				#interrupt-cells = <2>;
+				device_type = "isa";
+				compatible = "isa";
+				ranges = <1 0 01000000 0 0 00800000>;
+
+				serial@3f8 {
+					linux,phandle = <4511>;
+					device_type = "serial";
+					compatible = "ns16550";
+					reg = <1 3f8 8>;
+					clock-frequency = <1c2000>;
+					current-speed = <2580>;
+					interrupts = <4 0>;
+					interrupt-parent = <4400>;
+				};
+
+				serial@2f8 {
+					linux,phandle = <4512>;
+					device_type = "serial";
+					compatible = "ns16550";
+					reg = <1 2f8 8>;
+					clock-frequency = <1c2000>;
+					current-speed = <2580>;
+					interrupts = <3 0>;
+					interrupt-parent = <4400>;
+				};
+			};
+		};
+	};
+
+	chosen {
+		linux,phandle = <5000>;
+		linux,platform = <1>;
+		bootargs = "ip=on";
+		linux,stdout-path = "/mpc10x/pci/isa/serial@3f8";
+		interrupt-controller = <4400>;
+	};
+};
diff --git a/arch/powerpc/boot/fdt.c b/arch/powerpc/boot/fdt.c
new file mode 100644
index 0000000..f8ad8e6
--- /dev/null
+++ b/arch/powerpc/boot/fdt.c
@@ -0,0 +1,525 @@
+/*
+ * Simple dtb (binary flattened device tree) search/manipulation routines.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ * 	- The code for strrchr() was copied from lib/string.c and is
+ * 	copyrighted by Linus Torvalds.
+ * 	- The smarts for fdt_finddevice() were copied with the author's
+ * 	permission from u-boot:common/ft_build.c which was written by
+ * 	Pantelis Antoniou <pantelis@embeddedalley.com>.
+ * 	- Many of the routines related to fdt_translate_addr() came
+ * 	from arch/powerpc/kernel/prom_parse.c which has no author or
+ * 	copyright notice.
+ *
+ * 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.
+ */
+
+/* Supports dtb version 0x10 only */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.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 */
+};
+
+extern void *dt_blob_start;
+extern void *dt_blob_end;
+
+static void *dtb_start;
+static void *dtb_end;
+
+#define MAX_ADDR_CELLS	4
+#define BAD_ADDR	((u64)-1)
+
+struct fdt_bus {
+	u64	(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
+	int	(*translate)(u32 *addr, u64 offset, int na);
+};
+
+static inline struct boot_param_header *
+fdt_get_bph(void *dt_blob)
+{
+	return (struct boot_param_header *)dt_blob;
+}
+
+static char *
+fdt_strrchr(const char *s, int c)
+{
+	const char *p = s + strlen(s);
+
+	do {
+		if (*p == (char)c)
+			return (char *)p;
+	} while (--p >= s);
+	return NULL;
+}
+
+/* 'path' is modified */
+static void
+fdt_parentize(char *path, u8 leave_slash)
+{
+	char *s = &path[strlen(path) - 1];
+
+	if (*s == '/')
+		*s = '\0';
+	s = fdt_strrchr(path, '/');
+	if (s != NULL) {
+		if (leave_slash)
+			s[1] = '\0';
+		else if (s[0] == '/')
+			s[0] = '\0';
+	}
+}
+
+static inline u32 *
+fdt_next(u32 *dp, u32 **tagpp, char **namepp, char **datapp, u32 **sizepp)
+{
+	static char *str_region;
+
+	*namepp = NULL;
+	*datapp = NULL;
+	*sizepp = NULL;
+
+	if (dp == NULL) { /* first time */
+		struct boot_param_header *bph = fdt_get_bph(dtb_start);
+
+		if (bph->magic != OF_DT_HEADER) {
+			*tagpp = NULL;
+			return NULL;
+		}
+		dp = (u32 *)((u32)dtb_start + bph->off_dt_struct);
+		str_region = (char *)((u32)dtb_start + bph->off_dt_strings);
+	}
+
+	*tagpp = dp;
+
+	switch (*dp++) { /* Tag */
+	case OF_DT_PROP:
+		*sizepp = dp++;
+		*namepp = str_region + *dp++;
+		*datapp = (char *)dp;
+		dp = (u32 *)_ALIGN_UP((unsigned long)dp + **sizepp, 4);
+		break;
+	case OF_DT_BEGIN_NODE:
+		*namepp = (char *)dp;
+		dp = (u32 *)_ALIGN_UP((u32)dp + strlen((char *)dp) + 1, 4);
+		break;
+	case OF_DT_END_NODE:
+	case OF_DT_NOP:
+		break;
+	case OF_DT_END:
+	default:
+		dp = NULL;
+		break;
+	}
+
+	return dp;
+}
+
+static void *
+fdt_finddevice(const char *name)
+{
+	u32 *dp, *tagp, *sizep;
+	char *namep, *datap;
+	static char path[MAX_PATH_LEN];
+
+	path[0] = '\0';
+	dp = NULL;
+
+	while ((dp = fdt_next(dp, &tagp, &namep, &datap, &sizep)) != NULL)
+		switch (*tagp) {
+		case OF_DT_BEGIN_NODE:
+			strcat(path, namep);
+			if (!strcmp(path, name))
+				return tagp;
+			strcat(path, "/");
+			break;
+		case OF_DT_END_NODE:
+			fdt_parentize(path, 1);
+			break;
+		}
+	return NULL;
+}
+
+static int
+fdt_getprop(void *node, const char *name, void *buf, int buflen)
+{
+	u32 *dp, *tagp, *sizep, size;
+	char *namep, *datap;
+	int level;
+
+	level = 0;
+	dp = node;
+
+	while ((dp = fdt_next(dp, &tagp, &namep, &datap, &sizep)) != NULL)
+		switch (*tagp) {
+		case OF_DT_PROP:
+			if ((level == 1) && !strcmp(namep, name)) {
+				size = min(*sizep, (u32)buflen);
+				memcpy(buf, datap, size);
+				return size;
+			}
+			break;
+		case OF_DT_BEGIN_NODE:
+			level++;
+			break;
+		case OF_DT_END_NODE:
+			if (--level <= 0)
+				return -1;
+			break;
+		}
+	return -1;
+}
+
+static void
+fdt_modify_prop(u32 *dp, char *datap, u32 *old_prop_sizep, char *buf,
+		int buflen)
+{
+	u32 old_prop_data_len, new_prop_data_len;
+
+	old_prop_data_len = _ALIGN_UP(*old_prop_sizep, 4);
+	new_prop_data_len = _ALIGN_UP(buflen, 4);
+
+	/* Check if new prop data fits in old prop data area */
+	if (new_prop_data_len == old_prop_data_len) {
+		memcpy(datap, buf, buflen);
+		*old_prop_sizep = buflen;
+	}
+	else { /* Need to alloc new area to put larger or smaller fdt */
+		struct boot_param_header *old_bph, *new_bph;
+		u32 *old_tailp, *new_tailp, *new_datap;
+		u32 old_total_size, new_total_size, head_len, tail_len, diff;
+		void *new_dtb_start, *new_dtb_end;
+
+		old_bph = fdt_get_bph(dtb_start),
+		old_total_size = old_bph->totalsize;
+		head_len = (u32)datap - (u32)dtb_start;
+		tail_len = old_total_size - (head_len + old_prop_data_len);
+		old_tailp = (u32 *)((u32)dtb_end - tail_len);
+		new_total_size = head_len + new_prop_data_len + tail_len;
+
+		if (!(new_dtb_start = malloc(new_total_size))) {
+			printf("Can't alloc space for new fdt\n\r");
+			exit();
+		}
+
+		new_dtb_end = (void *)((u32)new_dtb_start + new_total_size);
+		new_datap = (u32 *)((u32)new_dtb_start + head_len);
+		new_tailp = (u32 *)((u32)new_dtb_end - tail_len);
+
+		memcpy(new_dtb_start, dtb_start, head_len);
+		memcpy(new_datap, buf, buflen);
+		memcpy(new_tailp, old_tailp, tail_len);
+		*(new_datap - 2) = buflen;
+
+		new_bph = fdt_get_bph(new_dtb_start),
+		new_bph->totalsize = new_total_size;
+
+		diff = new_prop_data_len - old_prop_data_len;
+
+		/* Adjust offsets of other sections, if necessary */
+		if (new_bph->off_dt_strings > new_bph->off_dt_struct)
+			new_bph->off_dt_strings += diff;
+
+		if (new_bph->off_mem_rsvmap > new_bph->off_dt_struct)
+			new_bph->off_mem_rsvmap += diff;
+
+		free(dtb_start, old_total_size);
+
+		dtb_start = new_dtb_start;
+		dtb_end = new_dtb_end;
+	}
+}
+
+/* Only modifies existing properties */
+static int
+fdt_setprop(void *node, const char *name, void *buf, int buflen)
+{
+	u32 *dp, *tagp, *sizep;
+	char *namep, *datap;
+	int level;
+
+	level = 0;
+	dp = node;
+
+	while ((dp = fdt_next(dp, &tagp, &namep, &datap, &sizep)) != NULL)
+		switch (*tagp) {
+		case OF_DT_PROP:
+			if ((level == 1) && !strcmp(namep, name)) {
+				fdt_modify_prop(tagp, datap, sizep, buf,buflen);
+				return *sizep;
+			}
+			break;
+		case OF_DT_BEGIN_NODE:
+			level++;
+			break;
+		case OF_DT_END_NODE:
+			if (--level <= 0)
+				return -1;
+			break;
+		}
+	return -1;
+}
+
+static u32
+fdt_find_cells(char *path, char *prop)
+{
+	void *devp;
+	u32 num;
+	char p[MAX_PATH_LEN];
+
+	strcpy(p, path);
+	do {
+		if ((devp = finddevice(p))
+				&& (getprop(devp, prop, &num, sizeof(num)) > 0))
+			return num;
+		fdt_parentize(p, 0);
+	} while (strlen(p) > 0);
+	return 1; /* default of 1 */
+}
+
+static u64
+fdt_read_addr(u32 *cell, int size)
+{
+	u64 r = 0;
+	while (size--)
+		r = (r << 32) | *(cell++);
+	return r;
+}
+
+static u64
+fdt_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	cp = fdt_read_addr(range, na);
+	s  = fdt_read_addr(range + na + pna, ns);
+	da = fdt_read_addr(addr, na);
+
+	if (da < cp || da >= (cp + s))
+		return BAD_ADDR;
+	return da - cp;
+}
+
+static int
+fdt_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+	u64 a = fdt_read_addr(addr, na);
+	memset(addr, 0, na * 4);
+	a += offset;
+	if (na > 1)
+		addr[na - 2] = a >> 32;
+	addr[na - 1] = a & 0xffffffffu;
+
+	return 0;
+}
+
+static u64
+fdt_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	/* Check address type match */
+	if ((addr[0] ^ range[0]) & 0x03000000)
+		return BAD_ADDR;
+
+	/* Read address values, skipping high cell */
+	cp = fdt_read_addr(range + 1, na - 1);
+	s  = fdt_read_addr(range + na + pna, ns);
+	da = fdt_read_addr(addr + 1, na - 1);
+
+	if (da < cp || da >= (cp + s))
+		return BAD_ADDR;
+	return da - cp;
+}
+
+static int
+fdt_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+	return fdt_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static u64
+fdt_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
+{
+	u64 cp, s, da;
+
+	/* Check address type match */
+	if ((addr[0] ^ range[0]) & 0x00000001)
+		return BAD_ADDR;
+
+	/* Read address values, skipping high cell */
+	cp = fdt_read_addr(range + 1, na - 1);
+	s  = fdt_read_addr(range + na + pna, ns);
+	da = fdt_read_addr(addr + 1, na - 1);
+
+	if (da < cp || da >= (cp + s))
+		return BAD_ADDR;
+	return da - cp;
+}
+
+static int
+fdt_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+	return fdt_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static void
+fdt_match_bus(char *path, struct fdt_bus *bus)
+{
+	void *devp;
+	char dtype[128]; /* XXXX */
+
+	if ((devp = finddevice(path)) && (getprop(devp, "device_type", dtype,
+					sizeof(dtype)) > 0)) {
+		if (!strcmp(dtype, "isa")) {
+			bus->map = fdt_bus_isa_map;
+			bus->translate = fdt_bus_isa_translate;
+		} else if (!strcmp(dtype, "pci")) {
+			bus->map = fdt_bus_pci_map;
+			bus->translate = fdt_bus_pci_translate;
+		} else {
+			bus->map = fdt_bus_default_map;
+			bus->translate = fdt_bus_default_translate;
+		}
+	}
+}
+
+static int
+fdt_translate_one(char *path, struct fdt_bus *bus, struct fdt_bus *pbus,
+		u32 *addr, u32 na, u32 ns, u32 pna)
+{
+	void *devp;
+	u32 ranges[10 * (na + pna + ns)]; /* XXXX */
+	u32 *rp;
+	unsigned int rlen;
+	int rone;
+	u64 offset = BAD_ADDR;
+
+	if (!(devp = finddevice(path))
+			|| ((rlen = getprop(devp, "ranges", ranges,
+						sizeof(ranges))) < 0)
+			|| (rlen == 0)) {
+		offset = fdt_read_addr(addr, na);
+		memset(addr, 0, pna * 4);
+		goto finish;
+	}
+
+	rlen /= 4;
+	rone = na + pna + ns;
+	rp = ranges;
+	for (; rlen >= rone; rlen -= rone, rp += rone) {
+		offset = bus->map(addr, rp, na, ns, pna);
+		if (offset != BAD_ADDR)
+			break;
+	}
+	if (offset == BAD_ADDR)
+		return 1;
+	memcpy(addr, rp + na, 4 * pna);
+
+finish:
+	/* Translate it into parent bus space */
+	return pbus->translate(addr, offset, pna);
+}
+
+/* 'addr' is modified */
+static u64
+fdt_translate_addr(char *p, u32 *in_addr, u32 addr_len)
+{
+	struct fdt_bus	bus, pbus;
+	int na, ns, pna, pns;
+	u32 addr[MAX_ADDR_CELLS];
+	char path[MAX_PATH_LEN], ppath[MAX_PATH_LEN];
+
+	strcpy(ppath, p);
+	fdt_parentize(ppath, 0);
+	fdt_match_bus(ppath, &bus);
+	na = fdt_find_cells(ppath, "#address-cells");
+	ns = fdt_find_cells(ppath, "#size-cells");
+	memcpy(addr, in_addr, na * 4);
+
+	for (;;) {
+		strcpy(path, ppath);
+		fdt_parentize(ppath, 0);
+
+		if (strlen(ppath) == 0)
+			return fdt_read_addr(addr, na);
+
+		fdt_match_bus(ppath, &pbus);
+		pna = fdt_find_cells(ppath, "#address-cells");
+		pns = fdt_find_cells(ppath, "#size-cells");
+
+		if (fdt_translate_one(path, &bus, &pbus, addr, na, ns, pna))
+			exit();
+
+		na = pna;
+		ns = pns;
+		memcpy(&bus, &pbus, sizeof(struct fdt_bus));
+	}
+}
+
+static void
+fdt_call_kernel(void *entry_addr, unsigned long a1, unsigned long a2,
+		void *promptr, void *sp)
+{
+	void (*kernel_entry)(void *dt_blob, void *start_addr,
+			void *must_be_null);
+
+#ifdef DEBUG
+	printf("kernel:\n\r"
+		"        entry addr   = 0x%lx\n\r"
+		"        flattened dt = 0x%lx\n\r",
+		(unsigned long)entry_addr, dtb_start);
+#endif
+
+	kernel_entry = entry_addr;
+	kernel_entry(dtb_start, entry_addr, NULL);
+}
+
+static struct dt_ops fdt_dt_ops;
+
+struct dt_ops *
+fdt_init(void)
+{
+	fdt_dt_ops.finddevice = fdt_finddevice;
+	fdt_dt_ops.getprop = fdt_getprop;
+	fdt_dt_ops.setprop = fdt_setprop;
+	fdt_dt_ops.translate_addr = fdt_translate_addr;
+	fdt_dt_ops.call_kernel = fdt_call_kernel;
+
+	dtb_start = &dt_blob_start;
+	dtb_end = &dt_blob_end;
+
+	return &fdt_dt_ops;
+}
diff --git a/arch/powerpc/boot/io.h b/arch/powerpc/boot/io.h
new file mode 100644
index 0000000..65c1864
--- /dev/null
+++ b/arch/powerpc/boot/io.h
@@ -0,0 +1,160 @@
+#ifndef _IO_H
+#define __IO_H
+
+#include "types.h"
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ * These routines do not perform EEH-related I/O address translation,
+ * and should not be used directly by device drivers.  Use inb/readb
+ * instead.
+ */
+static inline int in_8(const volatile unsigned char *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+static inline void out_8(volatile unsigned char *addr, int val)
+{
+	__asm__ __volatile__("stb%U0%X0 %1,%0; sync"
+			     : "=m" (*addr) : "r" (val));
+}
+
+static inline int in_le16(const volatile unsigned short *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("lhbrx %0,0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "r" (addr), "m" (*addr));
+	return ret;
+}
+
+static inline int in_be16(const volatile unsigned short *addr)
+{
+	int ret;
+
+	__asm__ __volatile__("lhz%U1%X1 %0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+static inline void out_le16(volatile unsigned short *addr, int val)
+{
+	__asm__ __volatile__("sthbrx %1,0,%2; sync"
+			     : "=m" (*addr) : "r" (val), "r" (addr));
+}
+
+static inline void out_be16(volatile unsigned short *addr, int val)
+{
+	__asm__ __volatile__("sth%U0%X0 %1,%0; sync"
+			     : "=m" (*addr) : "r" (val));
+}
+
+static inline unsigned in_le32(const volatile unsigned *addr)
+{
+	unsigned ret;
+
+	__asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "r" (addr), "m" (*addr));
+	return ret;
+}
+
+static inline unsigned in_be32(const volatile unsigned *addr)
+{
+	unsigned ret;
+
+	__asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+static inline void out_le32(volatile unsigned *addr, int val)
+{
+	__asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr)
+			     : "r" (val), "r" (addr));
+}
+
+static inline void out_be32(volatile unsigned *addr, int val)
+{
+	__asm__ __volatile__("stw%U0%X0 %1,%0; sync"
+			     : "=m" (*addr) : "r" (val));
+}
+
+static inline unsigned long in_le64(const volatile unsigned long *addr)
+{
+	unsigned long tmp, ret;
+
+	__asm__ __volatile__(
+			     "ld %1,0(%2)\n"
+			     "twi 0,%1,0\n"
+			     "isync\n"
+			     "rldimi %0,%1,5*8,1*8\n"
+			     "rldimi %0,%1,3*8,2*8\n"
+			     "rldimi %0,%1,1*8,3*8\n"
+			     "rldimi %0,%1,7*8,4*8\n"
+			     "rldicl %1,%1,32,0\n"
+			     "rlwimi %0,%1,8,8,31\n"
+			     "rlwimi %0,%1,24,16,23\n"
+			     : "=r" (ret) , "=r" (tmp) : "b" (addr) , "m" (*addr));
+	return ret;
+}
+
+static inline unsigned long in_be64(const volatile unsigned long *addr)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("ld%U1%X1 %0,%1; twi 0,%0,0; isync"
+			     : "=r" (ret) : "m" (*addr));
+	return ret;
+}
+
+static inline void out_le64(volatile unsigned long *addr, unsigned long val)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+			     "rldimi %0,%1,5*8,1*8\n"
+			     "rldimi %0,%1,3*8,2*8\n"
+			     "rldimi %0,%1,1*8,3*8\n"
+			     "rldimi %0,%1,7*8,4*8\n"
+			     "rldicl %1,%1,32,0\n"
+			     "rlwimi %0,%1,8,8,31\n"
+			     "rlwimi %0,%1,24,16,23\n"
+			     "std %0,0(%3)\n"
+			     "sync"
+			     : "=&r" (tmp) , "=&r" (val) : "1" (val) , "b" (addr) , "m" (*addr));
+}
+
+static inline void out_be64(volatile unsigned long *addr, unsigned long val)
+{
+	__asm__ __volatile__("std%U0%X0 %1,%0; sync" : "=m" (*addr) : "r" (val));
+}
+
+#define	PCI_DEVFN(slot,func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
+
+/* Indirect PCI config space access routines */
+static inline void
+pci_indirect_read_config_byte(u32 *cfg_addr, u32 *cfg_data, int devfn,
+		int offset, u8 *val)
+{
+	out_be32(cfg_addr,
+		((offset & 0xfc) << 24) | (devfn << 16) | (0 << 8) | 0x80);
+	*val = in_8((u8 *)(cfg_data + (offset & 3)));
+	return;
+}
+
+static inline void
+pci_indirect_read_config_dword(u32 *cfg_addr, u32 *cfg_data, int devfn,
+		int offset, u32 *val)
+{
+	out_be32(cfg_addr,
+		((offset & 0xfc) << 24) | (devfn << 16) | (0 << 8) | 0x80);
+	*val = in_le32(cfg_data + (offset & 3));
+	return;
+}
+
+#endif /* _IO_H */
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 816446f..03e305b 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -14,17 +14,11 @@ #include "elf.h"
 #include "page.h"
 #include "string.h"
 #include "stdio.h"
-#include "prom.h"
 #include "zlib.h"
+#include "ops.h"
 
 extern void flush_cache(void *, unsigned long);
 
-
-/* Value picked to match that used by yaboot */
-#define PROG_START	0x01400000	/* only used on 64-bit systems */
-#define RAM_END		(512<<20)	/* Fixme: use OF */
-#define	ONE_MB		0x100000
-
 extern char _start[];
 extern char __bss_start[];
 extern char _end[];
@@ -46,17 +40,8 @@ static unsigned long elfoffset;
 
 static char scratch[46912];	/* scratch space for gunzip, from zlib_inflate_workspacesize() */
 static char elfheader[256];
-
-
-typedef void (*kernel_entry_t)( unsigned long,
-                                unsigned long,
-                                void *,
-				void *);
 
-
 #undef DEBUG
-
-static unsigned long claim_base;
 
 #define HEAD_CRC	2
 #define EXTRA_FIELD	4
@@ -113,24 +98,6 @@ static void gunzip(void *dst, int dstlen
 	}
 	*lenp = s.next_out - (unsigned char *) dst;
 	zlib_inflateEnd(&s);
-}
-
-static unsigned long try_claim(unsigned long size)
-{
-	unsigned long addr = 0;
-
-	for(; claim_base < RAM_END; claim_base += ONE_MB) {
-#ifdef DEBUG
-		printf("    trying: 0x%08lx\n\r", claim_base);
-#endif
-		addr = (unsigned long)claim(claim_base, size, 0);
-		if ((void *)addr != (void *)-1)
-			break;
-	}
-	if (addr == 0)
-		return 0;
-	claim_base = PAGE_ALIGN(claim_base + size);
-	return addr;
 }
 
 static int is_elf64(void *hdr)
@@ -161,16 +128,6 @@ static int is_elf64(void *hdr)
 	vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
 	vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
 
-#if defined(PROG_START)
-	/*
-	 * Maintain a "magic" minimum address. This keeps some older
-	 * firmware platforms running.
-	 */
-
-	if (claim_base < PROG_START)
-		claim_base = PROG_START;
-#endif
-
 	return 1;
 }
 
@@ -204,31 +161,12 @@ static int is_elf32(void *hdr)
 	return 1;
 }
 
-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+static void prep_kernel(unsigned long *a1, unsigned long *a2, void *sp)
 {
 	int len;
-	kernel_entry_t kernel_entry;
 
-	memset(__bss_start, 0, _end - __bss_start);
+	printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start,sp);
 
-	prom = (int (*)(void *)) promptr;
-	chosen_handle = finddevice("/chosen");
-	if (chosen_handle == (void *) -1)
-		exit();
-	if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
-		exit();
-
-	printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
-
-	/*
-	 * The first available claim_base must be above the end of the
-	 * the loaded kernel wrapper file (_start to _end includes the
-	 * initrd image if it is present) and rounded up to a nice
-	 * 1 MB boundary for good measure.
-	 */
-
-	claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
-
 	vmlinuz.addr = (unsigned long)_vmlinux_start;
 	vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 
@@ -238,43 +176,46 @@ void start(unsigned long a1, unsigned lo
 		gunzip(elfheader, sizeof(elfheader),
 				(unsigned char *)vmlinuz.addr, &len);
 	} else
-		memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader));
+		memcpy(elfheader, (const void *)vmlinuz.addr,sizeof(elfheader));
 
 	if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
 		printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
 		exit();
 	}
 
-	/* We need to claim the memsize plus the file offset since gzip
+	/* We need to alloc the memsize plus the file offset since gzip
 	 * will expand the header (file offset), then the kernel, then
 	 * possible rubbish we don't care about. But the kernel bss must
 	 * be claimed (it will be zero'd by the kernel itself)
 	 */
 	printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
-	vmlinux.addr = try_claim(vmlinux.memsize);
+	vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
 	if (vmlinux.addr == 0) {
 		printf("Can't allocate memory for kernel image !\n\r");
 		exit();
 	}
 
 	/*
-	 * Now we try to claim memory for the initrd (and copy it there)
+	 * Now we try to alloc memory for the initrd (and copy it there)
 	 */
 	initrd.size = (unsigned long)(_initrd_end - _initrd_start);
 	initrd.memsize = initrd.size;
 	if ( initrd.size > 0 ) {
-		printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size);
-		initrd.addr = try_claim(initrd.size);
+		printf("Allocating 0x%lx bytes for initrd ...\n\r",initrd.size);
+		initrd.addr = (unsigned long)malloc((u32)initrd.size);
 		if (initrd.addr == 0) {
-			printf("Can't allocate memory for initial ramdisk !\n\r");
+			printf("Can't allocate memory for initial "
+					"ramdisk !\n\r");
 			exit();
 		}
-		a1 = initrd.addr;
-		a2 = initrd.size;
-		printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
-		       initrd.addr, (unsigned long)_initrd_start, initrd.size);
-		memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
-		printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
+		*a1 = initrd.addr;
+		*a2 = initrd.size;
+		printf("initial ramdisk moving 0x%lx <- 0x%lx "
+			"(0x%lx bytes)\n\r", initrd.addr,
+			(unsigned long)_initrd_start, initrd.size);
+		memmove((void *)initrd.addr, (void *)_initrd_start,initrd.size);
+		printf("initrd head: 0x%lx\n\r",
+				*((unsigned long *)initrd.addr));
 	}
 
 	/* Eventually gunzip the kernel */
@@ -297,23 +238,75 @@ #endif
 	vmlinux.addr += elfoffset;
 
 	flush_cache((void *)vmlinux.addr, vmlinux.size);
+}
 
-	kernel_entry = (kernel_entry_t)vmlinux.addr;
-#ifdef DEBUG
-	printf( "kernel:\n\r"
-		"        entry addr = 0x%lx\n\r"
-		"        a1         = 0x%lx,\n\r"
-		"        a2         = 0x%lx,\n\r"
-		"        prom       = 0x%lx,\n\r"
-		"        bi_recs    = 0x%lx,\n\r",
-		(unsigned long)kernel_entry, a1, a2,
-		(unsigned long)prom, NULL);
-#endif
+static char zimage_cmdline[COMMAND_LINE_SIZE]
+	__attribute__((section("__zimage_cmdline")));
 
-	kernel_entry(a1, a2, prom, NULL);
+static void get_cmdline(char *buf, int size)
+{
+	void *devp;
+	int len = strlen(zimage_cmdline);
 
-	printf("Error: Linux kernel returned to zImage bootloader!\n\r");
+	buf[0] = '\0';
 
-	exit();
+	if (len > 0) { /* zimage_cmdline overrides dt's /chosen/bootargs */
+		len = min(len, size-1);
+		strncpy(buf, zimage_cmdline, len);
+		buf[len] = '\0';
+	}
+	else if ((devp = finddevice("/chosen")))
+		getprop(devp, "bootargs", buf, size);
 }
+
+static void set_cmdline(char *buf)
+{
+	void *devp;
+
+	if ((devp = finddevice("/chosen")))
+		setprop(devp, "bootargs", buf, strlen(buf) + 1);
+}
+
+struct ops *ops;
+
+void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+{
+	char cmdline[COMMAND_LINE_SIZE];
+
+	memset(__bss_start, 0, _end - __bss_start);
+
+	ops = platform_init(promptr);
+
+	if (!ops || !ops->platform_ops || !ops->fw_ops || !ops->dt_ops
+			|| !ops->console_ops)
+		exit();
 
+	if (ops->console_ops->open && (ops->console_ops->open() < 0))
+		exit();
+	if (ops->platform_ops->fixups)
+		ops->platform_ops->fixups();
+
+	prep_kernel(&a1, &a2, sp);
+
+	/* If cmdline came from zimage wrapper or if we can edit the one
+	 * in the dt, print it out and edit it, if possible.
+	 */
+	if ((strlen(zimage_cmdline) > 0) || ops->console_ops->edit_cmdline) {
+		get_cmdline(cmdline, COMMAND_LINE_SIZE);
+		printf("\n\rLinux/PowerPC load: %s", cmdline);
+		if (ops->console_ops->edit_cmdline)
+			ops->console_ops->edit_cmdline(cmdline,
+					COMMAND_LINE_SIZE);
+		printf("\n\r");
+		set_cmdline(cmdline);
+	}
+
+	if (ops->console_ops->close)
+		ops->console_ops->close();
+
+	ops->dt_ops->call_kernel((void *)vmlinux.addr, a1, a2, promptr, sp);
+
+	/* console closed so printf below may not work */
+	printf("Error: Linux kernel returned to zImage bootloader!\n\r");
+	exit();
+}
diff --git a/arch/powerpc/boot/mpc10x.c b/arch/powerpc/boot/mpc10x.c
new file mode 100644
index 0000000..2916fdc
--- /dev/null
+++ b/arch/powerpc/boot/mpc10x.c
@@ -0,0 +1,87 @@
+/*
+ * Freescale mpc10[67] & mpc824[015] specific code.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2001 (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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+
+/* Map B (CHRP Map) Defines */
+#define	MPC10X_MAPB_CNFG_ADDR		0xfec00000
+#define	MPC10X_MAPB_CNFG_DATA		0xfee00000
+
+/* Define offsets for the memory controller registers in the config space */
+#define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_START_2	0x84	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_START_1	0x88	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_END_2		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_BANK_ENABLES	0xa0
+
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ * Assume memory map B (CHRP).
+ */
+u32
+mpc10x_get_mem_size(void)
+{
+	u32 *config_addr, *config_data, val;
+	u32 start, end, total, offset, i;
+	u8 bank_enables;
+
+	config_addr = (u32 *)MPC10X_MAPB_CNFG_ADDR;
+	config_data = (u32 *)MPC10X_MAPB_CNFG_DATA;
+
+	pci_indirect_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
+			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
+
+	total = 0;
+
+	for (i=0; i<8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			pci_indirect_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			pci_indirect_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			pci_indirect_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			pci_indirect_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
new file mode 100644
index 0000000..5a6d91f
--- /dev/null
+++ b/arch/powerpc/boot/ns16550.c
@@ -0,0 +1,125 @@
+/*
+ * 16550 serial console support
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Much of the code is copied from arch/ppc/boot/common/ns16550.c
+ * which has no Author or Copyright text.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+#define UART_DLL	0	/* Out: Divisor Latch Low */
+#define UART_DLM	1	/* Out: Divisor Latch High */
+#define UART_FCR	2	/* Out: FIFO Control Register */
+#define UART_LCR	3	/* Out: Line Control Register */
+#define UART_MCR	4	/* Out: Modem Control Register */
+#define UART_LSR	5	/* In:  Line Status Register */
+#define UART_LSR_THRE	0x20	/* Transmit-hold-register empty */
+#define UART_LSR_DR	0x01	/* Receiver data ready */
+#define UART_MSR	6	/* In:  Modem Status Register */
+#define UART_SCR	7	/* I/O: Scratch Register */
+
+int
+ns16550_get_dt_info(struct serial_console_data *scdp)
+{
+	u64 addr;
+	u32 reg[2], reg_shift;
+	void *devp;
+	char path[MAX_PATH_LEN+1], compat[MAX_PATH_LEN+1];
+
+	scdp->base = NULL;
+	scdp->reg_shift = 0;
+
+	if ((devp = finddevice("/chosen"))
+			&& (getprop(devp, "linux,stdout-path", path,
+					sizeof(path)) > 0)
+			&& (devp = finddevice(path))
+			&& (getprop(devp, "compatible", compat, sizeof(compat))
+				> 0)
+			&& !strcmp(compat, "ns16550")
+			&& (getprop(devp, "reg", reg, sizeof(reg))
+				== sizeof(reg))) {
+
+		addr = ops->dt_ops->translate_addr(path, reg, sizeof(reg));
+		scdp->base = (unsigned char *)((u32)addr & 0xffffffffu);
+
+		if (getprop(devp, "reg_shift", &reg_shift, sizeof(reg_shift))
+				== sizeof(reg_shift))
+			scdp->reg_shift = reg_shift;
+		return 0;
+	}
+	return -1;
+}
+
+static int
+ns16550_open(void)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+
+	if (ns16550_get_dt_info(scdp) < 0)
+		return -1;
+
+	out_8(scdp->base + (UART_FCR << scdp->reg_shift), 0x06);
+	return 0;
+}
+
+static void
+ns16550_putc(unsigned char c)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+	while ((in_8(scdp->base + (UART_LSR << scdp->reg_shift))
+							& UART_LSR_THRE) == 0);
+	out_8(scdp->base, c);
+}
+
+static unsigned char
+ns16550_getc(void)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+	while ((in_8(scdp->base + (UART_LSR << scdp->reg_shift))
+							& UART_LSR_DR) == 0);
+	return in_8(scdp->base);
+}
+
+static u8
+ns16550_tstc(void)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+	return ((in_8(scdp->base + (UART_LSR << scdp->reg_shift)) & UART_LSR_DR)
+			!= 0);
+}
+
+static struct serial_console_data ns16550_scd;
+static struct console_ops ns16550_console_ops;
+
+struct console_ops *
+ns16550_init(void)
+{
+	ns16550_scd.open = ns16550_open;
+	ns16550_scd.putc = ns16550_putc;
+	ns16550_scd.getc = ns16550_getc;
+	ns16550_scd.tstc = ns16550_tstc;
+	ns16550_scd.close = NULL;
+	ns16550_scd.base = NULL;
+	ns16550_scd.reg_shift = 0;
+
+	ns16550_console_ops.open = serial_open;
+	ns16550_console_ops.write = serial_write;
+	ns16550_console_ops.edit_cmdline = serial_edit_cmdline;
+	ns16550_console_ops.close = serial_close;
+	ns16550_console_ops.data = &ns16550_scd;
+
+	return &ns16550_console_ops;
+}
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
new file mode 100644
index 0000000..313f125
--- /dev/null
+++ b/arch/powerpc/boot/of.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+
+typedef void *ihandle;
+typedef void *phandle;
+
+extern char _end[];
+
+/* Value picked to match that used by yaboot */
+#define PROG_START	0x01400000	/* only used on 64-bit systems */
+#define RAM_END		(512<<20)	/* Fixme: use OF */
+#define	ONE_MB		0x100000
+
+int (*prom) (void *);
+
+
+static unsigned long claim_base;
+
+static int call_prom(const char *service, int nargs, int nret, ...)
+{
+	int i;
+	struct prom_args {
+		const char *service;
+		int nargs;
+		int nret;
+		unsigned int args[12];
+	} args;
+	va_list list;
+
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, nret);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (prom(&args) < 0)
+		return -1;
+
+	return (nret > 0)? args.args[nargs]: 0;
+}
+
+static int call_prom_ret(const char *service, int nargs, int nret,
+		  unsigned int *rets, ...)
+{
+	int i;
+	struct prom_args {
+		const char *service;
+		int nargs;
+		int nret;
+		unsigned int args[12];
+	} args;
+	va_list list;
+
+	args.service = service;
+	args.nargs = nargs;
+	args.nret = nret;
+
+	va_start(list, rets);
+	for (i = 0; i < nargs; i++)
+		args.args[i] = va_arg(list, unsigned int);
+	va_end(list);
+
+	for (i = 0; i < nret; i++)
+		args.args[nargs+i] = 0;
+
+	if (prom(&args) < 0)
+		return -1;
+
+	if (rets != (void *) 0)
+		for (i = 1; i < nret; ++i)
+			rets[i-1] = args.args[nargs+i];
+
+	return (nret > 0)? args.args[nargs]: 0;
+}
+
+/*
+ * Older OF's require that when claiming a specific range of addresses,
+ * we claim the physical space in the /memory node and the virtual
+ * space in the chosen mmu node, and then do a map operation to
+ * map virtual to physical.
+ */
+static int need_map = -1;
+static ihandle chosen_mmu;
+static phandle memory;
+
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
+{
+	for (; *s2; ++s2)
+		if (*s1++ != *s2)
+			return 0;
+	return 1;
+}
+
+static int check_of_version(void)
+{
+	phandle oprom, chosen;
+	char version[64];
+
+	oprom = finddevice("/openprom");
+	if (oprom == (phandle) -1)
+		return 0;
+	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+		return 0;
+	version[sizeof(version)-1] = 0;
+	printf("OF version = '%s'\r\n", version);
+	if (!string_match(version, "Open Firmware, 1.")
+	    && !string_match(version, "FirmWorks,3."))
+		return 0;
+	chosen = finddevice("/chosen");
+	if (chosen == (phandle) -1) {
+		chosen = finddevice("/chosen@0");
+		if (chosen == (phandle) -1) {
+			printf("no chosen\n");
+			return 0;
+		}
+	}
+	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+		printf("no mmu\n");
+		return 0;
+	}
+	memory = (ihandle) call_prom("open", 1, 1, "/memory");
+	if (memory == (ihandle) -1) {
+		memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
+		if (memory == (ihandle) -1) {
+			printf("no memory node\n");
+			return 0;
+		}
+	}
+	printf("old OF detected\r\n");
+	return 1;
+}
+
+static void *claim(unsigned long virt, unsigned long size, unsigned long align)
+{
+	int ret;
+	unsigned int result;
+
+	if (need_map < 0)
+		need_map = check_of_version();
+	if (align || !need_map)
+		return (void *) call_prom("claim", 3, 1, virt, size, align);
+
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+			    align, size, virt);
+	if (ret != 0 || result == -1)
+		return (void *) -1;
+	ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+			    align, size, virt);
+	/* 0x12 == coherent + read/write */
+	ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
+			0x12, size, virt, virt);
+	return (void *) virt;
+}
+
+static void *of_try_claim(u32 size)
+{
+	unsigned long addr = 0;
+	static u8 first_time = 1;
+
+	if (first_time) {
+#if defined(PROG_START)
+		/*
+		 * Maintain a "magic" minimum address. This keeps some older
+		 * firmware platforms running.
+		 */
+
+		if (claim_base < PROG_START)
+			claim_base = PROG_START;
+#endif
+		claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
+		first_time = 0;
+	}
+
+	for(; claim_base < RAM_END; claim_base += ONE_MB) {
+#ifdef DEBUG
+		printf("    trying: 0x%08lx\n\r", claim_base);
+#endif
+		addr = (unsigned long)claim(claim_base, size, 0);
+		if ((void *)addr != (void *)-1)
+			break;
+	}
+	if (addr == 0)
+		return NULL;
+	claim_base = PAGE_ALIGN(claim_base + size);
+	return (void *)addr;
+}
+
+static void of_fw_exit(void)
+{
+	call_prom("exit", 0, 0);
+}
+
+/*
+ * OF device tree routines
+ */
+static void *of_finddevice(const char *name)
+{
+	return (phandle) call_prom("finddevice", 1, 1, name);
+}
+
+static int of_getprop(void *phandle, const char *name,
+			  void *buf, int buflen)
+{
+	return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+}
+
+static int of_setprop(void *phandle, const char *name,
+			  void *buf, int buflen)
+{
+	return call_prom("setprop", 4, 1, phandle, name, buf, buflen);
+}
+
+static void of_call_kernel(void *entry_addr, unsigned long a1,
+		unsigned long a2, void *promptr, void *sp)
+{
+	void (*kernel_entry)(unsigned long a1, unsigned long a2, void *promptr,
+			void *sp);
+
+	kernel_entry = entry_addr;
+	kernel_entry(a1, a2, promptr, sp);
+}
+
+/*
+ * OF console routines
+ */
+static void *of_stdout_handle;
+
+static int of_console_open(void)
+{
+	void *devp;
+
+	if (((devp = finddevice("/chosen")) != NULL)
+			&& (getprop(devp, "stdout", &of_stdout_handle,
+				sizeof(of_stdout_handle))
+				== sizeof(of_stdout_handle)))
+		return 0;
+
+	return -1;
+}
+
+static void of_console_write(char *buf, int len)
+{
+	call_prom("write", 3, 1, of_stdout_handle, buf, len);
+}
+
+/* Init code that hooks up all of the routines */
+static struct platform_ops of_platform_ops;
+static struct fw_ops of_fw_ops;
+static struct dt_ops of_dt_ops;
+static struct console_ops of_console_ops;
+static struct ops of_ops;
+
+struct ops *platform_init(void *promptr)
+{
+	of_platform_ops.fixups = NULL;
+	of_platform_ops.exit = NULL;
+
+	of_fw_ops.malloc = of_try_claim;
+	of_fw_ops.free = NULL;
+	of_fw_ops.exit = of_fw_exit;
+
+	of_dt_ops.finddevice = of_finddevice;
+	of_dt_ops.getprop = of_getprop;
+	of_dt_ops.setprop = of_setprop;
+	of_dt_ops.call_kernel = of_call_kernel;
+
+	of_console_ops.open = of_console_open;
+	of_console_ops.write = of_console_write;
+	of_console_ops.edit_cmdline = NULL;
+	of_console_ops.close = NULL;
+	of_console_ops.data = NULL;
+
+	of_ops.platform_ops = &of_platform_ops;
+	of_ops.fw_ops = &of_fw_ops;
+	of_ops.dt_ops = &of_dt_ops;
+	of_ops.console_ops = &of_console_ops;
+
+	prom = (int (*)(void *))promptr;
+
+	return &of_ops;
+}
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
new file mode 100644
index 0000000..c214f2b
--- /dev/null
+++ b/arch/powerpc/boot/ops.h
@@ -0,0 +1,117 @@
+/*
+ * Global definition of all the bootwrapper operations.
+ *
+ * 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.
+ */
+#ifndef _PPC_BOOT_OPS_H_
+#define _PPC_BOOT_OPS_H_
+
+#include "types.h"
+
+/* Platform specific operations */
+struct platform_ops {
+	void	(*fixups)(void);
+	void	(*exit)(void);
+};
+
+/* Firmware specific operations */
+struct fw_ops {
+	void *	(*malloc)(u32 size);
+	void	(*free)(void *ptr, u32 size);
+	void	(*exit)(void);
+};
+
+/* Device Tree operations */
+struct dt_ops {
+	void *	(*finddevice)(const char *name);
+	int	(*getprop)(void *node, const char *name, void *buf, int buflen);
+	int	(*setprop)(void *node, const char *name, void *buf, int buflen);
+	u64	(*translate_addr)(char *path, u32 *in_addr, u32 addr_len);
+	void	(*call_kernel)(void *entry_addr, unsigned long a1,
+			unsigned long a2, void *promptr, void *sp);
+};
+
+/* Serial console operations */
+struct serial_console_data {
+	int		(*open)(void);
+	void		(*putc)(unsigned char c);
+	unsigned char	(*getc)(void);
+	u8		(*tstc)(void);
+	void		(*close)(void);
+	unsigned char	*base;
+	u8		reg_shift;
+};
+
+/* Console operations */
+struct console_ops {
+	int	(*open)(void);
+	void	(*write)(char *buf, int len);
+	void	(*edit_cmdline)(char *buf, int len);
+	void	(*close)(void);
+	void	*data;
+};
+
+struct ops {
+	struct platform_ops	*platform_ops;
+	struct fw_ops		*fw_ops;
+	struct dt_ops		*dt_ops;
+	struct console_ops	*console_ops;
+};
+
+extern struct ops *ops;
+
+extern struct ops *platform_init(void *promptr);
+extern struct fw_ops *dink_init(void);
+extern struct dt_ops *fdt_init(void);
+extern struct console_ops *ns16550_init(void);
+
+extern int serial_open(void);
+extern void serial_write(char *buf, int len);
+extern void serial_edit_cmdline(char *buf, int len);
+extern void serial_close(void);
+
+static inline void *finddevice(const char *name)
+{
+	return (ops->dt_ops->finddevice) ? ops->dt_ops->finddevice(name) : NULL;
+}
+
+static inline int getprop(void *devp, const char *name, void *buf, int buflen)
+{
+	return (ops->dt_ops->getprop) ?
+			ops->dt_ops->getprop(devp, name, buf, buflen) : -1;
+}
+
+static inline int setprop(void *devp, const char *name, void *buf, int buflen)
+{
+	return (ops->dt_ops->setprop) ?
+			ops->dt_ops->setprop(devp, name, buf, buflen) : -1;
+}
+
+static inline void *malloc(u32 size)
+{
+	return (ops->fw_ops->malloc) ?  ops->fw_ops->malloc(size) : NULL;
+}
+
+static inline void free(void *ptr, u32 size)
+{
+	if (ops->fw_ops->free)
+		ops->fw_ops->free(ptr, size);
+}
+
+static inline void exit(void)
+{
+	if (ops) {
+		if (ops->platform_ops && ops->platform_ops->exit)
+			ops->platform_ops->exit();
+		if (ops->fw_ops && ops->fw_ops->exit)
+			ops->fw_ops->exit();
+	}
+	for(;;);
+}
+
+#endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/prom.c b/arch/powerpc/boot/prom.c
deleted file mode 100644
index fa00577..0000000
--- a/arch/powerpc/boot/prom.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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.
- */
-#include <stdarg.h>
-#include <stddef.h>
-#include "string.h"
-#include "stdio.h"
-#include "prom.h"
-
-int (*prom)(void *);
-phandle chosen_handle;
-ihandle stdout;
-
-int call_prom(const char *service, int nargs, int nret, ...)
-{
-	int i;
-	struct prom_args {
-		const char *service;
-		int nargs;
-		int nret;
-		unsigned int args[12];
-	} args;
-	va_list list;
-
-	args.service = service;
-	args.nargs = nargs;
-	args.nret = nret;
-
-	va_start(list, nret);
-	for (i = 0; i < nargs; i++)
-		args.args[i] = va_arg(list, unsigned int);
-	va_end(list);
-
-	for (i = 0; i < nret; i++)
-		args.args[nargs+i] = 0;
-
-	if (prom(&args) < 0)
-		return -1;
-
-	return (nret > 0)? args.args[nargs]: 0;
-}
-
-int call_prom_ret(const char *service, int nargs, int nret,
-		  unsigned int *rets, ...)
-{
-	int i;
-	struct prom_args {
-		const char *service;
-		int nargs;
-		int nret;
-		unsigned int args[12];
-	} args;
-	va_list list;
-
-	args.service = service;
-	args.nargs = nargs;
-	args.nret = nret;
-
-	va_start(list, rets);
-	for (i = 0; i < nargs; i++)
-		args.args[i] = va_arg(list, unsigned int);
-	va_end(list);
-
-	for (i = 0; i < nret; i++)
-		args.args[nargs+i] = 0;
-
-	if (prom(&args) < 0)
-		return -1;
-
-	if (rets != (void *) 0)
-		for (i = 1; i < nret; ++i)
-			rets[i-1] = args.args[nargs+i];
-
-	return (nret > 0)? args.args[nargs]: 0;
-}
-
-int write(void *handle, void *ptr, int nb)
-{
-	return call_prom("write", 3, 1, handle, ptr, nb);
-}
-
-/*
- * Older OF's require that when claiming a specific range of addresses,
- * we claim the physical space in the /memory node and the virtual
- * space in the chosen mmu node, and then do a map operation to
- * map virtual to physical.
- */
-static int need_map = -1;
-static ihandle chosen_mmu;
-static phandle memory;
-
-/* returns true if s2 is a prefix of s1 */
-static int string_match(const char *s1, const char *s2)
-{
-	for (; *s2; ++s2)
-		if (*s1++ != *s2)
-			return 0;
-	return 1;
-}
-
-static int check_of_version(void)
-{
-	phandle oprom, chosen;
-	char version[64];
-
-	oprom = finddevice("/openprom");
-	if (oprom == (phandle) -1)
-		return 0;
-	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
-		return 0;
-	version[sizeof(version)-1] = 0;
-	printf("OF version = '%s'\r\n", version);
-	if (!string_match(version, "Open Firmware, 1.")
-	    && !string_match(version, "FirmWorks,3."))
-		return 0;
-	chosen = finddevice("/chosen");
-	if (chosen == (phandle) -1) {
-		chosen = finddevice("/chosen@0");
-		if (chosen == (phandle) -1) {
-			printf("no chosen\n");
-			return 0;
-		}
-	}
-	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
-		printf("no mmu\n");
-		return 0;
-	}
-	memory = (ihandle) call_prom("open", 1, 1, "/memory");
-	if (memory == (ihandle) -1) {
-		memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
-		if (memory == (ihandle) -1) {
-			printf("no memory node\n");
-			return 0;
-		}
-	}
-	printf("old OF detected\r\n");
-	return 1;
-}
-
-void *claim(unsigned long virt, unsigned long size, unsigned long align)
-{
-	int ret;
-	unsigned int result;
-
-	if (need_map < 0)
-		need_map = check_of_version();
-	if (align || !need_map)
-		return (void *) call_prom("claim", 3, 1, virt, size, align);
-	
-	ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
-			    align, size, virt);
-	if (ret != 0 || result == -1)
-		return (void *) -1;
-	ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
-			    align, size, virt);
-	/* 0x12 == coherent + read/write */
-	ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
-			0x12, size, virt, virt);
-	return (void *) virt;
-}
diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
deleted file mode 100644
index 3e2ddd4..0000000
--- a/arch/powerpc/boot/prom.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _PPC_BOOT_PROM_H_
-#define _PPC_BOOT_PROM_H_
-
-typedef void *phandle;
-typedef void *ihandle;
-
-extern int (*prom) (void *);
-extern phandle chosen_handle;
-extern ihandle stdout;
-
-int	call_prom(const char *service, int nargs, int nret, ...);
-int	call_prom_ret(const char *service, int nargs, int nret,
-		      unsigned int *rets, ...);
-
-extern int write(void *handle, void *ptr, int nb);
-extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
-
-static inline void exit(void)
-{
-	call_prom("exit", 0, 0);
-}
-
-static inline phandle finddevice(const char *name)
-{
-	return (phandle) call_prom("finddevice", 1, 1, name);
-}
-
-static inline int getprop(void *phandle, const char *name,
-			  void *buf, int buflen)
-{
-	return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
-}
-
-#endif				/* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/boot/sandpoint.c b/arch/powerpc/boot/sandpoint.c
new file mode 100644
index 0000000..dc10e51
--- /dev/null
+++ b/arch/powerpc/boot/sandpoint.c
@@ -0,0 +1,148 @@
+/*
+ * Sandpoint specific fixups.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+#define	CPU_824X	0
+#define	CPU_7XX		1
+#define	CPU_7457	2
+#define	CPU_NUM		3
+
+static u32 cpu_pll[CPU_NUM][32] = {
+	[CPU_824X] = { /* 824x */
+		5, 6, 9, 4, 4, 5, 2, 6, 6, 4, 9, 6, 5, 7, 6, 7,
+		4, 5, 4, 6, 7, 8, 8, 4, 6, 5, 8, 6, 6, 5, 7, 0
+	},
+	[CPU_7XX] = { /* 750/755 */
+		0, 15, 14, 2, 4, 13, 20, 9, 6, 11, 8, 10, 16, 12, 7, 0,
+		0,  0,  0, 0, 0,  0,  0, 0, 0,  0, 0,  0,  0,  0, 0, 0
+
+	},
+	[CPU_7457] = { /* 7457 */
+		23, 34, 15, 30, 14, 36,  2, 40,  4, 42, 13, 26, 17, 48, 19, 18,
+		 6, 21, 11, 22,  8, 20, 10, 24, 16, 28, 12, 32, 27, 56,  0, 25
+	}
+};
+
+static struct processor_info {
+	u32	pvr;
+	u32	mask;
+	u32	bus_freq;
+	u32	hid1_shift;
+	u32	hid1_mask;
+	u32	pll_tbl_idx;
+	u32	max_mem;	/* 7457 flaky with > 64MB of mem */
+} processor_info_tbl[] = { /* From cputable -- MHz are only guesses */
+	/* 824x */
+	{ 0x00810000, 0x7fff0000, 100000000, 27, 0x1f, CPU_824X, 0x80000000 },
+	/* 750 */
+	{ 0x00084202, 0xffffffff, 100000000, 28, 0xf, CPU_7XX, 0x80000000 },
+	/* 745/755 */
+	{ 0x00083000, 0xfffff000, 100000000, 28, 0xf, CPU_7XX, 0x80000000 },
+	/* 7447/7457 Rev 1.0 */
+	{ 0x80020100, 0xffffffff, 100000000, 12, 0x1f, CPU_7457, 0x04000000 },
+	/* 7447/7457 Rev 1.1 */
+	{ 0x80020101, 0xffffffff, 100000000, 12, 0x1f, CPU_7457, 0x04000000 },
+	/* 7447/7457 Rev 1.2 & up*/
+	{ 0x80020000, 0xffff0000, 100000000, 12, 0x1f, CPU_7457, 0x04000000 },
+	/* 7447A */
+	{ 0x80030000, 0xffff0000, 100000000, 12, 0x1f, CPU_7457, 0x80000000 },
+};
+
+static struct processor_info *
+get_processor_info(u32 pvr)
+{
+	struct processor_info *pit = processor_info_tbl;
+	u32 i;
+
+	for (i=0; i<ARRAY_SIZE(processor_info_tbl); i++, pit++)
+		if (pit->pvr == (pvr & pit->mask))
+			return pit;
+	return NULL;
+}
+
+#define	__stringify_1(x)	#x
+#define	__stringify(x)		__stringify_1(x)
+
+
+#define SPRN_PVR	0x11F	/* Processor Version Register */
+#define SPRN_HID1	0x3F1	/* Hardware Implementation Register 1 */
+#define mfspr(rn)	({unsigned long rval; \
+			asm volatile("mfspr %0," __stringify(rn) \
+				: "=r" (rval)); rval;})
+
+static void
+sandpoint_fixups(void)
+{
+	u32 i, v[2], hid1, max_mem = 0xffffffff;
+	void *devp;
+	struct processor_info *pit;
+	extern u32 mpc10x_get_mem_size(void);
+
+	if ((pit = get_processor_info(mfspr(SPRN_PVR)))
+			&& (devp = finddevice("/cpus/PowerPC,603e"))) {
+
+		max_mem = pit->max_mem;
+
+		hid1 = (mfspr(SPRN_HID1) >> pit->hid1_shift) & pit->hid1_mask;
+		v[0] = pit->bus_freq * cpu_pll[pit->pll_tbl_idx][hid1]/2;
+		setprop(devp, "clock-frequency", v, sizeof(v[0]));
+
+		v[0] = pit->bus_freq / 4;
+		setprop(devp, "timebase-frequency", v, sizeof(v[0]));
+	}
+
+	/* Get the RAM size from the memory controller */
+	if ((devp = finddevice("/memory"))) {
+		i = mpc10x_get_mem_size();
+		v[0] = 0;
+		v[1] = min(i, max_mem);
+		setprop(devp, "reg", v, sizeof(v));
+	}
+
+	/* XXXX stuff from platforms/.../sandpoint.c should be here */
+}
+
+static void
+sandpoint_reset(void)
+{
+	void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+	_nmask_and_or_msr(0, (1<<6)); /* Set exception prefix high - firmware */
+
+	/* Reset system via Port 92 */
+	out_8((volatile unsigned char *)0xfe000092, 0x00);
+	out_8((volatile unsigned char *)0xfe000092, 0x01);
+
+	for(;;);	/* Spin until reset happens */
+}
+
+static struct ops sandpoint_ops;
+static struct platform_ops sandpoint_platform_ops;
+
+struct ops *
+platform_init(void *promptr)
+{
+	sandpoint_platform_ops.fixups = sandpoint_fixups;
+	sandpoint_platform_ops.exit = sandpoint_reset;
+
+	sandpoint_ops.platform_ops = &sandpoint_platform_ops;
+	sandpoint_ops.fw_ops = dink_init();
+	sandpoint_ops.dt_ops = fdt_init();
+	sandpoint_ops.console_ops = ns16550_init();
+
+	return &sandpoint_ops;
+}
diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c
new file mode 100644
index 0000000..91d6e91
--- /dev/null
+++ b/arch/powerpc/boot/serial.c
@@ -0,0 +1,90 @@
+/*
+ * Generic serial console support
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Code in serial_edit_cmdline() copied from arch/ppc/boot/simple/misc.c
+ * and was written by Matt Porter <mporter@kernel.crashing.org>.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+extern void udelay(long delay);
+
+int
+serial_open(void)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+	return scdp->open();
+}
+
+void
+serial_write(char *buf, int len)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+
+	while (*buf != '\0')
+		scdp->putc(*buf++);
+}
+
+void
+serial_edit_cmdline(char *buf, int len)
+{
+	int timer = 0, count;
+	char ch, *cp;
+	struct serial_console_data *scdp = ops->console_ops->data;
+
+	cp = buf;
+	count = strlen(buf);
+	cp = &buf[count];
+	count++;
+
+	while (timer++ < 5*1000) {
+		if (scdp->tstc()) {
+			while ((ch = scdp->getc()) != '\n' && ch != '\r') {
+				/* Test for backspace/delete */
+				if (ch == '\b' || ch == '\177') {
+					if (cp != buf) {
+						cp--;
+						count--;
+						printf("\b \b");
+					}
+				/* Test for ^x/^u (and wipe the line) */
+				} else if (ch == '\030' || ch == '\025') {
+					while (cp != buf) {
+						cp--;
+						count--;
+						printf("\b \b");
+					}
+				} else if (count < len) {
+						*cp++ = ch;
+						count++;
+						scdp->putc(ch);
+				}
+			}
+			break;  /* Exit 'timer' loop */
+		}
+		udelay(1000);  /* 1 msec */
+	}
+	*cp = 0;
+}
+
+void
+serial_close(void)
+{
+	struct serial_console_data *scdp = ops->console_ops->data;
+
+	if (scdp->close)
+		scdp->close();
+}
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
index b5aa522..7ccc504 100644
--- a/arch/powerpc/boot/stdio.c
+++ b/arch/powerpc/boot/stdio.c
@@ -10,7 +10,7 @@ #include <stdarg.h>
 #include <stddef.h>
 #include "string.h"
 #include "stdio.h"
-#include "prom.h"
+#include "ops.h"
 
 size_t strnlen(const char * s, size_t count)
 {
@@ -320,6 +320,6 @@ printf(const char *fmt, ...)
 	va_start(args, fmt);
 	n = vsprintf(sprint_buf, fmt, args);
 	va_end(args);
-	write(stdout, sprint_buf, n);
+	ops->console_ops->write(sprint_buf, n);
 	return n;
 }
diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
new file mode 100644
index 0000000..2a2fa2b
--- /dev/null
+++ b/arch/powerpc/boot/types.h
@@ -0,0 +1,29 @@
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#define	COMMAND_LINE_SIZE	512
+#define	MAX_PATH_LEN		256
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef unsigned char		u8;
+typedef unsigned short		u16;
+typedef unsigned int		u32;
+#ifdef __powerpc64__
+typedef unsigned long		u64;
+#else
+typedef unsigned long long	u64;
+#endif
+
+#define min(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);	\
+	_x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+	typeof(x) _x = (x);	\
+	typeof(y) _y = (y);	\
+	(void) (&_x == &_y);	\
+	_x > _y ? _x : _y; })
+
+#endif /* _TYPES_H_ */
diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S
new file mode 100644
index 0000000..c86d3ba
--- /dev/null
+++ b/arch/powerpc/boot/util.S
@@ -0,0 +1,101 @@
+/*
+ * Copied from arch/powerpc/kernel/misc_32.S
+ *
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * 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.
+ *
+ */
+#include "ppc_asm.h"
+
+#define SPRN_PVR        0x11F   /* Processor Version Register */
+
+	.text
+/*
+ * complement mask on the msr then "or" some values on.
+ *     _nmask_and_or_msr(nmask, value_to_or)
+ */
+	.globl _nmask_and_or_msr
+_nmask_and_or_msr:
+	mfmsr	r0		/* Get current msr */
+	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
+	or	r0,r0,r4	/* Or on the bits in r4 (second parm) */
+	SYNC			/* Some chip revs have problems here... */
+	mtmsr	r0		/* Update machine state */
+	isync
+	blr			/* Done */
+
+/* udelay (on non-601 processors) needs to know the period of the
+ * timebase in nanoseconds.  This used to be hardcoded to be 60ns
+ * (period of 66MHz/4).  Now a variable is used that is initialized to
+ * 60 for backward compatibility, but it can be overridden as necessary
+ * with code something like this:
+ *    extern unsigned long timebase_period_ns;
+ *    timebase_period_ns = 1000000000 / bd->bi_tbfreq;
+ */
+	.data
+	.globl timebase_period_ns
+timebase_period_ns:
+	.long	60
+
+	.text
+/*
+ * Delay for a number of microseconds
+ */
+	.globl	udelay
+udelay:
+	mfspr	r4,SPRN_PVR
+	srwi	r4,r4,16
+	cmpwi	0,r4,1		/* 601 ? */
+	bne	.udelay_not_601
+00:	li	r0,86	/* Instructions / microsecond? */
+	mtctr	r0
+10:	addi	r0,r0,0 /* NOP */
+	bdnz	10b
+	subic.	r3,r3,1
+	bne	00b
+	blr
+
+.udelay_not_601:
+	mulli	r4,r3,1000	/* nanoseconds */
+	/*  Change r4 to be the number of ticks using:
+	 *	(nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
+	 *  timebase_period_ns defaults to 60 (16.6MHz) */
+	mflr	r5
+	bl	0f
+0:	mflr	r6
+	mtlr	r5
+	lis	r5,0b@ha
+	addi	r5,r5,0b@l
+	subf	r5,r5,r6	/* In case we're relocated */
+	addis	r5,r5,timebase_period_ns@ha
+	lwz	r5,timebase_period_ns@l(r5)
+	add	r4,r4,r5
+	addi	r4,r4,-1
+	divw	r4,r4,r5	/* BUS ticks */
+1:	mftbu	r5
+	mftb	r6
+	mftbu	r7
+	cmpw	0,r5,r7
+	bne	1b		/* Get [synced] base time */
+	addc	r9,r6,r4	/* Compute end time */
+	addze	r8,r5
+2:	mftbu	r5
+	cmpw	0,r5,r8
+	blt	2b
+	bgt	3f
+	mftb	r6
+	cmpw	0,r6,r9
+	blt	2b
+3:	blr

^ permalink raw reply related

* [PATCH] powerpc: Use soft irq-disable on all 64-bit machines
From: Paul Mackerras @ 2006-06-14  3:31 UTC (permalink / raw)
  To: linuxppc-dev

This patch extends the soft interrupt-disable strategy used on iSeries
so that it applies to all 64-bit machines.  Basically, the idea is
that local_irq_disable() and related functions don't actually change
the MSR_EE (external interrupt enable) bit in the MSR, they just clear
a per-cpu "interrupts enabled" flag.  If an interrupt does come along,
the exception prolog code notices that interrupts are supposed to be
disabled.  It then clears a per-cpu "interrupts are actually enabled"
flag, and returns from the interrupt with MSR_EE clear.

Then, when interrupts later get enabled, we noticed that the
"interrupts are actually enabled" flag got cleared, and set it and the
MSR_EE bit in the MSR.

This should result in improved performance, since setting and clearing
the MSR_EE bit in the MSR can be much more expensive than setting and
clearing a per-cpu flag in memory.  This also reduces the
iSeries-specific differences in the code.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index ff29405..178a725 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -119,6 +119,7 @@ #ifdef CONFIG_PPC64
 	DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1));
 	DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
 	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled));
+	DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
 	DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
 	DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 19ad5c6..434461a 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -29,9 +29,7 @@ #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cputable.h>
 
-#ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
-#endif
 
 /*
  * System calls.
@@ -97,9 +95,9 @@ #ifdef CONFIG_PPC_ISERIES
 	andi.	r10,r12,MSR_PR		/* from kernel */
 	crand	4*cr0+eq,4*cr1+eq,4*cr0+eq
 	beq	hardware_interrupt_entry
+#endif
 	lbz	r10,PACAPROCENABLED(r13)
 	std	r10,SOFTE(r1)
-#endif
 	mfmsr	r11
 	ori	r11,r11,MSR_EE
 	mtmsrd	r11,1
@@ -454,8 +452,8 @@ #else /* !CONFIG_PREEMPT */
 #endif
 
 restore:
-#ifdef CONFIG_PPC_ISERIES
 	ld	r5,SOFTE(r1)
+#ifdef CONFIG_PPC_ISERIES
 	cmpdi	0,r5,0
 	beq	4f
 	/* Check for pending interrupts (iSeries) */
@@ -472,8 +470,9 @@ #ifdef CONFIG_PPC_ISERIES
 	bl	.do_IRQ
 	b	.ret_from_except_lite		/* loop back and handle more */
 
-4:	stb	r5,PACAPROCENABLED(r13)
+4:
 #endif
+	stb	r5,PACAPROCENABLED(r13)
 
 	ld	r3,_MSR(r1)
 	andi.	r0,r3,MSR_RI
@@ -530,20 +529,15 @@ #ifdef CONFIG_PREEMPT
 	/* Check that preempt_count() == 0 and interrupts are enabled */
 	lwz	r8,TI_PREEMPT(r9)
 	cmpwi	cr1,r8,0
-#ifdef CONFIG_PPC_ISERIES
 	ld	r0,SOFTE(r1)
 	cmpdi	r0,0
-#else
-	andi.	r0,r3,MSR_EE
-#endif
 	crandc	eq,cr1*4+eq,eq
 	bne	restore
 	/* here we are preempting the current task */
 1:
-#ifdef CONFIG_PPC_ISERIES
 	li	r0,1
 	stb	r0,PACAPROCENABLED(r13)
-#endif
+	stb	r0,PACAHARDIRQEN(r13)
 	ori	r10,r10,MSR_EE
 	mtmsrd	r10,1		/* reenable interrupts */
 	bl	.preempt_schedule
@@ -626,8 +620,7 @@ _GLOBAL(enter_rtas)
 	/* There is no way it is acceptable to get here with interrupts enabled,
 	 * check it with the asm equivalent of WARN_ON
 	 */
-	mfmsr	r6
-	andi.	r0,r6,MSR_EE
+	lbz	r0,PACAPROCENABLED(r13)
 1:	tdnei	r0,0
 .section __bug_table,"a"
 	.llong	1b,__LINE__ + 0x1000000, 1f, 2f
@@ -636,7 +629,13 @@ _GLOBAL(enter_rtas)
 1:	.asciz	__FILE__
 2:	.asciz "enter_rtas"
 .previous
-	
+
+	/* Hard-disable interrupts */
+	mfmsr	r6
+	rldicl	r7,r6,48,1
+	rotldi	r7,r7,16
+	mtmsrd	r7,1
+
 	/* Unfortunately, the stack pointer and the MSR are also clobbered,
 	 * so they are saved in the PACA which allows us to restore
 	 * our original state after RTAS returns.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index b7d1404..26729e9 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -35,9 +35,7 @@ #include <asm/hvcall.h>
 #include <asm/iseries/lpar_map.h>
 #include <asm/thread_info.h>
 
-#ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
-#endif
 
 /*
  * We layout physical memory as follows:
@@ -296,7 +294,9 @@ #define EXCEPTION_PROLOG_COMMON(n, area)
 	std	r9,_LINK(r1);						   \
 	mfctr	r10;			/* save CTR in stackframe	*/ \
 	std	r10,_CTR(r1);						   \
+	lbz	r10,PACAPROCENABLED(r13);				   \
 	mfspr	r11,SPRN_XER;		/* save XER in stackframe	*/ \
+	std	r10,SOFTE(r1);						   \
 	std	r11,_XER(r1);						   \
 	li	r9,(n)+1;						   \
 	std	r9,_TRAP(r1);		/* set trap number		*/ \
@@ -315,6 +315,34 @@ label##_pSeries:					\
 	HMT_MEDIUM;					\
 	mtspr	SPRN_SPRG1,r13;		/* save r13 */	\
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+
+#define MASKABLE_EXCEPTION_PSERIES(n, label)				\
+	. = n;								\
+	.globl label##_pSeries;						\
+label##_pSeries:							\
+	HMT_MEDIUM;							\
+	mtspr	SPRN_SPRG1,r13;		/* save r13 */			\
+	mfspr	r13,SPRN_SPRG3;		/* get paca address into r13 */	\
+	std	r9,PACA_EXGEN+EX_R9(r13);	/* save r9, r10 */	\
+	std	r10,PACA_EXGEN+EX_R10(r13);				\
+	lbz	r10,PACAPROCENABLED(r13);				\
+	mfcr	r9;							\
+	cmpwi	r10,0;							\
+	beq	masked_interrupt;					\
+	mfspr	r10,SPRN_SPRG1;						\
+	std	r10,PACA_EXGEN+EX_R13(r13);				\
+	std	r11,PACA_EXGEN+EX_R11(r13);				\
+	std	r12,PACA_EXGEN+EX_R12(r13);				\
+	clrrdi	r12,r13,32;		/* get high part of &label */	\
+	mfmsr	r10;							\
+	mfspr	r11,SPRN_SRR0;		/* save SRR0 */			\
+	LOAD_HANDLER(r12,label##_common)				\
+	ori	r10,r10,MSR_IR|MSR_DR|MSR_RI;				\
+	mtspr	SPRN_SRR0,r12;						\
+	mfspr	r12,SPRN_SRR1;		/* and SRR1 */			\
+	mtspr	SPRN_SRR1,r10;						\
+	rfid;								\
+	b	.	/* prevent speculative execution */
 
 #define STD_EXCEPTION_ISERIES(n, label, area)		\
 	.globl label##_iSeries;				\
@@ -338,19 +366,22 @@ label##_iSeries:							\
 	b	label##_common;						\
 
 #ifdef DO_SOFT_DISABLE
+#ifndef CONFIG_PPC_ISERIES
 #define DISABLE_INTS				\
-	lbz	r10,PACAPROCENABLED(r13);	\
 	li	r11,0;				\
-	std	r10,SOFTE(r1);			\
+	stb	r11,PACAPROCENABLED(r13);	\
+	stb	r10,PACAHARDIRQEN(r13)
+#else
+#define DISABLE_INTS				\
+	li	r11,0;				\
 	mfmsr	r10;				\
 	stb	r11,PACAPROCENABLED(r13);	\
 	ori	r10,r10,MSR_EE;			\
 	mtmsrd	r10,1
+#endif
 
 #define ENABLE_INTS				\
-	lbz	r10,PACAPROCENABLED(r13);	\
 	mfmsr	r11;				\
-	std	r10,SOFTE(r1);			\
 	ori	r11,r11,MSR_EE;			\
 	mtmsrd	r11,1
 
@@ -505,11 +536,11 @@ #endif /* __DISABLED__ */
 	mfspr	r12,SPRN_SRR1		/* and SRR1 */
 	b	.slb_miss_realmode	/* Rel. branch works in real mode */
 
-	STD_EXCEPTION_PSERIES(0x500, hardware_interrupt)
+	MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt)
 	STD_EXCEPTION_PSERIES(0x600, alignment)
 	STD_EXCEPTION_PSERIES(0x700, program_check)
 	STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
-	STD_EXCEPTION_PSERIES(0x900, decrementer)
+	MASKABLE_EXCEPTION_PSERIES(0x900, decrementer)
 	STD_EXCEPTION_PSERIES(0xa00, trap_0a)
 	STD_EXCEPTION_PSERIES(0xb00, trap_0b)
 
@@ -552,8 +583,25 @@ system_call_pSeries:
 /*** pSeries interrupt support ***/
 
 	/* moved from 0xf00 */
-	STD_EXCEPTION_PSERIES(., performance_monitor)
+	MASKABLE_EXCEPTION_PSERIES(., performance_monitor)
 
+/*
+ * An interrupt came in while soft-disabled; clear EE in SRR1,
+ * clear paca->hard_enabled and return.
+ */
+masked_interrupt:
+	stb	r10,PACAHARDIRQEN(r13)
+	mtcrf	0x80,r9
+	ld	r9,PACA_EXGEN+EX_R9(r13)
+	mfspr	r10,SPRN_SRR1
+	rldicl	r10,r10,48,1		/* clear MSR_EE */
+	rotldi	r10,r10,16
+	mtspr	SPRN_SRR1,r10
+	ld	r10,PACA_EXGEN+EX_R10(r13)
+	mfspr	r13,SPRN_SPRG1
+	rfid
+	b	.
+
 	.align	7
 _GLOBAL(do_stab_bolted_pSeries)
 	mtcrf	0x80,r12
@@ -902,7 +950,8 @@ #endif
 	REST_8GPRS(2, r1)
 
 	mfmsr	r10
-	clrrdi	r10,r10,2		/* clear RI (LE is 0 already) */
+	rldicl	r10,r10,48,1		/* clear EE */
+	rldicr	r10,r10,16,61		/* clear RI (LE is 0 already) */
 	mtmsrd	r10,1
 
 	mtspr	SPRN_SRR1,r12
@@ -1800,8 +1849,11 @@ _GLOBAL(__secondary_start)
 	/* enable MMU and jump to start_secondary */
 	LOAD_REG_ADDR(r3, .start_secondary_prolog)
 	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
-#ifdef DO_SOFT_DISABLE
+#ifdef CONFIG_PPC_ISERIES
 	ori	r4,r4,MSR_EE
+#else
+	stb	r7,PACAPROCENABLED(r13)
+	stb	r7,PACAHARDIRQEN(r13)
 #endif
 	mtspr	SPRN_SRR0,r3
 	mtspr	SPRN_SRR1,r4
@@ -1953,9 +2005,11 @@ _STATIC(start_here_common)
 
 	/* Load up the kernel context */
 5:
-#ifdef DO_SOFT_DISABLE
 	li	r5,0
 	stb	r5,PACAPROCENABLED(r13)	/* Soft Disabled */
+#ifndef CONFIG_PPC_ISERIES
+	stb	r5,PACAHARDIRQEN(r13)	/* hard-disabled too */
+#else
 	mfmsr	r5
 	ori	r5,r5,MSR_EE		/* Hard Enabled */
 	mtmsrd	r5
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index d85c7c9..5571136 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -31,7 +31,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
 	beqlr
 
 	/* Go to NAP now */
-BEGIN_FTR_SECTION
+	mfmsr	r7
+	rldicl	r0,r7,48,1
+	rotldi	r0,r0,16
+	mtmsrd	r0,1			/* hard-disable interrupts */
+	li	r0,1
+	stb	r0,PACAPROCENABLED(r13)	/* we'll hard-enable shortly */
+	stb	r0,PACAHARDIRQEN(r13)
+BEGIN_FTR_SECTION
 	DSSALL
 	sync
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
@@ -39,7 +46,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	ld	r8,TI_LOCAL_FLAGS(r9)	/* set napping bit */
 	ori	r8,r8,_TLF_NAPPING	/* so when we take an exception */
 	std	r8,TI_LOCAL_FLAGS(r9)	/* it will return to our caller */
-	mfmsr	r7
 	ori	r7,r7,MSR_EE
 	oris	r7,r7,MSR_POW@h
 1:	sync
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 57d560c..2936640 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -90,6 +90,20 @@ EXPORT_SYMBOL(irq_desc);
 
 int distribute_irqs = 1;
 u64 ppc64_interrupt_controller;
+
+#ifndef CONFIG_PPC_ISERIES
+void local_irq_restore(unsigned long en)
+{
+	get_paca()->proc_enabled = en;
+	if (!en || get_paca()->hard_enabled)
+		return;
+	/* need to hard-enable interrupts here */
+	get_paca()->hard_enabled = en;
+	if ((int)mfspr(SPRN_DEC) < 0)
+		mtspr(SPRN_DEC, 1);
+	hard_irq_enable();
+}
+#endif /* CONFIG_PPC_ISERIES */
 #endif /* CONFIG_PPC64 */
 
 int show_interrupts(struct seq_file *p, void *v)
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 4b052ae..38109a3 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -50,6 +50,10 @@ #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
 #endif
 
+#ifdef CONFIG_PPC64
+EXPORT_SYMBOL(local_irq_restore);
+#endif
+
 #ifdef CONFIG_PPC32
 extern void transfer_to_handler(void);
 extern void do_IRQ(struct pt_regs *regs);
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c
index a220084..2430848 100644
--- a/arch/powerpc/platforms/iseries/ksyms.c
+++ b/arch/powerpc/platforms/iseries/ksyms.c
@@ -19,9 +19,3 @@ EXPORT_SYMBOL(HvCall4);
 EXPORT_SYMBOL(HvCall5);
 EXPORT_SYMBOL(HvCall6);
 EXPORT_SYMBOL(HvCall7);
-
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(local_get_flags);
-EXPORT_SYMBOL(local_irq_disable);
-EXPORT_SYMBOL(local_irq_restore);
-#endif
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
index 7641fc7..385a627 100644
--- a/arch/powerpc/platforms/iseries/misc.S
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -19,18 +19,6 @@ #include <asm/ppc_asm.h>
 
 	.text
 
-/* unsigned long local_save_flags(void) */
-_GLOBAL(local_get_flags)
-	lbz	r3,PACAPROCENABLED(r13)
-	blr
-
-/* unsigned long local_irq_disable(void) */
-_GLOBAL(local_irq_disable)
-	lbz	r3,PACAPROCENABLED(r13)
-	li	r4,0
-	stb	r4,PACAPROCENABLED(r13)
-	blr			/* Done */
-
 /* void local_irq_restore(unsigned long flags) */
 _GLOBAL(local_irq_restore)
 	lbz	r5,PACAPROCENABLED(r13)
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index 26b89d8..f231264 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -13,10 +13,21 @@ #include <asm/processor.h>
 
 extern void timer_interrupt(struct pt_regs *);
 
-#ifdef CONFIG_PPC_ISERIES
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
 
-extern unsigned long local_get_flags(void);
-extern unsigned long local_irq_disable(void);
+static inline unsigned long local_get_flags(void)
+{
+	return get_paca()->proc_enabled;
+}
+
+static inline unsigned long local_irq_disable(void)
+{
+	unsigned long flag = get_paca()->proc_enabled;
+	get_paca()->proc_enabled = 0;
+	return flag;
+}
+
 extern void local_irq_restore(unsigned long);
 
 #define local_irq_enable()	local_irq_restore(1)
@@ -24,6 +35,9 @@ #define local_save_flags(flags)	((flags)
 #define local_irq_save(flags)	((flags) = local_irq_disable())
 
 #define irqs_disabled()		(local_get_flags() == 0)
+
+#define hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
+#define hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
 
 #else
 
@@ -82,7 +96,7 @@ #define local_save_flags(flags)	((flags)
 #define local_irq_save(flags)	local_irq_save_ptr(&flags)
 #define irqs_disabled()		((mfmsr() & MSR_EE) == 0)
 
-#endif /* CONFIG_PPC_ISERIES */
+#endif /* CONFIG_PPC64 */
 
 #define mask_irq(irq)						\
 	({							\
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 1740635..75a219c 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -94,6 +94,7 @@ #endif /* CONFIG_PPC_ISERIES */
 	u64 saved_r1;			/* r1 save for RTAS calls */
 	u64 saved_msr;			/* MSR saved here by enter_rtas */
 	u8 proc_enabled;		/* irq soft-enable flag */
+	u8 hard_enabled;		/* set if irqs are enabled in MSR */
 
 	/* Stuff for accurate time accounting */
 	u64 user_time;			/* accumulated usermode TB ticks */

^ permalink raw reply related

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Chuck Meade @ 2006-06-14  2:27 UTC (permalink / raw)
  To: Joakim Tjernlund, 'Kumar Gala', 'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <001301c68f48$24f80890$0e67a8c0@Jocke>

Hi Joakim,

> > > Here you go:
> > 
> > Thanks, now it boot into the ramdisk and a get a login prompt 
> > and all, but I don't see any output during kernel 
> > startup(only a few garbage chars).
> > Tried the console params Alex sent but makes no difference. 
> > How does your cmdline look like?
> 
> ahem, I forgot the obvious console=ttyS0. Now it works, thanks a lot

Sure no problem.

Chuck

^ permalink raw reply

* [PATCH] powerpc: Adding the use of the firmware soft-reset-nmi to kdump.
From: David Wilder @ 2006-06-14  1:58 UTC (permalink / raw)
  To: linuxppc-dev, fastboot, paulus, akpm, Haren Myneni

[-- Attachment #1: Type: text/plain, Size: 3287 bytes --]

-I am reposting this patch based on comments from Paul Mackerras and 
Michael Ellerman requesting updated documentation.

-This patch is build against 2.6.17-rc6-git5 with the following patch 
applied first.
http://lists.osdl.org/pipermail/fastboot/2006-May/002947.html
The above patch must be applied first to prevent a collision in 
include/linux/kexec.h

-My patch includes mostly powerpc specific changes plus a small generic 
change in kernel/kexec.h

- Patch Description
With this patch, kdump uses the firmware soft-rest NMI for two purposes:
1) Initiate the kdump (take a crash dump) by issuing a soft-reset.
2) Break a CPU out of a deadlock condition that is detected during kdump 
processing.

When a soft-reset is initiated each CPU will enter 
system_reset_exception() and set its corresponding bit in the global 
bit-array cpus_in_sr then call die(). When die() finds the CPU’s bit set 
in cpu_in_sr crash_kexec() is called to initiate a crash dump. The first 
CPU to enter crash_kexec() is called the “crashing CPU”. All other CPUs 
are “secondary CPUs”. The secondary CPU’s pass through to 
crash_kexec_secondary() and sleep. The crashing CPU waits for all CPUs 
to enter via soft-reset then boots the kdump kernel (see 
crash_soft_reset_check())

When the system crashes due to a panic or exception, crash_kexec() is 
called by panic() or die(). The crashing CPU sends an IPI to all other 
CPUs to notify them of the pending shutdown. If a CPU is in a deadlock 
or hung state with interrupts disabled, the IPI will not be delivered. 
The result being, that the kdump kernel is not booted. This problem is 
solved with the use of a firmware generated soft-reset. After the 
crashing_cpu has issued the IPI, it waits for 10 sec for all CPUs to 
enter crash_ipi_callback(). A CPU signifies its entry to 
crash_ipi_callback() by setting its corresponding bit in the 
cpus_in_crash bit array. After 10 sec, if one or more CPUs have not set 
their bit in cpus_in_crash we assume that the CPU(s) is deadlocked. The 
operator is then prompted to generate a soft-reset to break the 
deadlock. Each CPU enters the soft reset handler as described above.

Two conditions must be handled at this point:
1) The system crashed because the operator generated a soft-reset. See 
#1 above.
2) The system had crashed before the soft-reset was generated ( in the 
case of a Panic or oops…).

The first CPU to enter crash_kexec() uses the state of the kexec_lock to 
determine this state. If kexec_lock is already held then condition 2 is 
true and crash_kexec_secondary() is called, else; this CPU is flagged as 
the crashing CPU, the kexec_lock is acquired and crash_kexec() proceeds 
as described above.

Each additional CPUs responding to the soft-reset will pass through 
crash_kexec() to kexec_secondary(). All secondary CPUs call 
crash_ipi_callback() readying them self's for the shutdown. When ready 
they clear their bit in cpus_in_sr. The crashing CPU waits in 
kexec_secondary() until all other CPUs have cleared their bits in 
cpus_in_sr. The kexec kernel boot is then started.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
Signed-off-by: David Wilder <dwilder@us.ibm.com>
-- 

David Wilder
IBM Linux Technology Center
Beaverton, Oregon, USA 
dwilder@us.ibm.com
(503)578-3789


[-- Attachment #2: ppc64-softreset-in-k-dump-2.6.17-rc6-git5.patch --]
[-- Type: text/x-patch, Size: 10352 bytes --]

diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 778f22f..d84ca6b 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -23,9 +23,11 @@
 #include <linux/elfcore.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/irq.h>
 
 #include <asm/processor.h>
 #include <asm/machdep.h>
+#include <asm/kexec.h>
 #include <asm/kdump.h>
 #include <asm/lmb.h>
 #include <asm/firmware.h>
@@ -40,6 +42,7 @@
 
 /* This keeps a track of which one is crashing cpu. */
 int crashing_cpu = -1;
+static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 
 static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
 							       size_t data_len)
@@ -97,34 +100,66 @@ static void crash_save_this_cpu(struct p
 }
 
 #ifdef CONFIG_SMP
-static atomic_t waiting_for_crash_ipi;
+static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
 
 void crash_ipi_callback(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
-	if (cpu == crashing_cpu)
-		return;
-
 	if (!cpu_online(cpu))
 		return;
 
-	if (ppc_md.kexec_cpu_down)
-		ppc_md.kexec_cpu_down(1, 1);
-
 	local_irq_disable();
+	if (!cpu_isset(cpu, cpus_in_crash))
+		crash_save_this_cpu(regs, cpu);
+	cpu_set(cpu, cpus_in_crash);
 
-	crash_save_this_cpu(regs, cpu);
-	atomic_dec(&waiting_for_crash_ipi);
+	/*
+	 * Entered via soft-reset - could be the kdump  
+	 * process is invoked using soft-reset or user activated
+	 * it if some CPU did not respond to an IPI.
+	 * For soft-reset, the secondary CPU can enter this func
+	 * twice. 1 - using IPI, and 2. soft-reset.
+	 * Tell the kexec CPU that entered via soft-reset and ready 
+	 * to go down.
+	 */
+	if (cpu_isset(cpu, cpus_in_sr)) {
+		cpu_clear(cpu, cpus_in_sr);
+		atomic_inc(&enter_on_soft_reset);
+	} 
+		
+	/*
+	 * Starting the kdump boot.
+	 * This barrier is needed to make sure that all CPUs are stopped.
+	 * If not, soft-reset will be invoked to bring other CPUs. 
+	 */
+	while (!cpu_isset(crashing_cpu, cpus_in_crash)) 
+		cpu_relax();
+	
+	if (ppc_md.kexec_cpu_down)
+		ppc_md.kexec_cpu_down(1, 1);
 	kexec_smp_wait();
 	/* NOTREACHED */
 }
 
-static void crash_kexec_prepare_cpus(void)
+/*
+ * Wait until all CPUs are entered via soft-reset.
+ */
+static void crash_soft_reset_check(int cpu)
+{
+	unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
+
+	cpu_clear(cpu, cpus_in_sr);
+	while (atomic_read(&enter_on_soft_reset) != ncpus)
+		cpu_relax();
+}
+	
+	
+static void crash_kexec_prepare_cpus(int cpu)
 {
 	unsigned int msecs;
 
-	atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+	unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
 
 	crash_send_ipi(crash_ipi_callback);
 	smp_wmb();
@@ -132,14 +167,13 @@ static void crash_kexec_prepare_cpus(voi
 	/*
 	 * FIXME: Until we will have the way to stop other CPUSs reliabally,
 	 * the crash CPU will send an IPI and wait for other CPUs to
-	 * respond. If not, proceed the kexec boot even though we failed to
-	 * capture other CPU states.
+	 * respond.
 	 * Delay of at least 10 seconds.
 	 */
-	printk(KERN_ALERT "Sending IPI to other cpus...\n");
+	printk(KERN_EMERG "Sending IPI to other cpus...\n");
 	msecs = 10000;
-	while ((atomic_read(&waiting_for_crash_ipi) > 0) && (--msecs > 0)) {
-		barrier();
+	while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) {
+		cpu_relax();
 		mdelay(1);
 	}
 
@@ -148,18 +182,71 @@ static void crash_kexec_prepare_cpus(voi
 	/*
 	 * FIXME: In case if we do not get all CPUs, one possibility: ask the
 	 * user to do soft reset such that we get all.
-	 * IPI handler is already set by the panic cpu initially. Therefore,
-	 * all cpus could invoke this handler from die() and the panic CPU
-	 * will call machine_kexec() directly from this handler to do
-	 * kexec boot.
-	 */
-	if (atomic_read(&waiting_for_crash_ipi))
-		printk(KERN_ALERT "done waiting: %d cpus not responding\n",
-			atomic_read(&waiting_for_crash_ipi));
+	 * Soft-reset will be used until better mechanism is implemented.
+	 */
+	if (cpus_weight(cpus_in_crash) < ncpus) {
+		printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
+			ncpus - cpus_weight(cpus_in_crash));
+		printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
+		cpus_in_sr = CPU_MASK_NONE;
+		atomic_set(&enter_on_soft_reset, 0);
+		while (cpus_weight(cpus_in_crash) < ncpus)
+			cpu_relax();
+	}
+	/*
+	 * Make sure all CPUs are entered via soft-reset if the kdump is
+	 * invoked using soft-reset.
+	 */
+	if (cpu_isset(cpu, cpus_in_sr)) 
+		crash_soft_reset_check(cpu);
 	/* Leave the IPI callback set */
 }
+
+/*
+ * This function will be called by secondary cpus or by kexec cpu 
+ * if soft-reset is activated to stop some CPUs.
+ */
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	unsigned long flags;
+	int msecs = 5;
+
+	local_irq_save(flags);
+	/* Wait 5ms if the kexec CPU is not entered yet. */
+	while (crashing_cpu < 0) {
+		if (--msecs < 0) {
+			/*
+			 * Either kdump image is not loaded or
+			 * kdump process is not started - Probably xmon
+			 * exited using 'x'(exit and recover) or 
+			 * kexec_should_crash() failed for all running tasks.
+			 */
+			cpu_clear(cpu, cpus_in_sr);
+			local_irq_restore(flags);
+			return;
+		}
+		mdelay(1);
+		cpu_relax();
+	}
+	if (cpu == crashing_cpu) {
+		/*
+		 * Panic CPU will enter this func only via soft-reset.
+		 * Wait until all secondary CPUs entered and
+		 * then start kexec boot.
+		 */
+		crash_soft_reset_check(cpu);
+		cpu_set(crashing_cpu, cpus_in_crash);
+		if (ppc_md.kexec_cpu_down)
+			ppc_md.kexec_cpu_down(1, 0);
+		machine_kexec(kexec_crash_image);
+		/* NOTREACHED */
+	}
+	crash_ipi_callback(regs);
+}
+
 #else
-static void crash_kexec_prepare_cpus(void)
+static void crash_kexec_prepare_cpus(int cpu)
 {
 	/*
 	 * move the secondarys to us so that we can copy
@@ -170,6 +257,10 @@ static void crash_kexec_prepare_cpus(voi
 	smp_release_cpus();
 }
 
+void crash_kexec_secondary(struct pt_regs *regs)
+{
+	cpus_in_sr = CPU_MASK_NONE;
+}
 #endif
 
 void default_machine_crash_shutdown(struct pt_regs *regs)
@@ -186,14 +277,14 @@ void default_machine_crash_shutdown(stru
 	 */
 	local_irq_disable();
 
-	if (ppc_md.kexec_cpu_down)
-		ppc_md.kexec_cpu_down(1, 0);
-
 	/*
 	 * Make a note of crashing cpu. Will be used in machine_kexec
 	 * such that another IPI will not be sent.
 	 */
 	crashing_cpu = smp_processor_id();
-	crash_kexec_prepare_cpus();
 	crash_save_this_cpu(regs, crashing_cpu);
+	crash_kexec_prepare_cpus(crashing_cpu);
+	cpu_set(crashing_cpu, cpus_in_crash);
+	if (ppc_md.kexec_cpu_down)
+		ppc_md.kexec_cpu_down(1, 0);
 }
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 064a525..d3c6402 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -51,9 +51,13 @@
 #include <asm/firmware.h>
 #include <asm/processor.h>
 #endif
+#include <asm/kexec.h>
 
 #ifdef CONFIG_PPC64	/* XXX */
 #define _IO_BASE	pci_io_base
+#ifdef CONFIG_KEXEC
+cpumask_t cpus_in_sr = CPU_MASK_NONE;
+#endif
 #endif
 
 #ifdef CONFIG_DEBUGGER
@@ -96,7 +100,7 @@ static DEFINE_SPINLOCK(die_lock);
 
 int die(const char *str, struct pt_regs *regs, long err)
 {
-	static int die_counter, crash_dump_start = 0;
+	static int die_counter;
 
 	if (debugger(regs))
 		return 1;
@@ -128,22 +132,13 @@ int die(const char *str, struct pt_regs 
 	print_modules();
 	show_regs(regs);
 	bust_spinlocks(0);
-
-	if (!crash_dump_start && kexec_should_crash(current)) {
-		crash_dump_start = 1;
-		spin_unlock_irq(&die_lock);
-		crash_kexec(regs);
-		/* NOTREACHED */
-	}
 	spin_unlock_irq(&die_lock);
-	if (crash_dump_start)
-		/*
-		 * Only for soft-reset: Other CPUs will be responded to an IPI
-		 * sent by first kexec CPU.
-		 */
-		for(;;)
-			;
 
+	if (kexec_should_crash(current) ||
+		kexec_sr_activated(smp_processor_id()))
+		crash_kexec(regs);
+	crash_kexec_secondary(regs);
+		
 	if (in_interrupt())
 		panic("Fatal exception in interrupt");
 
@@ -205,6 +200,10 @@ void system_reset_exception(struct pt_re
 		if (ppc_md.system_reset_exception(regs))
 			return;
 	}
+	
+#ifdef CONFIG_KEXEC
+	cpu_set(smp_processor_id(), cpus_in_sr);
+#endif
 
 	die("System Reset", regs, SIGABRT);
 
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 6a2af2f..2a35215 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -31,9 +31,9 @@
 #define KEXEC_ARCH KEXEC_ARCH_PPC
 #endif
 
+#ifndef __ASSEMBLY__
 #ifdef CONFIG_KEXEC
 
-#ifndef __ASSEMBLY__
 #ifdef __powerpc64__
 /*
  * This function is responsible for capturing register states if coming
@@ -114,6 +114,11 @@ extern void kexec_smp_wait(void);	/* get
 extern void __init kexec_setup(void);
 extern int crashing_cpu;
 extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
+extern cpumask_t cpus_in_sr;
+static inline int kexec_sr_activated(int cpu)
+{
+	return cpu_isset(cpu,cpus_in_sr);
+}
 #endif /* __powerpc64 __ */
 
 struct kimage;
@@ -123,8 +128,15 @@ extern int default_machine_kexec_prepare
 extern void default_machine_crash_shutdown(struct pt_regs *regs);
 
 extern void machine_kexec_simple(struct kimage *image);
+extern void crash_kexec_secondary(struct pt_regs *regs);
+extern int overlaps_crashkernel(unsigned long start, unsigned long size);
+extern void reserve_crashkernel(void);
+
+#else /* !CONFIG_KEXEC */
+static inline int kexec_sr_activated(int cpu) { return 0; }
+static inline void crash_kexec_secondary(struct pt_regs *regs) { }
 
-#endif /* ! __ASSEMBLY__ */
 #endif /* CONFIG_KEXEC */
+#endif /* ! __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KEXEC_H */
diff --git a/kernel/kexec.c b/kernel/kexec.c
index f99d69c..950559d 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1042,7 +1042,6 @@ asmlinkage long compat_sys_kexec_load(un
 
 void crash_kexec(struct pt_regs *regs)
 {
-	struct kimage *image;
 	int locked;
 
 
@@ -1056,12 +1055,11 @@ void crash_kexec(struct pt_regs *regs)
 	 */
 	locked = xchg(&kexec_lock, 1);
 	if (!locked) {
-		image = xchg(&kexec_crash_image, NULL);
-		if (image) {
+		if (kexec_crash_image) {
 			struct pt_regs fixed_regs;
 			crash_setup_regs(&fixed_regs, regs);
 			machine_crash_shutdown(&fixed_regs);
-			machine_kexec(image);
+			machine_kexec(kexec_crash_image);
 		}
 		xchg(&kexec_lock, 0);
 	}

^ permalink raw reply related

* Re: [PATCH] powerpc-genirq: Use generic_handle_irq()
From: Josh Boyer @ 2006-06-14  0:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Ingo Molnar, David Woodhouse, Thomas Gleixner
In-Reply-To: <1150240803.13958.66.camel@localhost.localdomain>

On Wed, 2006-06-14 at 09:20 +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2006-06-13 at 07:46 -0500, Josh Boyer wrote:
> > On Tue, 2006-06-13 at 13:39 +0100, David Woodhouse wrote:
> > > On Tue, 2006-06-13 at 05:51 -0500, Josh Boyer wrote:
> > > > It does?  I only see arch/powerpc in the patch.  Is arch/ppc hiding
> > > > somewhere else?
> > > > 
> > > > And yes, arch/ppc still exists.  We can debate that later ;).
> > > 
> > > Did a maintainer step forward for it yet?
> > 
> > For arch/ppc?  Not that I'm aware of.  But that wasn't particularly my
> > point.  The email says "This patch updates the ppc and powerpc
> > architectures..." when it doesn't.
> 
> It does, check again :)

Ugh.  Today is not my day apparently.  Sorry for the noise.

josh

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Joakim Tjernlund @ 2006-06-14  0:19 UTC (permalink / raw)
  To: 'Chuck Meade', 'Kumar Gala',
	'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <001201c68f44$962c1fa0$0e67a8c0@Jocke>

 
> 
> Hi Chuck
> 
> > 
> > > > Hi Joakim,
> > > > 
> > > > Same here -- go into arch/ppc/platforms/83xx and edit file 
> > > > mpc83xx_sys.c.
> > > > If you are using the 8323e cpu, then you need to make sure
> > > 
> > > Yes, got one of those.
> > >  
> > > > that file has code to support the 8323E.  Mine didn't, so
> > I got no
> > > > platform devices initialized (no serial port, no Eth
> > devs).  I added
> > > > a block of code to support the 8323E (set mask to 
> 0xffff0000 and 
> > > > "value" to 0x80620000, then the device list for the 
> 8323E).  Use 
> > > > existing code there as a guide, it was not difficult once
> > I figured
> > > > out that this was the problem.
> > > 
> > > hmm, you don't have a patch handy?
> > 
> > Here you go:
> 
> Thanks, now it boot into the ramdisk and a get a login prompt 
> and all, but I don't see any output during kernel 
> startup(only a few garbage chars).
> Tried the console params Alex sent but makes no difference. 
> How does your cmdline look like?

ahem, I forgot the obvious console=ttyS0. Now it works, thanks a lot

 Jocke

^ permalink raw reply

* Re: 32 bit userland on G5
From: David Woodhouse @ 2006-06-14  0:04 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Johannes Berg
In-Reply-To: <17551.20066.365036.256580@cargo.ozlabs.ibm.com>

On Wed, 2006-06-14 at 09:46 +1000, Paul Mackerras wrote:
> > We already did it in Fedora. We don't default to READ_IMPLIES_EXEC 
> > for 32-bit processes on the 64-bit kernel.
> 
> By patching include/asm-powerpc/elf.h? 

By patching fs/binfmt_elf.c -- it's part of the exec-shield patch.
http://cvs.fedora.redhat.com/viewcvs/devel/kernel/linux-2.6-execshield.patch?rev=1.20&view=auto

shinybook /home/dwmw2 $ cat foo.c
int foo[2] = { 0x3860005a, 0x4e800020 };
int main(void)
{
        int (*foofn)(void) = (void *)foo;
        int f = foofn();
        printf("%x\n", f);
}
shinybook /home/dwmw2 $ ./foo
5a
shinybook /home/dwmw2 $ scp foo pmac: ; ssh pmac
foo                                             100% 9996     9.8KB/s
00:00
Last login: Wed Jun 14 00:58:26 2006 from shinybook-bcm.infradead.org
pmac /home/dwmw2 $ ./foo
Segmentation fault
pmac /home/dwmw2 $ setarch ppc -X ./foo
5a

-- 
dwmw2

^ permalink raw reply

* RE: OpenFirmware framebuffer
From: Benjamin Herrenschmidt @ 2006-06-13 23:53 UTC (permalink / raw)
  To: matt; +Cc: linuxppc-dev, 'Nathan Lynch'
In-Reply-To: <024901c68f06$4aa71f00$99dfdfdf@bakuhatsu.net>

On Tue, 2006-06-13 at 11:27 -0500, Matt Sealey wrote:
> Gentoo 2.6.15-r5 from the 2006.0 install CD.
> 
> It says "Welcome to Linux gentoo-2.6.15-r5" and then I see four
> lines, MSR, HID0 and hex printout of each.
> 
> That's it.
> 
> I get the usual messages spooled to the serial console. My args are;
> 
> boot cd /boot/pegasos console=ttyS1,115200,8n1 console=tty0 init=/linuxrc looptype=squashfs loop=/image.squashfs udev nodevfs cdroot
> root=/dev/ram0 video=ofonly

Send us a copy of your dmesg log. Also, does the pegasos firmware
creates a "display" node in OF with the right type and properties ?

Ben.

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Joakim Tjernlund @ 2006-06-13 23:53 UTC (permalink / raw)
  To: 'Chuck Meade', 'Kumar Gala',
	'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <IIEEICKJLNEPBBDJICNGCEFHLDAA.chuckmeade@mindspring.com>

Hi Chuck

> 
> > > Hi Joakim,
> > > 
> > > Same here -- go into arch/ppc/platforms/83xx and edit file 
> > > mpc83xx_sys.c.
> > > If you are using the 8323e cpu, then you need to make sure
> > 
> > Yes, got one of those.
> >  
> > > that file has code to support the 8323E.  Mine didn't, so 
> I got no 
> > > platform devices initialized (no serial port, no Eth 
> devs).  I added 
> > > a block of code to support the 8323E (set mask to 0xffff0000 and 
> > > "value" to 0x80620000, then the device list for the 8323E).  Use 
> > > existing code there as a guide, it was not difficult once 
> I figured 
> > > out that this was the problem.
> > 
> > hmm, you don't have a patch handy?
> 
> Here you go:

Thanks, now it boot into the ramdisk and a get a login prompt and all, but I don't
see any output during kernel startup(only a few garbage chars).
Tried the console params Alex sent but makes no difference. How does
your cmdline look like?

^ permalink raw reply

* Re: 32 bit userland on G5
From: Paul Mackerras @ 2006-06-13 23:46 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linuxppc-dev list, Johannes Berg
In-Reply-To: <1150241510.11159.159.camel@shinybook.infradead.org>

David Woodhouse writes:

> 'Historical' being until about 4 years ago, around the time of
> http://ecos.sourceware.org/ml/binutils/2002-05/msg00097.html ?

That's not the one I was talking about; that appears to be about
marking the GOT and PLT as executable in the ELF file.  That may be
enough in fact to allow us to turn off read-implies-exec, though.

> We already did it in Fedora. We don't default to READ_IMPLIES_EXEC for
> 32-bit processes on the 64-bit kernel.

By patching include/asm-powerpc/elf.h?

Paul.

^ permalink raw reply

* Re: 32 bit userland on G5
From: David Woodhouse @ 2006-06-13 23:31 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev list, Johannes Berg
In-Reply-To: <17551.16830.186314.247458@cargo.ozlabs.ibm.com>

On Wed, 2006-06-14 at 08:52 +1000, Paul Mackerras wrote:
> Historically the PPC32 ELF ABI has used an executable PLT, containing
> instructions constructed at runtime, located next to the BSS, and
> without the corresponding program header entry indicating execute
> permission.  Alan Modra devised a new way of doing the PLT which
> doesn't require it to be executable, but of course it is only used in
> programs that have been built since the new method went into the
> toolchain (in fact all of the .o files being linked have to have been
> compiled with the new method in order for it to be used).

'Historical' being until about 4 years ago, around the time of
http://ecos.sourceware.org/ml/binutils/2002-05/msg00097.html ?

> So if you are absolutely sure that every program you will ever want to
> run on your kernel has been built with an up-to-date toolchain, you
> can turn on enforcement of execute permissions for 32-bit processes.
> It would be a "courageous" step (in the Yes Minister sense :) for a
> distro to do it, IMHO. 

We already did it in Fedora. We don't default to READ_IMPLIES_EXEC for
32-bit processes on the 64-bit kernel.

-- 
dwmw2

^ permalink raw reply

* Re: [PATCH] powerpc-genirq: Use generic_handle_irq()
From: Benjamin Herrenschmidt @ 2006-06-13 23:20 UTC (permalink / raw)
  To: Josh Boyer
  Cc: linuxppc-dev list, Ingo Molnar, David Woodhouse, Thomas Gleixner
In-Reply-To: <1150202794.29294.5.camel@weaponx.rchland.ibm.com>

On Tue, 2006-06-13 at 07:46 -0500, Josh Boyer wrote:
> On Tue, 2006-06-13 at 13:39 +0100, David Woodhouse wrote:
> > On Tue, 2006-06-13 at 05:51 -0500, Josh Boyer wrote:
> > > It does?  I only see arch/powerpc in the patch.  Is arch/ppc hiding
> > > somewhere else?
> > > 
> > > And yes, arch/ppc still exists.  We can debate that later ;).
> > 
> > Did a maintainer step forward for it yet?
> 
> For arch/ppc?  Not that I'm aware of.  But that wasn't particularly my
> point.  The email says "This patch updates the ppc and powerpc
> architectures..." when it doesn't.

It does, check again :)

Ben.

^ permalink raw reply

* Re: [PATCH] powerpc-genirq: Use generic_handle_irq()
From: Benjamin Herrenschmidt @ 2006-06-13 23:18 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev list, Ingo Molnar, Thomas Gleixner
In-Reply-To: <1150195883.5618.6.camel@vader.jdub.homelinux.org>

On Tue, 2006-06-13 at 05:51 -0500, Josh Boyer wrote:
> On Tue, 2006-06-13 at 13:47 +1000, Benjamin Herrenschmidt wrote:
> > This patch updates the ppc and powerpc architectures to use the new
> > generic_handle_irq() so that interrupt controllers can be ported to the
> > new genirq layer.
> 
> It does?  I only see arch/powerpc in the patch.  Is arch/ppc hiding
> somewhere else?
> 
> And yes, arch/ppc still exists.  We can debate that later ;).

arch/ppc uses arch/powerpc/kernel/irq.c

Ben.

^ permalink raw reply

* Re: 32 bit userland on G5
From: Paul Mackerras @ 2006-06-13 22:52 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linuxppc-dev list, Johannes Berg
In-Reply-To: <1150202709.12423.21.camel@hades.cambridge.redhat.com>

David Woodhouse writes:

> Why? Just because older hardware wasn't capable of enforcing the
> permissions, that doesn't mean that we shouldn't enforce them now.

Historically the PPC32 ELF ABI has used an executable PLT, containing
instructions constructed at runtime, located next to the BSS, and
without the corresponding program header entry indicating execute
permission.  Alan Modra devised a new way of doing the PLT which
doesn't require it to be executable, but of course it is only used in
programs that have been built since the new method went into the
toolchain (in fact all of the .o files being linked have to have been
compiled with the new method in order for it to be used).

So if you are absolutely sure that every program you will ever want to
run on your kernel has been built with an up-to-date toolchain, you
can turn on enforcement of execute permissions for 32-bit processes.
It would be a "courageous" step (in the Yes Minister sense :) for a
distro to do it, IMHO.

Paul.

^ permalink raw reply

* Re: 32 bit userland on G5
From: Paul Mackerras @ 2006-06-13 22:44 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linuxppc-dev list
In-Reply-To: <1150194348.9208.33.camel@johannes>

Johannes Berg writes:

> Since apparently the G5 honours no-execute permissions, shouldn't the 64
> bit kernel set the READ_IMPLIES_EXEC personality flag for 32-bit
> userland?

The elf_read_implies_exec() macro in include/asm-powerpc/elf.h
achieves the same effect, I believe.

Paul.

^ permalink raw reply

* USB flashdrive on Motorola MPC5200 (IceCube) board, linux kernel 2.4.20
From: Furxhi, Orges @ 2006-06-13 22:10 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 10999 bytes --]

Hi all,

 

I have been trying for days now to get my usb flashdrive to work on my
Motorola MPC5200 (IceCube) board running on the 2.4.20 linux kernel. I have
followed the instruction in this Flash Memory HOWTO  article
(http://www.tldp.org/HOWTO/Flash-Memory-HOWTO/index.html
<http://www.tldp.org/HOWTO/Flash-Memory-HOWTO/index.html> ), but I have had
no success.

When I mount the usbfs filesystem (mount -t usbfs none /proc/bus/usb/) the
following 3 items are  created in the /proc/bus/usb/ directory:

dr-xr-xr-x    1 root     root            0 Jan  1 00:12 001

-r--r--r--    1 root     root            0 Jan  1 00:12 devices

-r--r--r--    1 root     root            0 Jan  1 00:12 drivers

 

# cat devices shows:

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2

B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0

D:  Ver= 1.10 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1

P:  Vendor=0000 ProdID=0000 Rev= 0.00

S:  Product=USB OHCI Root Hub

S:  SerialNumber=f0001000

C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA

I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub

E:  Ad=81(I) Atr=03(Int.) MxPS=   2 Ivl=255ms

 

# cat drivers  shows

         usbdevfs

         hub

         usb-storage

 

In the this Flash Memory-HOWTO it is mentioned that the usb-storage-x
directory will be created in the /proc/scsi/ directory, but I do not see it
on my system. Also the contents of  /proc/scsi/scsi  are "Attached devices:
none". 

 

Following are my boot up messages:

 

U-Boot 1.1.4 (Mar 21 2006 - 15:07:57)

 

CPU:   MPC5200 v1.2 at 462 MHz

       Bus 132 MHz, IPB 66 MHz, PCI 33 MHz

Board: Motorola MPC5200 (IceCube)

I2C:   85 kHz, ready

DRAM:  64 MB

FLASH:  8 MB

In:    serial

Out:   serial

Err:   serial

Net:   FEC ETHERNET

 

Type "run flash_nfs" to mount root filesystem over NFS

 

Hit any key to stop autoboot:  0

## Booting image at ff900000 ...

   Image Name:   Linux-2.4.20_mvl31-lite5200

   Created:      2006-06-13  21:40:05 UTC

   Image Type:   PowerPC Linux Kernel Image (gzip compressed)

   Data Size:    989480 Bytes = 966.3 kB

   Load Address: 00000000

   Entry Point:  00000000

   Verifying Checksum ... OK

   Uncompressing Kernel Image ... OK

Memory BAT mapping: BAT2=64Mb, BAT3=0Mb, residual: 0Mb

Linux version 2.4.20_mvl31-lite5200 (ofurxhi@mdc58503) (gcc version 3.3.1
(Monta

Vista 3.3.1-7.0.13.0500039 2005-01-12)) #11 Tue Jun 13 16:32:09 CDT 2006

On node 0 totalpages: 16384

zone(0): 16384 pages.

zone(1): 0 pages.

zone(2): 0 pages.

Kernel command line: root=/dev/mtdblock2 rw rootfstype=jffs2
ip=192.168.0.7:192.

168.0.2:192.168.0.2:255.255.255.0:cpua::off

frequencies: cpu=461995100, bus=131998608, ipb=65999304, pci=32999652

Calibrating delay loop... 307.20 BogoMIPS

Memory: 62460k available (1540k kernel code, 524k data, 240k init, 0k
highmem)

Dentry cache hash table entries: 8192 (order: 4, 65536 bytes)

Inode cache hash table entries: 4096 (order: 3, 32768 bytes)

Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)

Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)

Page-cache hash table entries: 16384 (order: 4, 65536 bytes)

POSIX conformance testing by UNIFIX

PCI: Probing PCI hardware

PCI: Cannot allocate resource region 1 of device 00:00.0

PCI: Cannot allocate resource region 1 of device 00:01.0

PCI: Cannot allocate resource region 1 of device 00:02.0

PCI: Cannot allocate resource region 1 of device 00:03.0

PCI: Cannot allocate resource region 1 of device 00:04.0

PCI: Cannot allocate resource region 1 of device 00:05.0

PCI: Cannot allocate resource region 1 of device 00:06.0

PCI: Cannot allocate resource region 1 of device 00:07.0

PCI: Cannot allocate resource region 1 of device 00:08.0

PCI: Cannot allocate resource region 1 of device 00:09.0

PCI: Cannot allocate resource region 1 of device 00:0a.0

PCI: Cannot allocate resource region 1 of device 00:0b.0

PCI: Cannot allocate resource region 1 of device 00:0c.0

PCI: Cannot allocate resource region 1 of device 00:0d.0

PCI: Cannot allocate resource region 1 of device 00:0e.0

PCI: Cannot allocate resource region 1 of device 00:0f.0

PCI: Cannot allocate resource region 1 of device 00:10.0

PCI: Cannot allocate resource region 1 of device 00:11.0

PCI: Cannot allocate resource region 1 of device 00:12.0

PCI: Cannot allocate resource region 1 of device 00:13.0

PCI: Cannot allocate resource region 1 of device 00:14.0

PCI: Cannot allocate resource region 1 of device 00:15.0

PCI: Cannot allocate resource region 1 of device 00:16.0

PCI: Cannot allocate resource region 1 of device 00:17.0

PCI: Cannot allocate resource region 1 of device 00:18.0

PCI: Cannot allocate resource region 1 of device 00:19.0

PCI: Cannot allocate resource region 1 of device 00:1a.0

PCI: Cannot allocate resource region 1 of device 00:1b.0

PCI: Cannot allocate resource region 1 of device 00:1c.0

PCI: Cannot allocate resource region 1 of device 00:1d.0

PCI: Cannot allocate resource region 1 of device 00:1e.0

Linux NET4.0 for Linux 2.4

Based upon Swansea University Computer Society NET3.039

Initializing RT netlink socket

LSP Revision 52

ikconfig 0.5 with /proc/ikconfig

Starting kswapd

Disabling the Out Of Memory Killer

Journalled Block Device driver loaded

devfs: v1.12c (20020818) Richard Gooch (rgooch@atnf.csiro.au)

devfs: boot_options: 0x1

JFFS version 1.0, (C) 1999, 2000  Axis Communications AB

JFFS2 version 2.1. (C) 2001, 2002 Red Hat, Inc., designed by Axis
Communications

 AB.

pty: 256 Unix98 ptys configured

RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize

loop: loaded (max 8 devices)

Universal TUN/TAP device driver 1.5 (C)1999-2002 Maxim Krasnyansky

SCSI subsystem driver Revision: 1.00

kmod: failed to exec /sbin/modprobe -s -k scsi_hostadapter, errno = 2

kmod: failed to exec /sbin/modprobe -s -k scsi_hostadapter, errno = 2

NO QRY response

cfi_cmdset_0001: Erase suspend on write enabled

Using buffer write method

Icecube flash bank 0: Using static image partition definition

Creating 3 MTD partitions on "Icecube Bank 0":

0x00000000-0x00100000 : "u-boot"

0x00100000-0x00200000 : "kernel"

0x00200000-0x00800000 : "jffs2"

usb.c: registered new driver usbdevfs

usb.c: registered new driver hub

usb-ohci.c: USB OHCI at membase 0xf0001000, IRQ 44

usb.c: new USB bus registered, assigned bus number 1

Product: USB OHCI Root Hub

SerialNumber: f0001000

hub.c: USB hub found

hub.c: 2 ports detected

Initializing USB Mass Storage driver...

usb.c: registered new driver usb-storage

USB Mass Storage support registered.

eth0: Phy @ 0x0, type LXT971 (0x001378e2)

NET4: Linux TCP/IP 1.0 for NET4.0

IP Protocols: ICMP, UDP, TCP, IGMP

IP: routing cache hash table of 512 buckets, 4Kbytes

TCP: Hash tables configured (established 4096 bind 8192)

eth0: config: auto-negotiation off, 100HDX, 10HDX.

IP-Config: Complete:

      device=eth0, addr=192.168.0.7, mask=255.255.255.0, gw=192.168.0.2,

     host=cpua, domain=, nis-domain=(none),

     bootserver=192.168.0.2, rootserver=192.168.0.2, rootpath=

NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.

Empty flash at 0x0000fffc ends at 0x00010000

CLEANMARKER node found at 0x00010000, not first node in block (0x00000000)

Empty flash at 0x0002fffc ends at 0x00030000

CLEANMARKER node found at 0x00030000, not first node in block (0x00020000)

Empty flash at 0x0004fffc ends at 0x00050000

CLEANMARKER node found at 0x00050000, not first node in block (0x00040000)

Empty flash at 0x0006fffc ends at 0x00070000

CLEANMARKER node found at 0x00070000, not first node in block (0x00060000)

Empty flash at 0x0008fffc ends at 0x00090000

CLEANMARKER node found at 0x00090000, not first node in block (0x00080000)

Empty flash at 0x000afffc ends at 0x000b0000

CLEANMARKER node found at 0x000b0000, not first node in block (0x000a0000)

Empty flash at 0x000cfffc ends at 0x000d0000

CLEANMARKER node found at 0x000d0000, not first node in block (0x000c0000)

Empty flash at 0x000efffc ends at 0x000f0000

CLEANMARKER node found at 0x000f0000, not first node in block (0x000e0000)

Empty flash at 0x0010fffc ends at 0x00110000

CLEANMARKER node found at 0x00110000, not first node in block (0x00100000)

Empty flash at 0x0012fffc ends at 0x00130000

CLEANMARKER node found at 0x00130000, not first node in block (0x00120000)

Empty flash at 0x0014fffc ends at 0x00150000

CLEANMARKER node found at 0x00150000, not first node in block (0x00140000)

Empty flash at 0x0016fffc ends at 0x00170000

CLEANMARKER node found at 0x00170000, not first node in block (0x00160000)

Empty flash at 0x0018fffc ends at 0x00190000

CLEANMARKER node found at 0x00190000, not first node in block (0x00180000)

Empty flash at 0x001afffc ends at 0x001b0000

CLEANMARKER node found at 0x001b0000, not first node in block (0x001a0000)

Empty flash at 0x001cfffc ends at 0x001d0000

CLEANMARKER node found at 0x001d0000, not first node in block (0x001c0000)

Empty flash at 0x001efffc ends at 0x001f0000

CLEANMARKER node found at 0x001f0000, not first node in block (0x001e0000)

Empty flash at 0x0020fffc ends at 0x00210000

CLEANMARKER node found at 0x00210000, not first node in block (0x00200000)

Empty flash at 0x0022fffc ends at 0x00230000

CLEANMARKER node found at 0x00230000, not first node in block (0x00220000)

Empty flash at 0x0024fffc ends at 0x00250000

CLEANMARKER node found at 0x00250000, not first node in block (0x00240000)

Empty flash at 0x0026fffc ends at 0x00270000

CLEANMARKER node found at 0x00270000, not first node in block (0x00260000)

VFS: Mounted root (jffs2 filesystem).

Mounted devfs on /dev

Freeing unused kernel memory: 240k init

serial console detected.  Disabling virtual terminals.

init started:  BusyBox v0.60.3 (2004.01.09-22:53+0000) multi-call binary

Initializing iocspi

Warning: loading /lib/modules/iocspim.o will taint the kernel: no license

  See http://www.tux.org/lkml/#export-tainted for information about tainted
modu

les

iocspi: release_20060418

iocspi: major 254.

Module iocspim loaded, with warnings

Initializing canspi

Warning: loading /lib/modules/canspim.o will taint the kernel: no license

  See http://www.tux.org/lkml/#export-tainted for information about tainted
modu

les

canspi: init_module()

canspi: init_module(): sema_init

canspi: init_module(): register_chrdev

canspi: major 253.

canspi: micro_config()

canspi: micro_config: PSC request_irq failed (0)

canspi: micro_config psc=f0002400 cdm=f0000200 gpio=f0000b00
portcfg=10051004

Module canspim loaded, with warnings

Initializing iocdrv

Warning: loading /lib/modules/iocdrvm.o will taint the kernel: no license

  See http://www.tux.org/lkml/#export-tainted for information about tainted
modu

les

iocdrv: release_20060502

iocdrv: major 252.

Module iocdrvm loaded, with warnings

System initialized

 

MontaVista(R) Linux(R) Professional Edition 3.1

 

cpua login: 

 

 

Any help would be highly appreciated.

 

Thank you,

 

Orges Furxhi 


[-- Attachment #2: Type: text/html, Size: 43615 bytes --]

^ permalink raw reply

* Re: No ttyS device at I/O port 0xfe004500 for console
From: Kumar Gala @ 2006-06-13 22:32 UTC (permalink / raw)
  To: Chuck Meade; +Cc: linuxppc-embedded, Joakim Tjernlund
In-Reply-To: <IIEEICKJLNEPBBDJICNGCEFHLDAA.chuckmeade@mindspring.com>

> Here you go:

Let me know if this fixes the issues you guys are seeing with your  
83xx boards.  If so, I'll clean up this patch and push it upstream.

- k

> --- mpc83xx_sys.c-ORIG	2006-06-13 17:54:36.577339832 -0400
> +++ mpc83xx_sys.c	2006-06-13 17:56:02.394293672 -0400
> @@ -136,6 +136,23 @@ struct ppc_sys_spec ppc_sys_specs[] = {
>  #endif
>  		},
>  	},
> +	{
> +		.ppc_sys_name	= "8323E",
> +		.mask		= 0xFFFF0000,
> +		.value		= 0x80620000,
> +#ifdef CONFIG_QE
> +		.num_devices	= 4,
> +#else
> +		.num_devices	= 2,
> +#endif
> +		.device_list	= (enum ppc_sys_devices[])
> +		{
> +			MPC83xx_IIC1, MPC83xx_DUART,
> +#ifdef CONFIG_QE
> +			MPC83xx_QE_UCC3, MPC83xx_QE_UCC4,
> +#endif
> +		},
> +	},
>  	{	/* default match */
>  		.ppc_sys_name	= "",
>  		.mask 		= 0x00000000,
>
>
> Regards,
> Chuck
>

^ permalink raw reply

* Suspend-to-RAM?
From: Guennadi Liakhovetski @ 2006-06-13 22:02 UTC (permalink / raw)
  To: Linuxppc-embedded

Hi

Do I understand it right that in the stock 2.6.17-rc... kernels 
suspend-to-RAM is not available to any embedded ppc processors / boards? 
Only for powermac? Is it for a reason (which one?) or just nobody has done 
/ submitted to mainline this?

Thanks
Guennadi
---
Guennadi Liakhovetski

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Chuck Meade @ 2006-06-13 22:01 UTC (permalink / raw)
  To: Joakim Tjernlund, 'Kumar Gala', 'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <001101c68f31$d89aa220$0e67a8c0@Jocke>

> > Hi Joakim,
> > 
> > Same here -- go into arch/ppc/platforms/83xx and edit file 
> > mpc83xx_sys.c.
> > If you are using the 8323e cpu, then you need to make sure
> 
> Yes, got one of those.
>  
> > that file has code to support the 8323E.  Mine didn't, so I 
> > got no platform devices initialized (no serial port, no Eth 
> > devs).  I added a block of code to support the 8323E (set 
> > mask to 0xffff0000 and "value" to 0x80620000, then the device 
> > list for the 8323E).  Use existing code there as a guide, it 
> > was not difficult once I figured out that this was the problem.
> 
> hmm, you don't have a patch handy?

Here you go:

--- mpc83xx_sys.c-ORIG	2006-06-13 17:54:36.577339832 -0400
+++ mpc83xx_sys.c	2006-06-13 17:56:02.394293672 -0400
@@ -136,6 +136,23 @@ struct ppc_sys_spec ppc_sys_specs[] = {
 #endif
 		},
 	},
+	{
+		.ppc_sys_name	= "8323E",
+		.mask		= 0xFFFF0000,
+		.value		= 0x80620000,
+#ifdef CONFIG_QE
+		.num_devices	= 4,
+#else
+		.num_devices	= 2,
+#endif
+		.device_list	= (enum ppc_sys_devices[])
+		{
+			MPC83xx_IIC1, MPC83xx_DUART,
+#ifdef CONFIG_QE
+			MPC83xx_QE_UCC3, MPC83xx_QE_UCC4,
+#endif
+		},
+	},
 	{	/* default match */
 		.ppc_sys_name	= "",
 		.mask 		= 0x00000000,


Regards,
Chuck

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Chuck Meade @ 2006-06-13 21:25 UTC (permalink / raw)
  To: Joakim Tjernlund, 'Kumar Gala', 'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <000f01c68f2a$68b83960$0e67a8c0@Jocke>

> > On Jun 13, 2006, at 11:48 AM, Alex Zeffertt wrote:
> > 
> > > Hi list,
> > >
> > > I'm trying to boot a linux-2.6.11 kernel on a MPC83xx based 
> > board.   
> > > Through
> > > some experimentation I have found I need 
> > "console=uart,io,0xfe004500"
> > > in the kernel command line in order to get any output over 
> > the serial 
> > > port.
> > >
> > > Half way through initialisation the kernel appears to swap from its 
> > > "early"
> > > 8250 serial driver to a "full" 8250 serial driver.  At this 
> > point it 
> > > prints "No ttyS device at I/O port 0xfe004500 for console" 
> > and there 
> > > is no further output.
> > >
> > > Does anyone have any idea what I may be doing wrong?
> > >
> > > BTW, here's the output that I do get.
> > 
> > Alex, where did you get this 2.6.11 kernel?  The public tree 
> > didn't have support for 83xx in 2.6.11.  I'd suggest looking 
> > at using something newer like 2.6.16 and see if you have the 
> > same issue.
> 
> I suspect he got from the same place I did, freescales LTIB dev. env.
> which has been patched to support 832x. I am having the same problem as he
> has, any info on what the problem might be would be great.
> 
> Also, if anyone has any info on when these patches will be sent upstream, I 
> sure would like to hear about it.
> 
>  Jocke

Hi Joakim,

Same here -- go into arch/ppc/platforms/83xx and edit file mpc83xx_sys.c.
If you are using the 8323e cpu, then you need to make sure that file has
code to support the 8323E.  Mine didn't, so I got no platform devices 
initialized (no serial port, no Eth devs).  I added a block of code to support
the 8323E (set mask to 0xffff0000 and "value" to 0x80620000, then the 
device list for the 8323E).  Use existing code there as a guide, it was not
difficult once I figured out that this was the problem.

If you are using a newer LTIB release than me, perhaps yours is fixed.
The one I have is from 3/15/06.

Anyway, this works fine for me and addresses the problem of the platform
devs not getting initialized.

Chuck

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Joakim Tjernlund @ 2006-06-13 21:39 UTC (permalink / raw)
  To: 'Chuck Meade', 'Kumar Gala',
	'Alex Zeffertt'
  Cc: linuxppc-embedded
In-Reply-To: <IIEEICKJLNEPBBDJICNGKEFDLDAA.chuckmeade@mindspring.com>

> > 
> > I suspect he got from the same place I did, freescales LTIB 
> dev. env.
> > which has been patched to support 832x. I am having the 
> same problem 
> > as he has, any info on what the problem might be would be great.
> > 
> > Also, if anyone has any info on when these patches will be sent 
> > upstream, I sure would like to hear about it.
> > 
> >  Jocke
> 
> Hi Joakim,
> 
> Same here -- go into arch/ppc/platforms/83xx and edit file 
> mpc83xx_sys.c.
> If you are using the 8323e cpu, then you need to make sure

Yes, got one of those.
 
> that file has code to support the 8323E.  Mine didn't, so I 
> got no platform devices initialized (no serial port, no Eth 
> devs).  I added a block of code to support the 8323E (set 
> mask to 0xffff0000 and "value" to 0x80620000, then the device 
> list for the 8323E).  Use existing code there as a guide, it 
> was not difficult once I figured out that this was the problem.

hmm, you don't have a patch handy?

> 
> If you are using a newer LTIB release than me, perhaps yours is fixed.
> The one I have is from 3/15/06.

Me too, I have requested that freescale release a new LTIB with proper support,
but who knows when the will be.

> 
> Anyway, this works fine for me and addresses the problem of 
> the platform devs not getting initialized.
> 
> Chuck
> 
> 
> 

^ permalink raw reply

* Re: OpenFirmware framebuffer
From: David Woodhouse @ 2006-06-13 21:33 UTC (permalink / raw)
  To: matt; +Cc: linuxppc-dev
In-Reply-To: <021501c68efd$bc311080$99dfdfdf@bakuhatsu.net>

On Tue, 2006-06-13 at 10:26 -0500, Matt Sealey wrote:
> I just booted up my Pegasos and tried the offb driver for display and was
> rather disappointed. It just displays 4 lines about HID0 and stuff and then
> waits around. 

I didn't think the Pegasos firmware supported framebuffer?

-- 
dwmw2

^ permalink raw reply

* RE: No ttyS device at I/O port 0xfe004500 for console
From: Joakim Tjernlund @ 2006-06-13 21:20 UTC (permalink / raw)
  To: 'Alex Zeffertt', linuxppc-embedded
In-Reply-To: <448EEC59.2010201@cambridgebroadband.com>

 

> -----Original Message-----
> From: 
> linuxppc-embedded-bounces+joakim.tjernlund=lumentis.se@ozlabs.
> org 
> [mailto:linuxppc-embedded-bounces+joakim.tjernlund=lumentis.se
> @ozlabs.org] On Behalf Of Alex Zeffertt
> Sent: den 13 juni 2006 18:48
> To: linuxppc-embedded@ozlabs.org
> Subject: No ttyS device at I/O port 0xfe004500 for console
> 
> Hi list,
> 
> I'm trying to boot a linux-2.6.11 kernel on a MPC83xx based 
> board.  Through some experimentation I have found I need 
> "console=uart,io,0xfe004500"
> in the kernel command line in order to get any output over 
> the serial port.

Alex, can you post your complete u-boot env(printenv). I am trying to do
the same as you but I havn't gotten any output yet. I managed to wipe my
u-boot & u-boot env and the docs arent that great :(

 Jocke

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox