diff -urN -X dontdiff linux/arch/i386/kernel/mtrr.c linux-p6uc/arch/i386/kernel/mtrr.c
--- linux/arch/i386/kernel/mtrr.c	Fri Feb 11 20:07:52 2000
+++ linux-p6uc/arch/i386/kernel/mtrr.c	Tue Feb 15 23:57:18 2000
@@ -225,6 +225,10 @@
                success.
     19991008   Manfred Spraul <manfreds@colorfullife.com>
     	       replaced spin_lock_reschedule() with a normal semaphore.
+    20000215   Tigran Aivazian <tigran@sco.com>
+               Added MTRIOC_P6UPDATE ioctl for P6 microcode update.
+               Reference: Section 8.10 of Volume III, Intel Pentium III 
+	       Manual, Order Number 243192.
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -247,6 +251,7 @@
 #include <asm/mtrr.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -321,6 +326,8 @@
 static void compute_ascii (void);
 #endif
 
+static struct p6ucode * p6ucode = NULL;
+static int p6ucode_num = 0;
 
 struct set_mtrr_context
 {
@@ -1393,6 +1400,59 @@
     return -EINVAL;
 }   /*  End Function mtrr_write  */
 
+static void p6update_one(void *arg)
+{
+	struct cpuinfo_x86 * c;
+	unsigned int pf = 0, val[2], rev, sig;
+	int i, id;
+
+	id = smp_processor_id();
+	c = cpu_data + id;
+	sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
+
+	if (c->x86 >= 6 && c->x86_model >= 5) {
+		/* get processor flags from BBL_CR_OVRD MSR (0x17) */
+		rdmsr(0x17, val[0], val[1]);
+		pf = 1 << ((val[1] >> 18) & 7);
+	}
+
+	for (i=0; i<p6ucode_num; i++)
+		if (p6ucode[i].sig == sig && 
+		    p6ucode[i].pf == pf &&
+		    p6ucode[i].ldrver == 1 &&
+		    p6ucode[i].hdrver == 1) {
+			rdmsr(0x8B, val[0], rev);
+			if (p6ucode[i].rev <= rev) {
+				printk(KERN_ERR 
+					"p6update_one(): not 'upgrading' to earlier revision"
+					" %d (current=%d)\n", p6ucode[i].rev, rev);
+			} else { 
+				int sum = 0;
+				struct p6ucode *p = &p6ucode[i];
+				unsigned int *sump = (unsigned int *)(p+1);
+
+				while (--sump >= (unsigned int *)p)
+					sum += *sump;
+				if (sum != 0) {
+					printk(KERN_ERR "p6update_one(): aborting due to bad checksum\n");
+					break;
+				}
+				wrmsr(0x79, (unsigned int)(p->bits), 0);
+				__asm__ __volatile__ ("cpuid");
+				printk(KERN_ERR "p6update_one: CPU%d microcode updated\n", id);
+			}
+			break;
+		}
+}
+
+static int do_p6update(void)
+{
+	if (smp_call_function (p6update_one, NULL, 1, 0) != 0)
+	    panic("do_p6update(): timed out waiting for other CPUs\n");
+	p6update_one(NULL);
+	return -EINVAL;
+}
+
 static int mtrr_ioctl (struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
@@ -1400,34 +1460,65 @@
     mtrr_type type;
     struct mtrr_sentry sentry;
     struct mtrr_gentry gentry;
+    struct mtrr_p6update p6up_ioc;
+    int p6up_len;
 
     switch (cmd)
     {
       default:
 	return -ENOIOCTLCMD;
+      case MTRRIOC_P6UPDATE:
+	if ( !capable(CAP_SYS_RAWIO) ) return -EPERM;
+
+	/* basic sanity checks for this CPU */
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
+	    boot_cpu_data.x86 != 6)
+		return -EINVAL;
+
+	lock_kernel();
+	if ( copy_from_user (&p6up_ioc, (void *) arg, sizeof p6up_ioc) )
+	    return -EFAULT;
+	p6ucode_num = p6up_ioc.num;
+	p6up_len = p6up_ioc.num * sizeof(struct p6ucode);    
+	p6ucode = vmalloc(p6up_len);
+	if (!p6ucode) {
+		err = -ENOMEM;
+		unlock_kernel();
+        	break;
+	}
+	if ( copy_from_user (p6ucode, p6up_ioc.uaddr, p6up_len) ) {
+		err = -EFAULT;
+		vfree(p6ucode);
+		unlock_kernel();
+        	break;
+	}
+	err = do_p6update(); 
+	vfree(p6ucode);
+	unlock_kernel();
+	break;
       case MTRRIOC_ADD_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable (CAP_SYS_RAWIO) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_SET_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable (CAP_SYS_RAWIO) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_add (sentry.base, sentry.size, sentry.type, 0);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_DEL_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable (CAP_SYS_RAWIO) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_file_del (sentry.base, sentry.size, file);
 	if (err < 0) return err;
 	break;
       case MTRRIOC_KILL_ENTRY:
-	if ( !suser () ) return -EPERM;
+	if ( !capable (CAP_SYS_RAWIO) ) return -EPERM;
 	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
 	    return -EFAULT;
 	err = mtrr_del (-1, sentry.base, sentry.size);
diff -urN -X dontdiff linux/include/asm-i386/mtrr.h linux-p6uc/include/asm-i386/mtrr.h
--- linux/include/asm-i386/mtrr.h	Tue Dec 21 00:01:12 1999
+++ linux-p6uc/include/asm-i386/mtrr.h	Wed Feb 16 00:00:28 2000
@@ -43,12 +43,31 @@
     unsigned int type;     /*  Type of region   */
 };
 
+struct p6ucode {
+    unsigned int hdrver;
+    unsigned int rev;
+    unsigned int date;
+    unsigned int sig;
+    unsigned int cksum;
+    unsigned int ldrver;
+    unsigned int pf;
+    unsigned int reserved[5];
+    unsigned int bits[500];
+};
+
+struct mtrr_p6update
+{
+    unsigned int num;  /* number of 'struct p6ucode' elements, currently (15/02/2000) 48 */
+    void * uaddr;      /* pointer to the array of 'struct p6ucode' */
+};
+
 /*  These are the various ioctls  */
 #define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry)
 #define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry)
 #define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry)
 #define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
 #define MTRRIOC_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry)
+#define MTRRIOC_P6UPDATE         _IOW(MTRR_IOCTL_BASE,  5, struct mtrr_p6update)
 
 /*  These are the region types  */
 #define MTRR_TYPE_UNCACHABLE 0
