From 437a58db57c61385baaa1cb8b7fa590b6a2f1607 Mon Sep 17 00:00:00 2001
From: Paul Mackerras <paulus@samba.org>
Date: Fri, 18 Nov 2005 15:43:34 +1100
Subject: powerpc: Move remaining .c files from arch/ppc64 to arch/powerpc

This also deletes the now-unused Makefiles under arch/ppc64.

Both of the files moved over could use some merging, but for now I
have moved them as-is and arranged for them to be used only in 64-bit
kernels.  For 32-bit kernels we still use arch/ppc/kernel/idle.c and
drivers/char/generic_nvram.c as before.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/Makefile          |   4 +-
 arch/powerpc/kernel/Makefile   |   5 +-
 arch/powerpc/kernel/idle_64.c  | 121 +++++++
 arch/powerpc/kernel/nvram_64.c | 742 +++++++++++++++++++++++++++++++++++++++++
 arch/ppc64/Makefile            | 142 --------
 arch/ppc64/kernel/Makefile     |   7 -
 arch/ppc64/kernel/idle.c       | 121 -------
 arch/ppc64/kernel/nvram.c      | 742 -----------------------------------------
 8 files changed, 869 insertions(+), 1015 deletions(-)
 create mode 100644 arch/powerpc/kernel/idle_64.c
 create mode 100644 arch/powerpc/kernel/nvram_64.c
 delete mode 100644 arch/ppc64/Makefile
 delete mode 100644 arch/ppc64/kernel/Makefile
 delete mode 100644 arch/ppc64/kernel/idle.c
 delete mode 100644 arch/ppc64/kernel/nvram.c

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 99dbea8c5c5..987036b60c8 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -125,11 +125,11 @@ head-$(CONFIG_PPC64)		+= arch/powerpc/kernel/entry_64.o
 head-$(CONFIG_PPC_FPU)		+= arch/powerpc/kernel/fpu.o
 
 core-y				+= arch/powerpc/kernel/ \
-				   arch/$(OLDARCH)/kernel/ \
 				   arch/powerpc/mm/ \
 				   arch/powerpc/lib/ \
 				   arch/powerpc/sysdev/ \
 				   arch/powerpc/platforms/
+core-$(CONFIG_PPC32)		+= arch/ppc/kernel/
 core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
 core-$(CONFIG_APUS)		+= arch/ppc/amiga/
@@ -165,7 +165,7 @@ define archhelp
   @echo '                    (your) ~/bin/installkernel or'
   @echo '                    (distribution) /sbin/installkernel or'
   @echo '                    install to $$(INSTALL_PATH) and run lilo'
-  @echo '  *_defconfig     - Select default config from arch/$(ARCH)/ppc/configs'
+  @echo '  *_defconfig     - Select default config from arch/$(ARCH)/configs'
 endef
 
 archclean:
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 0e679afb2e2..9ed551b6c17 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -17,7 +17,7 @@ obj-y				+= vdso32/
 obj-$(CONFIG_PPC64)		+= setup_64.o binfmt_elf32.o sys_ppc32.o \
 				   signal_64.o ptrace32.o systbl.o \
 				   paca.o ioctl32.o cpu_setup_power4.o \
-				   firmware.o sysfs.o udbg.o
+				   firmware.o sysfs.o udbg.o idle_64.o
 obj-$(CONFIG_PPC64)		+= vdso64/
 obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
 obj-$(CONFIG_POWER4)		+= idle_power4.o
@@ -35,6 +35,7 @@ obj-$(CONFIG_PPC_PSERIES)	+= udbg_16550.o
 obj-$(CONFIG_PPC_MAPLE)		+= udbg_16550.o
 udbgscc-$(CONFIG_PPC64)		:= udbg_scc.o
 obj-$(CONFIG_PPC_PMAC)		+= $(udbgscc-y)
+obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 
@@ -78,5 +79,7 @@ smpobj-$(CONFIG_SMP)		+= smp.o
 
 endif
 
+obj-$(CONFIG_PPC64)		+= $(obj64-y)
+
 extra-$(CONFIG_PPC_FPU)		+= fpu.o
 extra-$(CONFIG_PPC64)		+= entry_64.o
diff --git a/arch/powerpc/kernel/idle_64.c b/arch/powerpc/kernel/idle_64.c
new file mode 100644
index 00000000000..b879d3057ef
--- /dev/null
+++ b/arch/powerpc/kernel/idle_64.c
@@ -0,0 +1,121 @@
+/*
+ * Idle daemon for PowerPC.  Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Originally Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com>
+ *
+ * Additional shared processor, SMT, and firmware support
+ *    Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com>
+ *
+ * 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 <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/sysctl.h>
+
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/smp.h>
+
+extern void power4_idle(void);
+
+void default_idle(void)
+{
+	unsigned int cpu = smp_processor_id();
+	set_thread_flag(TIF_POLLING_NRFLAG);
+
+	while (1) {
+		if (!need_resched()) {
+			while (!need_resched() && !cpu_is_offline(cpu)) {
+				ppc64_runlatch_off();
+
+				/*
+				 * Go into low thread priority and possibly
+				 * low power mode.
+				 */
+				HMT_low();
+				HMT_very_low();
+			}
+
+			HMT_medium();
+		}
+
+		ppc64_runlatch_on();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+			cpu_die();
+	}
+}
+
+void native_idle(void)
+{
+	while (1) {
+		ppc64_runlatch_off();
+
+		if (!need_resched())
+			power4_idle();
+
+		if (need_resched()) {
+			ppc64_runlatch_on();
+			preempt_enable_no_resched();
+			schedule();
+			preempt_disable();
+		}
+
+		if (cpu_is_offline(smp_processor_id()) &&
+		    system_state == SYSTEM_RUNNING)
+			cpu_die();
+	}
+}
+
+void cpu_idle(void)
+{
+	BUG_ON(NULL == ppc_md.idle_loop);
+	ppc_md.idle_loop();
+}
+
+int powersave_nap;
+
+#ifdef CONFIG_SYSCTL
+/*
+ * Register the sysctl to set/clear powersave_nap.
+ */
+static ctl_table powersave_nap_ctl_table[]={
+	{
+		.ctl_name	= KERN_PPC_POWERSAVE_NAP,
+		.procname	= "powersave-nap",
+		.data		= &powersave_nap,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{ 0, },
+};
+static ctl_table powersave_nap_sysctl_root[] = {
+	{ 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, },
+ 	{ 0,},
+};
+
+static int __init
+register_powersave_nap_sysctl(void)
+{
+	register_sysctl_table(powersave_nap_sysctl_root, 0);
+
+	return 0;
+}
+__initcall(register_powersave_nap_sysctl);
+#endif
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
new file mode 100644
index 00000000000..c0fcd29918c
--- /dev/null
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -0,0 +1,742 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ * /dev/nvram driver for PPC64
+ *
+ * This perhaps should live in drivers/char
+ *
+ * TODO: Split the /dev/nvram part (that one can use
+ *       drivers/char/generic_nvram.c) from the arch & partition
+ *       parsing code.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/nvram.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+#undef DEBUG_NVRAM
+
+static int nvram_scan_partitions(void);
+static int nvram_setup_partition(void);
+static int nvram_create_os_partition(void);
+static int nvram_remove_os_partition(void);
+
+static struct nvram_partition * nvram_part;
+static long nvram_error_log_index = -1;
+static long nvram_error_log_size = 0;
+
+int no_logging = 1; 	/* Until we initialize everything,
+			 * make sure we don't try logging
+			 * anything */
+
+extern volatile int error_log_cnt;
+
+struct err_log_info {
+	int error_type;
+	unsigned int seq_num;
+};
+
+static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
+{
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
+
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += size;
+		break;
+	}
+	if (offset < 0)
+		return -EINVAL;
+	file->f_pos = offset;
+	return file->f_pos;
+}
+
+
+static ssize_t dev_nvram_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	ssize_t len;
+	char *tmp_buffer;
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
+
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+	if (*ppos >= size)
+		return 0;
+	if (count > size) 
+		count = size;
+
+	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
+	if (!tmp_buffer) {
+		printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
+		return -ENOMEM;
+	}
+
+	len = ppc_md.nvram_read(tmp_buffer, count, ppos);
+	if ((long)len <= 0) {
+		kfree(tmp_buffer);
+		return len;
+	}
+
+	if (copy_to_user(buf, tmp_buffer, len)) {
+		kfree(tmp_buffer);
+		return -EFAULT;
+	}
+
+	kfree(tmp_buffer);
+	return len;
+
+}
+
+static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	ssize_t len;
+	char * tmp_buffer;
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
+	if (*ppos >= size)
+		return 0;
+	if (count > size)
+		count = size;
+
+	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
+	if (!tmp_buffer) {
+		printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
+		return -ENOMEM;
+	}
+	
+	if (copy_from_user(tmp_buffer, buf, count)) {
+		kfree(tmp_buffer);
+		return -EFAULT;
+	}
+
+	len = ppc_md.nvram_write(tmp_buffer, count, ppos);
+	if ((long)len <= 0) {
+		kfree(tmp_buffer);
+		return len;
+	}
+
+	kfree(tmp_buffer);
+	return len;
+}
+
+static int dev_nvram_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	switch(cmd) {
+#ifdef CONFIG_PPC_PMAC
+	case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
+		printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
+	case IOC_NVRAM_GET_OFFSET: {
+		int part, offset;
+
+		if (_machine != PLATFORM_POWERMAC)
+			return -EINVAL;
+		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
+			return -EFAULT;
+		if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+			return -EINVAL;
+		offset = pmac_get_partition(part);
+		if (offset < 0)
+			return offset;
+		if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
+			return -EFAULT;
+		return 0;
+	}
+#endif /* CONFIG_PPC_PMAC */
+	}
+	return -EINVAL;
+}
+
+struct file_operations nvram_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	dev_nvram_llseek,
+	.read =		dev_nvram_read,
+	.write =	dev_nvram_write,
+	.ioctl =	dev_nvram_ioctl,
+};
+
+static struct miscdevice nvram_dev = {
+	NVRAM_MINOR,
+	"nvram",
+	&nvram_fops
+};
+
+
+#ifdef DEBUG_NVRAM
+static void nvram_print_partitions(char * label)
+{
+	struct list_head * p;
+	struct nvram_partition * tmp_part;
+	
+	printk(KERN_WARNING "--------%s---------\n", label);
+	printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
+	list_for_each(p, &nvram_part->partition) {
+		tmp_part = list_entry(p, struct nvram_partition, partition);
+		printk(KERN_WARNING "%d    \t%02x\t%02x\t%d\t%s\n",
+		       tmp_part->index, tmp_part->header.signature,
+		       tmp_part->header.checksum, tmp_part->header.length,
+		       tmp_part->header.name);
+	}
+}
+#endif
+
+
+static int nvram_write_header(struct nvram_partition * part)
+{
+	loff_t tmp_index;
+	int rc;
+	
+	tmp_index = part->index;
+	rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); 
+
+	return rc;
+}
+
+
+static unsigned char nvram_checksum(struct nvram_header *p)
+{
+	unsigned int c_sum, c_sum2;
+	unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
+	c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
+
+	/* The sum may have spilled into the 3rd byte.  Fold it back. */
+	c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
+	/* The sum cannot exceed 2 bytes.  Fold it into a checksum */
+	c_sum2 = (c_sum >> 8) + (c_sum << 8);
+	c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
+	return c_sum;
+}
+
+
+/*
+ * Find an nvram partition, sig can be 0 for any
+ * partition or name can be NULL for any name, else
+ * tries to match both
+ */
+struct nvram_partition *nvram_find_partition(int sig, const char *name)
+{
+	struct nvram_partition * part;
+	struct list_head * p;
+
+	list_for_each(p, &nvram_part->partition) {
+		part = list_entry(p, struct nvram_partition, partition);
+
+		if (sig && part->header.signature != sig)
+			continue;
+		if (name && 0 != strncmp(name, part->header.name, 12))
+			continue;
+		return part; 
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(nvram_find_partition);
+
+
+static int nvram_remove_os_partition(void)
+{
+	struct list_head *i;
+	struct list_head *j;
+	struct nvram_partition * part;
+	struct nvram_partition * cur_part;
+	int rc;
+
+	list_for_each(i, &nvram_part->partition) {
+		part = list_entry(i, struct nvram_partition, partition);
+		if (part->header.signature != NVRAM_SIG_OS)
+			continue;
+		
+		/* Make os partition a free partition */
+		part->header.signature = NVRAM_SIG_FREE;
+		sprintf(part->header.name, "wwwwwwwwwwww");
+		part->header.checksum = nvram_checksum(&part->header);
+
+		/* Merge contiguous free partitions backwards */
+		list_for_each_prev(j, &part->partition) {
+			cur_part = list_entry(j, struct nvram_partition, partition);
+			if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
+				break;
+			}
+			
+			part->header.length += cur_part->header.length;
+			part->header.checksum = nvram_checksum(&part->header);
+			part->index = cur_part->index;
+
+			list_del(&cur_part->partition);
+			kfree(cur_part);
+			j = &part->partition; /* fixup our loop */
+		}
+		
+		/* Merge contiguous free partitions forwards */
+		list_for_each(j, &part->partition) {
+			cur_part = list_entry(j, struct nvram_partition, partition);
+			if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
+				break;
+			}
+
+			part->header.length += cur_part->header.length;
+			part->header.checksum = nvram_checksum(&part->header);
+
+			list_del(&cur_part->partition);
+			kfree(cur_part);
+			j = &part->partition; /* fixup our loop */
+		}
+		
+		rc = nvram_write_header(part);
+		if (rc <= 0) {
+			printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc);
+			return rc;
+		}
+
+	}
+	
+	return 0;
+}
+
+/* nvram_create_os_partition
+ *
+ * Create a OS linux partition to buffer error logs.
+ * Will create a partition starting at the first free
+ * space found if space has enough room.
+ */
+static int nvram_create_os_partition(void)
+{
+	struct nvram_partition *part;
+	struct nvram_partition *new_part;
+	struct nvram_partition *free_part = NULL;
+	int seq_init[2] = { 0, 0 };
+	loff_t tmp_index;
+	long size = 0;
+	int rc;
+	
+	/* Find a free partition that will give us the maximum needed size 
+	   If can't find one that will give us the minimum size needed */
+	list_for_each_entry(part, &nvram_part->partition, partition) {
+		if (part->header.signature != NVRAM_SIG_FREE)
+			continue;
+
+		if (part->header.length >= NVRAM_MAX_REQ) {
+			size = NVRAM_MAX_REQ;
+			free_part = part;
+			break;
+		}
+		if (!size && part->header.length >= NVRAM_MIN_REQ) {
+			size = NVRAM_MIN_REQ;
+			free_part = part;
+		}
+	}
+	if (!size)
+		return -ENOSPC;
+	
+	/* Create our OS partition */
+	new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
+	if (!new_part) {
+		printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n");
+		return -ENOMEM;
+	}
+
+	new_part->index = free_part->index;
+	new_part->header.signature = NVRAM_SIG_OS;
+	new_part->header.length = size;
+	strcpy(new_part->header.name, "ppc64,linux");
+	new_part->header.checksum = nvram_checksum(&new_part->header);
+
+	rc = nvram_write_header(new_part);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_create_os_partition: nvram_write_header \
+				failed (%d)\n", rc);
+		return rc;
+	}
+
+	/* make sure and initialize to zero the sequence number and the error
+	   type logged */
+	tmp_index = new_part->index + NVRAM_HEADER_LEN;
+	rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_create_os_partition: nvram_write "
+				"failed (%d)\n", rc);
+		return rc;
+	}
+	
+	nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN;
+	nvram_error_log_size = ((part->header.length - 1) *
+				NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
+	
+	list_add_tail(&new_part->partition, &free_part->partition);
+
+	if (free_part->header.length <= size) {
+		list_del(&free_part->partition);
+		kfree(free_part);
+		return 0;
+	} 
+
+	/* Adjust the partition we stole the space from */
+	free_part->index += size * NVRAM_BLOCK_LEN;
+	free_part->header.length -= size;
+	free_part->header.checksum = nvram_checksum(&free_part->header);
+	
+	rc = nvram_write_header(free_part);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_create_os_partition: nvram_write_header "
+		       "failed (%d)\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+
+/* nvram_setup_partition
+ *
+ * This will setup the partition we need for buffering the
+ * error logs and cleanup partitions if needed.
+ *
+ * The general strategy is the following:
+ * 1.) If there is ppc64,linux partition large enough then use it.
+ * 2.) If there is not a ppc64,linux partition large enough, search
+ * for a free partition that is large enough.
+ * 3.) If there is not a free partition large enough remove 
+ * _all_ OS partitions and consolidate the space.
+ * 4.) Will first try getting a chunk that will satisfy the maximum
+ * error log size (NVRAM_MAX_REQ).
+ * 5.) If the max chunk cannot be allocated then try finding a chunk
+ * that will satisfy the minum needed (NVRAM_MIN_REQ).
+ */
+static int nvram_setup_partition(void)
+{
+	struct list_head * p;
+	struct nvram_partition * part;
+	int rc;
+
+	/* For now, we don't do any of this on pmac, until I
+	 * have figured out if it's worth killing some unused stuffs
+	 * in our nvram, as Apple defined partitions use pretty much
+	 * all of the space
+	 */
+	if (_machine == PLATFORM_POWERMAC)
+		return -ENOSPC;
+
+	/* see if we have an OS partition that meets our needs.
+	   will try getting the max we need.  If not we'll delete
+	   partitions and try again. */
+	list_for_each(p, &nvram_part->partition) {
+		part = list_entry(p, struct nvram_partition, partition);
+		if (part->header.signature != NVRAM_SIG_OS)
+			continue;
+
+		if (strcmp(part->header.name, "ppc64,linux"))
+			continue;
+
+		if (part->header.length >= NVRAM_MIN_REQ) {
+			/* found our partition */
+			nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
+			nvram_error_log_size = ((part->header.length - 1) *
+						NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
+			return 0;
+		}
+	}
+	
+	/* try creating a partition with the free space we have */
+	rc = nvram_create_os_partition();
+	if (!rc) {
+		return 0;
+	}
+		
+	/* need to free up some space */
+	rc = nvram_remove_os_partition();
+	if (rc) {
+		return rc;
+	}
+	
+	/* create a partition in this new space */
+	rc = nvram_create_os_partition();
+	if (rc) {
+		printk(KERN_ERR "nvram_create_os_partition: Could not find a "
+		       "NVRAM partition large enough\n");
+		return rc;
+	}
+	
+	return 0;
+}
+
+
+static int nvram_scan_partitions(void)
+{
+	loff_t cur_index = 0;
+	struct nvram_header phead;
+	struct nvram_partition * tmp_part;
+	unsigned char c_sum;
+	char * header;
+	int total_size;
+	int err;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	total_size = ppc_md.nvram_size();
+	
+	header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
+	if (!header) {
+		printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
+		return -ENOMEM;
+	}
+
+	while (cur_index < total_size) {
+
+		err = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
+		if (err != NVRAM_HEADER_LEN) {
+			printk(KERN_ERR "nvram_scan_partitions: Error parsing "
+			       "nvram partitions\n");
+			goto out;
+		}
+
+		cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
+
+		memcpy(&phead, header, NVRAM_HEADER_LEN);
+
+		err = 0;
+		c_sum = nvram_checksum(&phead);
+		if (c_sum != phead.checksum) {
+			printk(KERN_WARNING "WARNING: nvram partition checksum"
+			       " was %02x, should be %02x!\n",
+			       phead.checksum, c_sum);
+			printk(KERN_WARNING "Terminating nvram partition scan\n");
+			goto out;
+		}
+		if (!phead.length) {
+			printk(KERN_WARNING "WARNING: nvram corruption "
+			       "detected: 0-length partition\n");
+			goto out;
+		}
+		tmp_part = (struct nvram_partition *)
+			kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+		err = -ENOMEM;
+		if (!tmp_part) {
+			printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
+			goto out;
+		}
+		
+		memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
+		tmp_part->index = cur_index;
+		list_add_tail(&tmp_part->partition, &nvram_part->partition);
+		
+		cur_index += phead.length * NVRAM_BLOCK_LEN;
+	}
+	err = 0;
+
+ out:
+	kfree(header);
+	return err;
+}
+
+static int __init nvram_init(void)
+{
+	int error;
+	int rc;
+	
+	if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
+		return  -ENODEV;
+
+  	rc = misc_register(&nvram_dev);
+	if (rc != 0) {
+		printk(KERN_ERR "nvram_init: failed to register device\n");
+		return rc;
+	}
+  	
+  	/* initialize our anchor for the nvram partition list */
+  	nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+  	if (!nvram_part) {
+  		printk(KERN_ERR "nvram_init: Failed kmalloc\n");
+  		return -ENOMEM;
+  	}
+  	INIT_LIST_HEAD(&nvram_part->partition);
+  
+  	/* Get all the NVRAM partitions */
+  	error = nvram_scan_partitions();
+  	if (error) {
+  		printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
+  		return error;
+  	}
+  		
+  	if(nvram_setup_partition()) 
+  		printk(KERN_WARNING "nvram_init: Could not find nvram partition"
+  		       " for nvram buffered error logging.\n");
+  
+#ifdef DEBUG_NVRAM
+	nvram_print_partitions("NVRAM Partitions");
+#endif
+
+  	return rc;
+}
+
+void __exit nvram_cleanup(void)
+{
+        misc_deregister( &nvram_dev );
+}
+
+
+#ifdef CONFIG_PPC_PSERIES
+
+/* nvram_write_error_log
+ *
+ * We need to buffer the error logs into nvram to ensure that we have
+ * the failure information to decode.  If we have a severe error there
+ * is no way to guarantee that the OS or the machine is in a state to
+ * get back to user land and write the error to disk.  For example if
+ * the SCSI device driver causes a Machine Check by writing to a bad
+ * IO address, there is no way of guaranteeing that the device driver
+ * is in any state that is would also be able to write the error data
+ * captured to disk, thus we buffer it in NVRAM for analysis on the
+ * next boot.
+ *
+ * In NVRAM the partition containing the error log buffer will looks like:
+ * Header (in bytes):
+ * +-----------+----------+--------+------------+------------------+
+ * | signature | checksum | length | name       | data             |
+ * |0          |1         |2      3|4         15|16        length-1|
+ * +-----------+----------+--------+------------+------------------+
+ *
+ * The 'data' section would look like (in bytes):
+ * +--------------+------------+-----------------------------------+
+ * | event_logged | sequence # | error log                         |
+ * |0            3|4          7|8            nvram_error_log_size-1|
+ * +--------------+------------+-----------------------------------+
+ *
+ * event_logged: 0 if event has not been logged to syslog, 1 if it has
+ * sequence #: The unique sequence # for each event. (until it wraps)
+ * error log: The error log from event_scan
+ */
+int nvram_write_error_log(char * buff, int length, unsigned int err_type)
+{
+	int rc;
+	loff_t tmp_index;
+	struct err_log_info info;
+	
+	if (no_logging) {
+		return -EPERM;
+	}
+
+	if (nvram_error_log_index == -1) {
+		return -ESPIPE;
+	}
+
+	if (length > nvram_error_log_size) {
+		length = nvram_error_log_size;
+	}
+
+	info.error_type = err_type;
+	info.seq_num = error_log_cnt;
+
+	tmp_index = nvram_error_log_index;
+
+	rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
+		return rc;
+	}
+
+	rc = ppc_md.nvram_write(buff, length, &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
+		return rc;
+	}
+	
+	return 0;
+}
+
+/* nvram_read_error_log
+ *
+ * Reads nvram for error log for at most 'length'
+ */
+int nvram_read_error_log(char * buff, int length, unsigned int * err_type)
+{
+	int rc;
+	loff_t tmp_index;
+	struct err_log_info info;
+	
+	if (nvram_error_log_index == -1)
+		return -1;
+
+	if (length > nvram_error_log_size)
+		length = nvram_error_log_size;
+
+	tmp_index = nvram_error_log_index;
+
+	rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
+		return rc;
+	}
+
+	rc = ppc_md.nvram_read(buff, length, &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
+		return rc;
+	}
+
+	error_log_cnt = info.seq_num;
+	*err_type = info.error_type;
+
+	return 0;
+}
+
+/* This doesn't actually zero anything, but it sets the event_logged
+ * word to tell that this event is safely in syslog.
+ */
+int nvram_clear_error_log(void)
+{
+	loff_t tmp_index;
+	int clear_word = ERR_FLAG_ALREADY_LOGGED;
+	int rc;
+
+	tmp_index = nvram_error_log_index;
+	
+	rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
+	if (rc <= 0) {
+		printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_PPC_PSERIES */
+
+module_init(nvram_init);
+module_exit(nvram_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
deleted file mode 100644
index a55a82d145d..00000000000
--- a/arch/ppc64/Makefile
+++ /dev/null
@@ -1,142 +0,0 @@
-# This file is included by the global makefile so that you can add your own
-# architecture-specific flags and dependencies. Remember to do have actions
-# for "archclean" and "archdep" for cleaning up and making dependencies for
-# this architecture
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License.  See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1994 by Linus Torvalds
-# Changes for PPC by Gary Thomas
-# Rewritten by Cort Dougan and Paul Mackerras
-# Adjusted for PPC64 by Tom Gall
-#
-
-KERNELLOAD	:= 0xc000000000000000
-
-# Set default 32 bits cross compilers for vdso and boot wrapper
-CROSS32_COMPILE ?=
-
-CROSS32CC		:= $(CROSS32_COMPILE)gcc
-CROSS32AS		:= $(CROSS32_COMPILE)as
-CROSS32LD		:= $(CROSS32_COMPILE)ld
-CROSS32OBJCOPY		:= $(CROSS32_COMPILE)objcopy
-
-# If we have a biarch compiler, use it for 32 bits cross compile if
-# CROSS32_COMPILE wasn't explicitely defined, and add proper explicit
-# target type to target compilers
-
-HAS_BIARCH      := $(call cc-option-yn, -m64)
-ifeq ($(HAS_BIARCH),y)
-ifeq ($(CROSS32_COMPILE),)
-CROSS32CC	:= $(CC) -m32
-CROSS32AS	:= $(AS) -a32
-CROSS32LD	:= $(LD) -m elf32ppc
-CROSS32OBJCOPY	:= $(OBJCOPY)
-endif
-override AS	+= -a64
-override LD	+= -m elf64ppc
-override CC	+= -m64
-endif
-
-export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
-
-new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi)
-
-ifeq ($(new_nm),y)
-NM		:= $(NM) --synthetic
-
-endif
-
-CHECKFLAGS	+= -m64 -D__powerpc__ -D__powerpc64__
-
-LDFLAGS		:= -m elf64ppc
-LDFLAGS_vmlinux	:= -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD)
-CFLAGS		+= -msoft-float -pipe -mminimal-toc -mtraceback=none \
-		   -mcall-aixdesc
-# Temporary hack until we have migrated to asm-powerpc
-CPPFLAGS	+= -Iarch/$(ARCH)/include
-
-GCC_VERSION     := $(call cc-version)
-GCC_BROKEN_VEC	:= $(shell if [ $(GCC_VERSION) -lt 0400 ] ; then echo "y"; fi ;)
-
-ifeq ($(CONFIG_POWER4_ONLY),y)
-ifeq ($(CONFIG_ALTIVEC),y)
-ifeq ($(GCC_BROKEN_VEC),y)
-	CFLAGS += $(call cc-option,-mcpu=970)
-else
-	CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-	CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
-	CFLAGS += $(call cc-option,-mtune=power4)
-endif
-
-# No AltiVec instruction when building kernel
-CFLAGS	+= $(call cc-option, -mno-altivec)
-
-# Enable unit-at-a-time mode when possible. It shrinks the
-# kernel considerably.
-CFLAGS += $(call cc-option,-funit-at-a-time)
-
-head-y := arch/ppc64/kernel/head.o
-head-y += arch/powerpc/kernel/fpu.o
-head-y += arch/powerpc/kernel/entry_64.o
-
-core-y				+= arch/ppc64/kernel/ arch/powerpc/kernel/
-core-y				+= arch/powerpc/mm/
-core-y				+= arch/powerpc/sysdev/
-core-y				+= arch/powerpc/platforms/
-core-y				+= arch/powerpc/lib/
-core-$(CONFIG_XMON)		+= arch/powerpc/xmon/
-drivers-$(CONFIG_OPROFILE)	+= arch/powerpc/oprofile/
-
-boot := arch/ppc64/boot
-
-boottargets-$(CONFIG_PPC_PSERIES) += zImage zImage.initrd
-boottargets-$(CONFIG_PPC_PMAC) += zImage.vmode zImage.initrd.vmode
-boottargets-$(CONFIG_PPC_MAPLE) += zImage zImage.initrd
-boottargets-$(CONFIG_PPC_ISERIES) += vmlinux.sminitrd vmlinux.initrd vmlinux.sm
-boottargets-$(CONFIG_PPC_BPA) += zImage zImage.initrd
-$(boottargets-y): vmlinux
-	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
-
-bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage
-bootimage-$(CONFIG_PPC_PMAC) := vmlinux
-bootimage-$(CONFIG_PPC_MAPLE) := $(boot)/zImage
-bootimage-$(CONFIG_PPC_BPA) := $(boot)/zImage
-bootimage-$(CONFIG_PPC_ISERIES) := vmlinux
-BOOTIMAGE := $(bootimage-y)
-install: vmlinux
-	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
-
-defaultimage-$(CONFIG_PPC_PSERIES) := zImage
-defaultimage-$(CONFIG_PPC_PMAC) := zImage.vmode
-defaultimage-$(CONFIG_PPC_MAPLE) := zImage
-defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux
-KBUILD_IMAGE := $(defaultimage-y)
-all: $(KBUILD_IMAGE)
-
-archclean:
-	$(Q)$(MAKE) $(clean)=$(boot)
-	# Temporary hack until we have migrated to asm-powerpc
-	$(Q)rm -rf arch/$(ARCH)/include
-
-
-# Temporary hack until we have migrated to asm-powerpc
-include/asm: arch/$(ARCH)/include/asm
-arch/$(ARCH)/include/asm:
-	$(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi
-	$(Q)ln -fsn $(srctree)/include/asm-powerpc arch/$(ARCH)/include/asm
-
-define archhelp
-  echo  '  zImage.vmode        - Compressed kernel image (arch/$(ARCH)/boot/zImage.vmode)'
-  echo  '  zImage.initrd.vmode - Compressed kernel image with initrd attached,'
-  echo  '                        sourced from arch/$(ARCH)/boot/ramdisk.image.gz'
-  echo  '                        (arch/$(ARCH)/boot/zImage.initrd.vmode)'
-  echo  '  zImage              - zImage for pSeries machines'
-  echo  '  zImage.initrd       - zImage with initrd for pSeries machines'
-endef
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
deleted file mode 100644
index 5f0abdb66e0..00000000000
--- a/arch/ppc64/kernel/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the linux ppc64 kernel.
-#
-
-obj-y               +=	idle.o
-
-obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
deleted file mode 100644
index b879d3057ef..00000000000
--- a/arch/ppc64/kernel/idle.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Idle daemon for PowerPC.  Idle daemon will handle any action
- * that needs to be taken when the system becomes idle.
- *
- * Originally Written by Cort Dougan (cort@cs.nmt.edu)
- *
- * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com>
- *
- * Additional shared processor, SMT, and firmware support
- *    Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com>
- *
- * 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 <linux/config.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/cpu.h>
-#include <linux/sysctl.h>
-
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/cputable.h>
-#include <asm/time.h>
-#include <asm/machdep.h>
-#include <asm/smp.h>
-
-extern void power4_idle(void);
-
-void default_idle(void)
-{
-	unsigned int cpu = smp_processor_id();
-	set_thread_flag(TIF_POLLING_NRFLAG);
-
-	while (1) {
-		if (!need_resched()) {
-			while (!need_resched() && !cpu_is_offline(cpu)) {
-				ppc64_runlatch_off();
-
-				/*
-				 * Go into low thread priority and possibly
-				 * low power mode.
-				 */
-				HMT_low();
-				HMT_very_low();
-			}
-
-			HMT_medium();
-		}
-
-		ppc64_runlatch_on();
-		preempt_enable_no_resched();
-		schedule();
-		preempt_disable();
-		if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
-}
-
-void native_idle(void)
-{
-	while (1) {
-		ppc64_runlatch_off();
-
-		if (!need_resched())
-			power4_idle();
-
-		if (need_resched()) {
-			ppc64_runlatch_on();
-			preempt_enable_no_resched();
-			schedule();
-			preempt_disable();
-		}
-
-		if (cpu_is_offline(smp_processor_id()) &&
-		    system_state == SYSTEM_RUNNING)
-			cpu_die();
-	}
-}
-
-void cpu_idle(void)
-{
-	BUG_ON(NULL == ppc_md.idle_loop);
-	ppc_md.idle_loop();
-}
-
-int powersave_nap;
-
-#ifdef CONFIG_SYSCTL
-/*
- * Register the sysctl to set/clear powersave_nap.
- */
-static ctl_table powersave_nap_ctl_table[]={
-	{
-		.ctl_name	= KERN_PPC_POWERSAVE_NAP,
-		.procname	= "powersave-nap",
-		.data		= &powersave_nap,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
-	{ 0, },
-};
-static ctl_table powersave_nap_sysctl_root[] = {
-	{ 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, },
- 	{ 0,},
-};
-
-static int __init
-register_powersave_nap_sysctl(void)
-{
-	register_sysctl_table(powersave_nap_sysctl_root, 0);
-
-	return 0;
-}
-__initcall(register_powersave_nap_sysctl);
-#endif
diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
deleted file mode 100644
index c0fcd29918c..00000000000
--- a/arch/ppc64/kernel/nvram.c
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- *  c 2001 PPC 64 Team, IBM Corp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- * /dev/nvram driver for PPC64
- *
- * This perhaps should live in drivers/char
- *
- * TODO: Split the /dev/nvram part (that one can use
- *       drivers/char/generic_nvram.c) from the arch & partition
- *       parsing code.
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/fcntl.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-#include <asm/nvram.h>
-#include <asm/rtas.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-
-#undef DEBUG_NVRAM
-
-static int nvram_scan_partitions(void);
-static int nvram_setup_partition(void);
-static int nvram_create_os_partition(void);
-static int nvram_remove_os_partition(void);
-
-static struct nvram_partition * nvram_part;
-static long nvram_error_log_index = -1;
-static long nvram_error_log_size = 0;
-
-int no_logging = 1; 	/* Until we initialize everything,
-			 * make sure we don't try logging
-			 * anything */
-
-extern volatile int error_log_cnt;
-
-struct err_log_info {
-	int error_type;
-	unsigned int seq_num;
-};
-
-static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
-{
-	int size;
-
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
-	size = ppc_md.nvram_size();
-
-	switch (origin) {
-	case 1:
-		offset += file->f_pos;
-		break;
-	case 2:
-		offset += size;
-		break;
-	}
-	if (offset < 0)
-		return -EINVAL;
-	file->f_pos = offset;
-	return file->f_pos;
-}
-
-
-static ssize_t dev_nvram_read(struct file *file, char __user *buf,
-			  size_t count, loff_t *ppos)
-{
-	ssize_t len;
-	char *tmp_buffer;
-	int size;
-
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
-	size = ppc_md.nvram_size();
-
-	if (!access_ok(VERIFY_WRITE, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size) 
-		count = size;
-
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_read_nvram: kmalloc failed\n");
-		return -ENOMEM;
-	}
-
-	len = ppc_md.nvram_read(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
-
-	if (copy_to_user(buf, tmp_buffer, len)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
-
-	kfree(tmp_buffer);
-	return len;
-
-}
-
-static ssize_t dev_nvram_write(struct file *file, const char __user *buf,
-			   size_t count, loff_t *ppos)
-{
-	ssize_t len;
-	char * tmp_buffer;
-	int size;
-
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
-	size = ppc_md.nvram_size();
-
-	if (!access_ok(VERIFY_READ, buf, count))
-		return -EFAULT;
-	if (*ppos >= size)
-		return 0;
-	if (count > size)
-		count = size;
-
-	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
-	if (!tmp_buffer) {
-		printk(KERN_ERR "dev_nvram_write: kmalloc failed\n");
-		return -ENOMEM;
-	}
-	
-	if (copy_from_user(tmp_buffer, buf, count)) {
-		kfree(tmp_buffer);
-		return -EFAULT;
-	}
-
-	len = ppc_md.nvram_write(tmp_buffer, count, ppos);
-	if ((long)len <= 0) {
-		kfree(tmp_buffer);
-		return len;
-	}
-
-	kfree(tmp_buffer);
-	return len;
-}
-
-static int dev_nvram_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg)
-{
-	switch(cmd) {
-#ifdef CONFIG_PPC_PMAC
-	case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
-		printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
-	case IOC_NVRAM_GET_OFFSET: {
-		int part, offset;
-
-		if (_machine != PLATFORM_POWERMAC)
-			return -EINVAL;
-		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
-			return -EFAULT;
-		if (part < pmac_nvram_OF || part > pmac_nvram_NR)
-			return -EINVAL;
-		offset = pmac_get_partition(part);
-		if (offset < 0)
-			return offset;
-		if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
-			return -EFAULT;
-		return 0;
-	}
-#endif /* CONFIG_PPC_PMAC */
-	}
-	return -EINVAL;
-}
-
-struct file_operations nvram_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	dev_nvram_llseek,
-	.read =		dev_nvram_read,
-	.write =	dev_nvram_write,
-	.ioctl =	dev_nvram_ioctl,
-};
-
-static struct miscdevice nvram_dev = {
-	NVRAM_MINOR,
-	"nvram",
-	&nvram_fops
-};
-
-
-#ifdef DEBUG_NVRAM
-static void nvram_print_partitions(char * label)
-{
-	struct list_head * p;
-	struct nvram_partition * tmp_part;
-	
-	printk(KERN_WARNING "--------%s---------\n", label);
-	printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
-	list_for_each(p, &nvram_part->partition) {
-		tmp_part = list_entry(p, struct nvram_partition, partition);
-		printk(KERN_WARNING "%d    \t%02x\t%02x\t%d\t%s\n",
-		       tmp_part->index, tmp_part->header.signature,
-		       tmp_part->header.checksum, tmp_part->header.length,
-		       tmp_part->header.name);
-	}
-}
-#endif
-
-
-static int nvram_write_header(struct nvram_partition * part)
-{
-	loff_t tmp_index;
-	int rc;
-	
-	tmp_index = part->index;
-	rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); 
-
-	return rc;
-}
-
-
-static unsigned char nvram_checksum(struct nvram_header *p)
-{
-	unsigned int c_sum, c_sum2;
-	unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
-	c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
-
-	/* The sum may have spilled into the 3rd byte.  Fold it back. */
-	c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
-	/* The sum cannot exceed 2 bytes.  Fold it into a checksum */
-	c_sum2 = (c_sum >> 8) + (c_sum << 8);
-	c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
-	return c_sum;
-}
-
-
-/*
- * Find an nvram partition, sig can be 0 for any
- * partition or name can be NULL for any name, else
- * tries to match both
- */
-struct nvram_partition *nvram_find_partition(int sig, const char *name)
-{
-	struct nvram_partition * part;
-	struct list_head * p;
-
-	list_for_each(p, &nvram_part->partition) {
-		part = list_entry(p, struct nvram_partition, partition);
-
-		if (sig && part->header.signature != sig)
-			continue;
-		if (name && 0 != strncmp(name, part->header.name, 12))
-			continue;
-		return part; 
-	}
-	return NULL;
-}
-EXPORT_SYMBOL(nvram_find_partition);
-
-
-static int nvram_remove_os_partition(void)
-{
-	struct list_head *i;
-	struct list_head *j;
-	struct nvram_partition * part;
-	struct nvram_partition * cur_part;
-	int rc;
-
-	list_for_each(i, &nvram_part->partition) {
-		part = list_entry(i, struct nvram_partition, partition);
-		if (part->header.signature != NVRAM_SIG_OS)
-			continue;
-		
-		/* Make os partition a free partition */
-		part->header.signature = NVRAM_SIG_FREE;
-		sprintf(part->header.name, "wwwwwwwwwwww");
-		part->header.checksum = nvram_checksum(&part->header);
-
-		/* Merge contiguous free partitions backwards */
-		list_for_each_prev(j, &part->partition) {
-			cur_part = list_entry(j, struct nvram_partition, partition);
-			if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
-				break;
-			}
-			
-			part->header.length += cur_part->header.length;
-			part->header.checksum = nvram_checksum(&part->header);
-			part->index = cur_part->index;
-
-			list_del(&cur_part->partition);
-			kfree(cur_part);
-			j = &part->partition; /* fixup our loop */
-		}
-		
-		/* Merge contiguous free partitions forwards */
-		list_for_each(j, &part->partition) {
-			cur_part = list_entry(j, struct nvram_partition, partition);
-			if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
-				break;
-			}
-
-			part->header.length += cur_part->header.length;
-			part->header.checksum = nvram_checksum(&part->header);
-
-			list_del(&cur_part->partition);
-			kfree(cur_part);
-			j = &part->partition; /* fixup our loop */
-		}
-		
-		rc = nvram_write_header(part);
-		if (rc <= 0) {
-			printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc);
-			return rc;
-		}
-
-	}
-	
-	return 0;
-}
-
-/* nvram_create_os_partition
- *
- * Create a OS linux partition to buffer error logs.
- * Will create a partition starting at the first free
- * space found if space has enough room.
- */
-static int nvram_create_os_partition(void)
-{
-	struct nvram_partition *part;
-	struct nvram_partition *new_part;
-	struct nvram_partition *free_part = NULL;
-	int seq_init[2] = { 0, 0 };
-	loff_t tmp_index;
-	long size = 0;
-	int rc;
-	
-	/* Find a free partition that will give us the maximum needed size 
-	   If can't find one that will give us the minimum size needed */
-	list_for_each_entry(part, &nvram_part->partition, partition) {
-		if (part->header.signature != NVRAM_SIG_FREE)
-			continue;
-
-		if (part->header.length >= NVRAM_MAX_REQ) {
-			size = NVRAM_MAX_REQ;
-			free_part = part;
-			break;
-		}
-		if (!size && part->header.length >= NVRAM_MIN_REQ) {
-			size = NVRAM_MIN_REQ;
-			free_part = part;
-		}
-	}
-	if (!size)
-		return -ENOSPC;
-	
-	/* Create our OS partition */
-	new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
-	if (!new_part) {
-		printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n");
-		return -ENOMEM;
-	}
-
-	new_part->index = free_part->index;
-	new_part->header.signature = NVRAM_SIG_OS;
-	new_part->header.length = size;
-	strcpy(new_part->header.name, "ppc64,linux");
-	new_part->header.checksum = nvram_checksum(&new_part->header);
-
-	rc = nvram_write_header(new_part);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_create_os_partition: nvram_write_header \
-				failed (%d)\n", rc);
-		return rc;
-	}
-
-	/* make sure and initialize to zero the sequence number and the error
-	   type logged */
-	tmp_index = new_part->index + NVRAM_HEADER_LEN;
-	rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_create_os_partition: nvram_write "
-				"failed (%d)\n", rc);
-		return rc;
-	}
-	
-	nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN;
-	nvram_error_log_size = ((part->header.length - 1) *
-				NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
-	
-	list_add_tail(&new_part->partition, &free_part->partition);
-
-	if (free_part->header.length <= size) {
-		list_del(&free_part->partition);
-		kfree(free_part);
-		return 0;
-	} 
-
-	/* Adjust the partition we stole the space from */
-	free_part->index += size * NVRAM_BLOCK_LEN;
-	free_part->header.length -= size;
-	free_part->header.checksum = nvram_checksum(&free_part->header);
-	
-	rc = nvram_write_header(free_part);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_create_os_partition: nvram_write_header "
-		       "failed (%d)\n", rc);
-		return rc;
-	}
-
-	return 0;
-}
-
-
-/* nvram_setup_partition
- *
- * This will setup the partition we need for buffering the
- * error logs and cleanup partitions if needed.
- *
- * The general strategy is the following:
- * 1.) If there is ppc64,linux partition large enough then use it.
- * 2.) If there is not a ppc64,linux partition large enough, search
- * for a free partition that is large enough.
- * 3.) If there is not a free partition large enough remove 
- * _all_ OS partitions and consolidate the space.
- * 4.) Will first try getting a chunk that will satisfy the maximum
- * error log size (NVRAM_MAX_REQ).
- * 5.) If the max chunk cannot be allocated then try finding a chunk
- * that will satisfy the minum needed (NVRAM_MIN_REQ).
- */
-static int nvram_setup_partition(void)
-{
-	struct list_head * p;
-	struct nvram_partition * part;
-	int rc;
-
-	/* For now, we don't do any of this on pmac, until I
-	 * have figured out if it's worth killing some unused stuffs
-	 * in our nvram, as Apple defined partitions use pretty much
-	 * all of the space
-	 */
-	if (_machine == PLATFORM_POWERMAC)
-		return -ENOSPC;
-
-	/* see if we have an OS partition that meets our needs.
-	   will try getting the max we need.  If not we'll delete
-	   partitions and try again. */
-	list_for_each(p, &nvram_part->partition) {
-		part = list_entry(p, struct nvram_partition, partition);
-		if (part->header.signature != NVRAM_SIG_OS)
-			continue;
-
-		if (strcmp(part->header.name, "ppc64,linux"))
-			continue;
-
-		if (part->header.length >= NVRAM_MIN_REQ) {
-			/* found our partition */
-			nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
-			nvram_error_log_size = ((part->header.length - 1) *
-						NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
-			return 0;
-		}
-	}
-	
-	/* try creating a partition with the free space we have */
-	rc = nvram_create_os_partition();
-	if (!rc) {
-		return 0;
-	}
-		
-	/* need to free up some space */
-	rc = nvram_remove_os_partition();
-	if (rc) {
-		return rc;
-	}
-	
-	/* create a partition in this new space */
-	rc = nvram_create_os_partition();
-	if (rc) {
-		printk(KERN_ERR "nvram_create_os_partition: Could not find a "
-		       "NVRAM partition large enough\n");
-		return rc;
-	}
-	
-	return 0;
-}
-
-
-static int nvram_scan_partitions(void)
-{
-	loff_t cur_index = 0;
-	struct nvram_header phead;
-	struct nvram_partition * tmp_part;
-	unsigned char c_sum;
-	char * header;
-	int total_size;
-	int err;
-
-	if (ppc_md.nvram_size == NULL)
-		return -ENODEV;
-	total_size = ppc_md.nvram_size();
-	
-	header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
-	if (!header) {
-		printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
-		return -ENOMEM;
-	}
-
-	while (cur_index < total_size) {
-
-		err = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
-		if (err != NVRAM_HEADER_LEN) {
-			printk(KERN_ERR "nvram_scan_partitions: Error parsing "
-			       "nvram partitions\n");
-			goto out;
-		}
-
-		cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
-
-		memcpy(&phead, header, NVRAM_HEADER_LEN);
-
-		err = 0;
-		c_sum = nvram_checksum(&phead);
-		if (c_sum != phead.checksum) {
-			printk(KERN_WARNING "WARNING: nvram partition checksum"
-			       " was %02x, should be %02x!\n",
-			       phead.checksum, c_sum);
-			printk(KERN_WARNING "Terminating nvram partition scan\n");
-			goto out;
-		}
-		if (!phead.length) {
-			printk(KERN_WARNING "WARNING: nvram corruption "
-			       "detected: 0-length partition\n");
-			goto out;
-		}
-		tmp_part = (struct nvram_partition *)
-			kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
-		err = -ENOMEM;
-		if (!tmp_part) {
-			printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
-			goto out;
-		}
-		
-		memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
-		tmp_part->index = cur_index;
-		list_add_tail(&tmp_part->partition, &nvram_part->partition);
-		
-		cur_index += phead.length * NVRAM_BLOCK_LEN;
-	}
-	err = 0;
-
- out:
-	kfree(header);
-	return err;
-}
-
-static int __init nvram_init(void)
-{
-	int error;
-	int rc;
-	
-	if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
-		return  -ENODEV;
-
-  	rc = misc_register(&nvram_dev);
-	if (rc != 0) {
-		printk(KERN_ERR "nvram_init: failed to register device\n");
-		return rc;
-	}
-  	
-  	/* initialize our anchor for the nvram partition list */
-  	nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
-  	if (!nvram_part) {
-  		printk(KERN_ERR "nvram_init: Failed kmalloc\n");
-  		return -ENOMEM;
-  	}
-  	INIT_LIST_HEAD(&nvram_part->partition);
-  
-  	/* Get all the NVRAM partitions */
-  	error = nvram_scan_partitions();
-  	if (error) {
-  		printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
-  		return error;
-  	}
-  		
-  	if(nvram_setup_partition()) 
-  		printk(KERN_WARNING "nvram_init: Could not find nvram partition"
-  		       " for nvram buffered error logging.\n");
-  
-#ifdef DEBUG_NVRAM
-	nvram_print_partitions("NVRAM Partitions");
-#endif
-
-  	return rc;
-}
-
-void __exit nvram_cleanup(void)
-{
-        misc_deregister( &nvram_dev );
-}
-
-
-#ifdef CONFIG_PPC_PSERIES
-
-/* nvram_write_error_log
- *
- * We need to buffer the error logs into nvram to ensure that we have
- * the failure information to decode.  If we have a severe error there
- * is no way to guarantee that the OS or the machine is in a state to
- * get back to user land and write the error to disk.  For example if
- * the SCSI device driver causes a Machine Check by writing to a bad
- * IO address, there is no way of guaranteeing that the device driver
- * is in any state that is would also be able to write the error data
- * captured to disk, thus we buffer it in NVRAM for analysis on the
- * next boot.
- *
- * In NVRAM the partition containing the error log buffer will looks like:
- * Header (in bytes):
- * +-----------+----------+--------+------------+------------------+
- * | signature | checksum | length | name       | data             |
- * |0          |1         |2      3|4         15|16        length-1|
- * +-----------+----------+--------+------------+------------------+
- *
- * The 'data' section would look like (in bytes):
- * +--------------+------------+-----------------------------------+
- * | event_logged | sequence # | error log                         |
- * |0            3|4          7|8            nvram_error_log_size-1|
- * +--------------+------------+-----------------------------------+
- *
- * event_logged: 0 if event has not been logged to syslog, 1 if it has
- * sequence #: The unique sequence # for each event. (until it wraps)
- * error log: The error log from event_scan
- */
-int nvram_write_error_log(char * buff, int length, unsigned int err_type)
-{
-	int rc;
-	loff_t tmp_index;
-	struct err_log_info info;
-	
-	if (no_logging) {
-		return -EPERM;
-	}
-
-	if (nvram_error_log_index == -1) {
-		return -ESPIPE;
-	}
-
-	if (length > nvram_error_log_size) {
-		length = nvram_error_log_size;
-	}
-
-	info.error_type = err_type;
-	info.seq_num = error_log_cnt;
-
-	tmp_index = nvram_error_log_index;
-
-	rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
-		return rc;
-	}
-
-	rc = ppc_md.nvram_write(buff, length, &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
-		return rc;
-	}
-	
-	return 0;
-}
-
-/* nvram_read_error_log
- *
- * Reads nvram for error log for at most 'length'
- */
-int nvram_read_error_log(char * buff, int length, unsigned int * err_type)
-{
-	int rc;
-	loff_t tmp_index;
-	struct err_log_info info;
-	
-	if (nvram_error_log_index == -1)
-		return -1;
-
-	if (length > nvram_error_log_size)
-		length = nvram_error_log_size;
-
-	tmp_index = nvram_error_log_index;
-
-	rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
-		return rc;
-	}
-
-	rc = ppc_md.nvram_read(buff, length, &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
-		return rc;
-	}
-
-	error_log_cnt = info.seq_num;
-	*err_type = info.error_type;
-
-	return 0;
-}
-
-/* This doesn't actually zero anything, but it sets the event_logged
- * word to tell that this event is safely in syslog.
- */
-int nvram_clear_error_log(void)
-{
-	loff_t tmp_index;
-	int clear_word = ERR_FLAG_ALREADY_LOGGED;
-	int rc;
-
-	tmp_index = nvram_error_log_index;
-	
-	rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
-	if (rc <= 0) {
-		printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
-		return rc;
-	}
-
-	return 0;
-}
-
-#endif /* CONFIG_PPC_PSERIES */
-
-module_init(nvram_init);
-module_exit(nvram_cleanup);
-MODULE_LICENSE("GPL");
-- 
cgit v1.2.3