Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
new file mode 100644
index 0000000..86f9fd8
--- /dev/null
+++ b/arch/x86_64/kernel/mce.c
@@ -0,0 +1,548 @@
+/*
+ * Machine check handler.
+ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
+ * Rest from unknown author(s). 
+ * 2004 Andi Kleen. Rewrote most of it. 
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/rcupdate.h>
+#include <linux/kallsyms.h>
+#include <linux/sysdev.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <asm/processor.h> 
+#include <asm/msr.h>
+#include <asm/mce.h>
+#include <asm/kdebug.h>
+#include <asm/uaccess.h>
+
+#define MISC_MCELOG_MINOR 227
+#define NR_BANKS 5
+
+static int mce_dont_init;
+
+/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
+   3: never panic or exit (for testing only) */
+static int tolerant = 1;
+static int banks;
+static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
+static unsigned long console_logged;
+static int notify_user;
+
+/*
+ * Lockless MCE logging infrastructure.
+ * This avoids deadlocks on printk locks without having to break locks. Also
+ * separate MCEs from kernel messages to avoid bogus bug reports.
+ */
+
+struct mce_log mcelog = { 
+	MCE_LOG_SIGNATURE,
+	MCE_LOG_LEN,
+}; 
+
+void mce_log(struct mce *mce)
+{
+	unsigned next, entry;
+	mce->finished = 0;
+	smp_wmb();
+	for (;;) {
+		entry = rcu_dereference(mcelog.next);
+		/* When the buffer fills up discard new entries. Assume 
+		   that the earlier errors are the more interesting. */
+		if (entry >= MCE_LOG_LEN) {
+			set_bit(MCE_OVERFLOW, &mcelog.flags);
+			return;
+		}
+		/* Old left over entry. Skip. */
+		if (mcelog.entry[entry].finished)
+			continue;
+		smp_rmb();
+		next = entry + 1;
+		if (cmpxchg(&mcelog.next, entry, next) == entry)
+			break;
+	}
+	memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
+	smp_wmb();
+	mcelog.entry[entry].finished = 1;
+	smp_wmb();
+
+	if (!test_and_set_bit(0, &console_logged))
+		notify_user = 1;
+}
+
+static void print_mce(struct mce *m)
+{
+	printk(KERN_EMERG "\n"
+	       KERN_EMERG
+	       "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
+	       m->cpu, m->mcgstatus, m->bank, m->status);
+	if (m->rip) {
+		printk(KERN_EMERG 
+		       "RIP%s %02x:<%016Lx> ",
+		       !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
+		       m->cs, m->rip);
+		if (m->cs == __KERNEL_CS)
+			print_symbol("{%s}", m->rip);
+		printk("\n");
+	}
+	printk(KERN_EMERG "TSC %Lx ", m->tsc); 
+	if (m->addr)
+		printk("ADDR %Lx ", m->addr);
+	if (m->misc)
+		printk("MISC %Lx ", m->misc); 	
+	printk("\n");
+}
+
+static void mce_panic(char *msg, struct mce *backup, unsigned long start)
+{ 
+	int i;
+	oops_begin();
+	for (i = 0; i < MCE_LOG_LEN; i++) {
+		unsigned long tsc = mcelog.entry[i].tsc;
+		if (time_before(tsc, start))
+			continue;
+		print_mce(&mcelog.entry[i]); 
+		if (backup && mcelog.entry[i].tsc == backup->tsc)
+			backup = NULL;
+	}
+	if (backup)
+		print_mce(backup);
+	if (tolerant >= 3)
+		printk("Fake panic: %s\n", msg);
+	else
+		panic(msg);
+} 
+
+static int mce_available(struct cpuinfo_x86 *c)
+{
+	return test_bit(X86_FEATURE_MCE, &c->x86_capability) &&
+	       test_bit(X86_FEATURE_MCA, &c->x86_capability);
+}
+
+/* 
+ * The actual machine check handler
+ */
+
+void do_machine_check(struct pt_regs * regs, long error_code)
+{
+	struct mce m, panicm;
+	int nowayout = (tolerant < 1); 
+	int kill_it = 0;
+	u64 mcestart = 0;
+	int i;
+	int panicm_found = 0;
+
+	if (regs)
+		notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
+	if (!banks)
+		return;
+
+	memset(&m, 0, sizeof(struct mce));
+	m.cpu = hard_smp_processor_id();
+	rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+	if (!(m.mcgstatus & MCG_STATUS_RIPV))
+		kill_it = 1;
+	
+	rdtscll(mcestart);
+	barrier();
+
+	for (i = 0; i < banks; i++) {
+		if (!bank[i])
+			continue;
+		
+		m.misc = 0; 
+		m.addr = 0;
+		m.bank = i;
+		m.tsc = 0;
+
+		rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
+		if ((m.status & MCI_STATUS_VAL) == 0)
+			continue;
+
+		if (m.status & MCI_STATUS_EN) {
+			/* In theory _OVER could be a nowayout too, but
+			   assume any overflowed errors were no fatal. */
+			nowayout |= !!(m.status & MCI_STATUS_PCC);
+			kill_it |= !!(m.status & MCI_STATUS_UC);
+		}
+
+		if (m.status & MCI_STATUS_MISCV)
+			rdmsrl(MSR_IA32_MC0_MISC + i*4, m.misc);
+		if (m.status & MCI_STATUS_ADDRV)
+			rdmsrl(MSR_IA32_MC0_ADDR + i*4, m.addr);
+
+		if (regs && (m.mcgstatus & MCG_STATUS_RIPV)) {
+			m.rip = regs->rip;
+			m.cs = regs->cs;
+		} else {
+			m.rip = 0;
+			m.cs = 0;
+		}
+
+		if (error_code != -1)
+			rdtscll(m.tsc);
+		wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
+		mce_log(&m);
+
+		/* Did this bank cause the exception? */
+		/* Assume that the bank with uncorrectable errors did it,
+		   and that there is only a single one. */
+		if ((m.status & MCI_STATUS_UC) && (m.status & MCI_STATUS_EN)) {
+			panicm = m;
+			panicm_found = 1;
+		}
+
+		tainted |= TAINT_MACHINE_CHECK;
+	}
+
+	/* Never do anything final in the polling timer */
+	if (!regs)
+		goto out;
+
+	/* If we didn't find an uncorrectable error, pick
+	   the last one (shouldn't happen, just being safe). */
+	if (!panicm_found)
+		panicm = m;
+	if (nowayout)
+		mce_panic("Machine check", &panicm, mcestart);
+	if (kill_it) {
+		int user_space = 0;
+
+		if (m.mcgstatus & MCG_STATUS_RIPV)
+			user_space = panicm.rip && (panicm.cs & 3);
+		
+		/* When the machine was in user space and the CPU didn't get
+		   confused it's normally not necessary to panic, unless you 
+		   are paranoid (tolerant == 0)
+
+		   RED-PEN could be more tolerant for MCEs in idle,
+		   but most likely they occur at boot anyways, where
+		   it is best to just halt the machine. */
+		if ((!user_space && (panic_on_oops || tolerant < 2)) ||
+		    (unsigned)current->pid <= 1)
+			mce_panic("Uncorrected machine check", &panicm, mcestart);
+
+		/* do_exit takes an awful lot of locks and has as
+		   slight risk of deadlocking. If you don't want that
+		   don't set tolerant >= 2 */
+		if (tolerant < 3)
+			do_exit(SIGBUS);
+	}
+
+ out:
+	/* Last thing done in the machine check exception to clear state. */
+	wrmsrl(MSR_IA32_MCG_STATUS, 0);
+}
+
+/*
+ * Periodic polling timer for "silent" machine check errors.
+ */
+
+static int check_interval = 5 * 60; /* 5 minutes */
+static void mcheck_timer(void *data);
+static DECLARE_WORK(mcheck_work, mcheck_timer, NULL);
+
+static void mcheck_check_cpu(void *info)
+{
+	if (mce_available(&current_cpu_data))
+		do_machine_check(NULL, 0);
+}
+
+static void mcheck_timer(void *data)
+{
+	on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
+	schedule_delayed_work(&mcheck_work, check_interval * HZ);
+
+	/*
+	 * It's ok to read stale data here for notify_user and
+	 * console_logged as we'll simply get the updated versions
+	 * on the next mcheck_timer execution and atomic operations
+	 * on console_logged act as synchronization for notify_user
+	 * writes.
+	 */
+	if (notify_user && console_logged) {
+		notify_user = 0;
+		clear_bit(0, &console_logged);
+		printk(KERN_INFO "Machine check events logged\n");
+	}
+}
+
+
+static __init int periodic_mcheck_init(void)
+{ 
+	if (check_interval)
+		schedule_delayed_work(&mcheck_work, check_interval*HZ);
+	return 0;
+} 
+__initcall(periodic_mcheck_init);
+
+
+/* 
+ * Initialize Machine Checks for a CPU.
+ */
+static void mce_init(void *dummy)
+{
+	u64 cap;
+	int i;
+
+	rdmsrl(MSR_IA32_MCG_CAP, cap);
+	banks = cap & 0xff;
+	if (banks > NR_BANKS) { 
+		printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
+		banks = NR_BANKS; 
+	}
+
+	/* Log the machine checks left over from the previous reset.
+	   This also clears all registers */
+	do_machine_check(NULL, -1);
+
+	set_in_cr4(X86_CR4_MCE);
+
+	if (cap & MCG_CTL_P)
+		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+
+	for (i = 0; i < banks; i++) {
+		wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
+		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
+	}	
+}
+
+/* Add per CPU specific workarounds here */
+static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) 
+{ 
+	/* This should be disabled by the BIOS, but isn't always */
+	if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
+		/* disable GART TBL walk error reporting, which trips off 
+		   incorrectly with the IOMMU & 3ware & Cerberus. */
+		clear_bit(10, &bank[4]);
+	}
+}			
+
+static void __init mce_cpu_features(struct cpuinfo_x86 *c)
+{
+	switch (c->x86_vendor) {
+	case X86_VENDOR_INTEL:
+		mce_intel_feature_init(c);
+		break;
+	default:
+		break;
+	}
+}
+
+/* 
+ * Called for each booted CPU to set up machine checks.
+ * Must be called with preempt off. 
+ */
+void __init mcheck_init(struct cpuinfo_x86 *c)
+{
+	static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
+
+	mce_cpu_quirks(c); 
+
+	if (mce_dont_init ||
+	    cpu_test_and_set(smp_processor_id(), mce_cpus) ||
+	    !mce_available(c))
+		return;
+
+	mce_init(NULL);
+	mce_cpu_features(c);
+}
+
+/*
+ * Character device to read and clear the MCE log.
+ */
+
+static void collect_tscs(void *data) 
+{ 
+	unsigned long *cpu_tsc = (unsigned long *)data;
+	rdtscll(cpu_tsc[smp_processor_id()]);
+} 
+
+static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off)
+{
+	unsigned long cpu_tsc[NR_CPUS];
+	static DECLARE_MUTEX(mce_read_sem);
+	unsigned next;
+	char __user *buf = ubuf;
+	int i, err;
+
+	down(&mce_read_sem); 
+	next = rcu_dereference(mcelog.next);
+
+	/* Only supports full reads right now */
+	if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce)) { 
+		up(&mce_read_sem);
+		return -EINVAL;
+	}
+
+	err = 0;
+	for (i = 0; i < next; i++) {
+		if (!mcelog.entry[i].finished)
+			continue;
+		smp_rmb();
+		err |= copy_to_user(buf, mcelog.entry + i, sizeof(struct mce));
+		buf += sizeof(struct mce); 
+	} 
+
+	memset(mcelog.entry, 0, next * sizeof(struct mce));
+	mcelog.next = 0;
+
+	synchronize_kernel();	
+
+	/* Collect entries that were still getting written before the synchronize. */
+
+	on_each_cpu(collect_tscs, cpu_tsc, 1, 1);
+	for (i = next; i < MCE_LOG_LEN; i++) { 
+		if (mcelog.entry[i].finished && 
+		    mcelog.entry[i].tsc < cpu_tsc[mcelog.entry[i].cpu]) {  
+			err |= copy_to_user(buf, mcelog.entry+i, sizeof(struct mce));
+			smp_rmb();
+			buf += sizeof(struct mce);
+			memset(&mcelog.entry[i], 0, sizeof(struct mce));
+		}
+	} 	
+	up(&mce_read_sem);
+	return err ? -EFAULT : buf - ubuf; 
+}
+
+static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg)
+{
+	int __user *p = (int __user *)arg;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM; 
+	switch (cmd) {
+	case MCE_GET_RECORD_LEN: 
+		return put_user(sizeof(struct mce), p);
+	case MCE_GET_LOG_LEN:
+		return put_user(MCE_LOG_LEN, p);		
+	case MCE_GETCLEAR_FLAGS: {
+		unsigned flags;
+		do { 
+			flags = mcelog.flags;
+		} while (cmpxchg(&mcelog.flags, flags, 0) != flags); 
+		return put_user(flags, p); 
+	}
+	default:
+		return -ENOTTY; 
+	} 
+}
+
+static struct file_operations mce_chrdev_ops = {
+	.read = mce_read,
+	.ioctl = mce_ioctl,
+};
+
+static struct miscdevice mce_log_device = {
+	MISC_MCELOG_MINOR,
+	"mcelog",
+	&mce_chrdev_ops,
+};
+
+/* 
+ * Old style boot options parsing. Only for compatibility. 
+ */
+
+static int __init mcheck_disable(char *str)
+{
+	mce_dont_init = 1;
+	return 0;
+}
+
+/* mce=off disables machine check. Note you can reenable it later
+   using sysfs */
+static int __init mcheck_enable(char *str)
+{
+	if (!strcmp(str, "off"))
+		mce_dont_init = 1;
+	else
+		printk("mce= argument %s ignored. Please use /sys", str); 
+	return 0;
+}
+
+__setup("nomce", mcheck_disable);
+__setup("mce", mcheck_enable);
+
+/* 
+ * Sysfs support
+ */ 
+
+/* On resume clear all MCE state. Don't want to see leftovers from the BIOS. */
+static int mce_resume(struct sys_device *dev)
+{
+	on_each_cpu(mce_init, NULL, 1, 1);
+	return 0;
+}
+
+/* Reinit MCEs after user configuration changes */
+static void mce_restart(void) 
+{ 
+	if (check_interval)
+		cancel_delayed_work(&mcheck_work);
+	/* Timer race is harmless here */
+	on_each_cpu(mce_init, NULL, 1, 1);       
+	if (check_interval)
+		schedule_delayed_work(&mcheck_work, check_interval*HZ);
+}
+
+static struct sysdev_class mce_sysclass = {
+	.resume = mce_resume,
+	set_kset_name("machinecheck"),
+};
+
+static struct sys_device device_mce = {
+	.id	= 0,
+	.cls	= &mce_sysclass,
+};
+
+/* Why are there no generic functions for this? */
+#define ACCESSOR(name, var, start) \
+	static ssize_t show_ ## name(struct sys_device *s, char *buf) { 	   	   \
+		return sprintf(buf, "%lx\n", (unsigned long)var);		   \
+	} 									   \
+	static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \
+		char *end; 							   \
+		unsigned long new = simple_strtoul(buf, &end, 0); 		   \
+		if (end == buf) return -EINVAL;					   \
+		var = new;							   \
+		start; 								   \
+		return end-buf;		     					   \
+	}									   \
+	static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
+
+ACCESSOR(bank0ctl,bank[0],mce_restart())
+ACCESSOR(bank1ctl,bank[1],mce_restart())
+ACCESSOR(bank2ctl,bank[2],mce_restart())
+ACCESSOR(bank3ctl,bank[3],mce_restart())
+ACCESSOR(bank4ctl,bank[4],mce_restart())
+ACCESSOR(tolerant,tolerant,)
+ACCESSOR(check_interval,check_interval,mce_restart())
+
+static __init int mce_init_device(void)
+{
+	int err;
+	if (!mce_available(&boot_cpu_data))
+		return -EIO;
+	err = sysdev_class_register(&mce_sysclass);
+	if (!err)
+		err = sysdev_register(&device_mce);
+	if (!err) { 
+		/* could create per CPU objects, but it is not worth it. */
+		sysdev_create_file(&device_mce, &attr_bank0ctl); 
+		sysdev_create_file(&device_mce, &attr_bank1ctl); 
+		sysdev_create_file(&device_mce, &attr_bank2ctl); 
+		sysdev_create_file(&device_mce, &attr_bank3ctl); 
+		sysdev_create_file(&device_mce, &attr_bank4ctl); 
+		sysdev_create_file(&device_mce, &attr_tolerant); 
+		sysdev_create_file(&device_mce, &attr_check_interval);
+	} 
+	
+	misc_register(&mce_log_device);
+	return err;
+
+}
+device_initcall(mce_init_device);