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 <[email protected]>
              replaced spin_lock_reschedule() with a normal semaphore.
+    20000215   Tigran Aivazian <[email protected]>
+               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