* [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", ®_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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox