[patch-2.4.0-test1-ac9] /dev/cpu/microcode fixes

From: Tigran Aivazian (tigran@veritas.com)
Date: Tue Jun 06 2000 - 10:53:08 EST


Dear Alan,

Last Thursday (on Expo2000) you said that no Linux kernel feature
currently relies (or should rely) on devfs being present.

Therefore, here is the patch to the Intel P6 microcode update driver that
does:

a) makes the use of devfs optional, registering the driver as a misc
   device on minor 184 (which H. Peter Anvin kindly allocated earlier)

b) adds MICROCODE_IOCFREE ioctl to clear memory allocated by the
   driver. The previous idea of overloading O_WRONLY flag at open() time
   was flowed as it destroyed the data on unsuccessful attempt to update.

c) removes unnecessary zero-initialisations from the driver (as BSS is
   zero-cleared anyway)

d) updated Documentation/Changes and Documentation/ioctl-number.txt to
   reflect these changes.

e) typos, cleanups, email address changes etc.

Regards,
Tigran

diff -urN -X dontdiff linux/Documentation/Changes mc/Documentation/Changes
--- linux/Documentation/Changes Tue Jun 6 10:26:25 2000
+++ mc/Documentation/Changes Tue Jun 6 12:19:25 2000
@@ -132,6 +132,14 @@
 more information, see the files in Documentation/fb/ ; you may also
 need to download the fbset utilities.
 
+ Intel P6 microcode update driver can now be accessed both via devfs
+regular file and as a normal (misc) character device. If you are not using
+devfs you may need to:
+
+ - mkdir /dev/cpu
+ - mknod /dev/cpu/microcode c 10 184
+ - chmod 0644 /dev/cpu/microcode
+
 Libc (libc5)
 ============
 
diff -urN -X dontdiff linux/Documentation/ioctl-number.txt mc/Documentation/ioctl-number.txt
--- linux/Documentation/ioctl-number.txt Sat May 13 09:32:01 2000
+++ mc/Documentation/ioctl-number.txt Tue Jun 6 16:33:07 2000
@@ -74,6 +74,8 @@
 0x22 all scsi/sg.h
 '1' 00-1F <linux/timepps.h> PPS kit from Ulrich Windl
                                         <ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
+'6' 00-10 <asm-i386/processor.h> Intel P6 microcode update driver
+ <tigran@veritas.com>
 '8' all SNP8023 advanced NIC card
                                         <mailto:mcr@solidum.com>
 'A' 00-1F linux/apm_bios.h
diff -urN -X dontdiff linux/arch/i386/kernel/microcode.c mc/arch/i386/kernel/microcode.c
--- linux/arch/i386/kernel/microcode.c Thu Mar 2 18:10:24 2000
+++ mc/arch/i386/kernel/microcode.c Tue Jun 6 16:42:26 2000
@@ -25,6 +25,9 @@
  * and frees the saved copy of applied microcode.
  * 1.03 29 February 2000, Tigran Aivazian <tigran@sco.com>
  * Made to use devfs (/dev/cpu/microcode) + cleanups.
+ * 1.04 06 June 2000, Simon Trimmer <simon@veritas.com>
+ * Added misc device support (now uses both devfs and misc).
+ * Added MICROCODE_IOCFREE ioctl to clear memory.
  */
 
 #include <linux/init.h>
@@ -33,16 +36,17 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
+#include <linux/miscdevice.h>
 #include <linux/devfs_fs_kernel.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_VERSION "1.03"
+#define MICROCODE_VERSION "1.04"
 
-MODULE_DESCRIPTION("CPU (P6) microcode update driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
+MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
 EXPORT_NO_SYMBOLS;
 
 /* VFS interface */
@@ -50,6 +54,7 @@
 static int microcode_release(struct inode *, struct file *);
 static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
 static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
+static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 
 /* internal helpers to do the work */
@@ -60,43 +65,61 @@
  * Bits in microcode_status. (31 bits of room for future expansion)
  */
 #define MICROCODE_IS_OPEN 0 /* set if device is in use */
-static unsigned long microcode_status = 0;
+
+static unsigned long microcode_status;
 
 /* the actual array of microcode blocks, each 2048 bytes */
-static struct microcode *microcode = NULL;
-static unsigned int microcode_num = 0;
-static char *mc_applied = NULL; /* holds an array of applied microcode blocks */
-static unsigned int mc_fsize; /* used often, so compute once at microcode_init() */
+static struct microcode *microcode;
+static unsigned int microcode_num;
+static char *mc_applied; /* holds an array of applied microcode blocks */
+static unsigned int mc_fsize;
 
 static struct file_operations microcode_fops = {
         read: microcode_read,
         write: microcode_write,
+ ioctl: microcode_ioctl,
         open: microcode_open,
         release: microcode_release,
 };
 
+static struct miscdevice microcode_dev = {
+ minor: MICROCODE_MINOR,
+ name: "microcode",
+ fops: &microcode_fops,
+};
+
 static devfs_handle_t devfs_handle;
 
 static int __init microcode_init(void)
 {
- devfs_handle = devfs_register(NULL, "cpu/microcode", 0, DEVFS_FL_DEFAULT, 0, 0,
- S_IFREG | S_IRUSR | S_IWUSR, 0, 0, &microcode_fops, NULL);
- if (!devfs_handle) {
- printk(KERN_ERR "microcode: can't create /dev/cpu/microcode\n");
- return -ENOMEM;
- }
- /* XXX assume no hotplug CPUs so smp_num_cpus does not change */
- mc_fsize = smp_num_cpus * sizeof(struct microcode);
- printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
+ int error = 0;
+
+ if (misc_register(&microcode_dev) < 0) {
+ printk(KERN_WARNING
+ "microcode: can't misc_register on minor=%d\n",
+ MICROCODE_MINOR);
+ error = 1;
+ }
+ devfs_handle = devfs_register(NULL, "cpu/microcode", 0,
+ DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR,
+ 0, 0, &microcode_fops, NULL);
+ if (devfs_handle == NULL && error) {
+ printk(KERN_ERR "microcode: failed to devfs_register()\n");
+ return -EINVAL;
+ }
+ printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n",
+ MICROCODE_VERSION);
         return 0;
 }
 
 static void __exit microcode_exit(void)
 {
+ misc_deregister(&microcode_dev);
         devfs_unregister(devfs_handle);
         if (mc_applied)
                 kfree(mc_applied);
- printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
+ printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n",
+ MICROCODE_VERSION);
 }
 
 module_init(microcode_init);
@@ -114,13 +137,6 @@
         if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
                 return -EBUSY;
 
- if ((file->f_flags & O_ACCMODE) == O_WRONLY && mc_applied) {
- devfs_set_file_size(devfs_handle, 0);
- memset(mc_applied, 0, mc_fsize);
- kfree(mc_applied);
- mc_applied = NULL;
- }
-
         MOD_INC_USE_COUNT;
         return 0;
 }
@@ -132,7 +148,7 @@
         return 0;
 }
 
-/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one()
+/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one()
  * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
  * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
  */
@@ -240,7 +256,8 @@
                 return -EINVAL;
         }
         if (!mc_applied) {
- mc_applied = kmalloc(mc_fsize, GFP_KERNEL);
+ mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
+ GFP_KERNEL);
                 if (!mc_applied) {
                         printk(KERN_ERR "microcode: out of memory for saved microcode\n");
                         return -ENOMEM;
@@ -257,17 +274,45 @@
         }
         if (copy_from_user(microcode, buf, len)) {
                 ret = -EFAULT;
- goto out_vfree;
+ goto out_fsize;
         }
         if(do_microcode_update()) {
                 ret = -EIO;
- goto out_vfree;
+ goto out_fsize;
+ } else {
+ mc_fsize = smp_num_cpus * sizeof(struct microcode);
+ ret = (ssize_t)len;
         }
+out_fsize:
         devfs_set_file_size(devfs_handle, mc_fsize);
- ret = (ssize_t)len;
-out_vfree:
         vfree(microcode);
 out_unlock:
         unlock_kernel();
         return ret;
+}
+
+static int microcode_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ case MICROCODE_IOCFREE:
+ if (mc_applied) {
+ devfs_set_file_size(devfs_handle, 0);
+ memset(mc_applied, 0, mc_fsize);
+ kfree(mc_applied);
+ mc_applied = NULL;
+ printk(KERN_WARNING
+ "microcode: freed %d bytes\n", mc_fsize);
+ mc_fsize = 0;
+ return 0;
+ }
+ return -ENODATA;
+
+ default:
+ printk(KERN_ERR "microcode: unknown ioctl cmd=%d\n",
+ cmd);
+ return -EINVAL;
+ }
+ /* NOT REACHED */
+ return -EINVAL;
 }
diff -urN -X dontdiff linux/fs/bfs/inode.c mc/fs/bfs/inode.c
--- linux/fs/bfs/inode.c Mon Mar 13 20:35:39 2000
+++ mc/fs/bfs/inode.c Tue Jun 6 11:06:35 2000
@@ -1,7 +1,7 @@
 /*
  * fs/bfs/inode.c
  * BFS superblock and inode operations.
- * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ * Copyright (C) 1999 Tigran Aivazian <tigran@veritas.com>
  * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
  */
 
@@ -16,7 +16,7 @@
 
 #include "bfs_defs.h"
 
-MODULE_AUTHOR("Tigran A. Aivazian");
+MODULE_AUTHOR("Tigran A. Aivazian <tigran@veritas.com>");
 MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
 EXPORT_NO_SYMBOLS;
 
diff -urN -X dontdiff linux/include/asm-i386/processor.h mc/include/asm-i386/processor.h
--- linux/include/asm-i386/processor.h Tue Jun 6 10:26:26 2000
+++ mc/include/asm-i386/processor.h Tue Jun 6 16:32:37 2000
@@ -549,4 +549,6 @@
         unsigned int bits[500];
 };
 
+#define MICROCODE_IOCFREE _IO('6',0) /* because it is for P6 */
+
 #endif /* __ASM_I386_PROCESSOR_H */
diff -urN -X dontdiff linux/include/linux/miscdevice.h mc/include/linux/miscdevice.h
--- linux/include/linux/miscdevice.h Sat Mar 18 20:11:35 2000
+++ mc/include/linux/miscdevice.h Tue Jun 6 16:33:51 2000
@@ -20,6 +20,7 @@
 #define SUN_OPENPROM_MINOR 139
 #define NVRAM_MINOR 144
 #define I2O_MINOR 166
+#define MICROCODE_MINOR 184
 #define MISC_DYNAMIC_MINOR 255
 
 #define SGI_GRAPHICS_MINOR 146

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Jun 07 2000 - 21:00:25 EST