]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/i386/kernel/dmi_scan.c
[PATCH] DMI: only ioremap stuff we actually need
[linux-2.6-omap-h63xx.git] / arch / i386 / kernel / dmi_scan.c
index 6ae4ef472dbf017f8e52a7f55770d6ef69570139..c032f9e06bb61ebb362b144fe30a2de757524c56 100644 (file)
@@ -3,35 +3,33 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/dmi.h>
+#include <linux/efi.h>
 #include <linux/bootmem.h>
-
-
-struct dmi_header {
-       u8 type;
-       u8 length;
-       u16 handle;
-};
-
-#undef DMI_DEBUG
-
-#ifdef DMI_DEBUG
-#define dmi_printk(x) printk x
-#else
-#define dmi_printk(x)
-#endif
+#include <linux/slab.h>
+#include <asm/dmi.h>
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
        u8 *bp = ((u8 *) dm) + dm->length;
+       char *str = "";
 
-       if (!s)
-               return "";
-       s--;
-       while (s > 0 && *bp) {
-               bp += strlen(bp) + 1;
+       if (s) {
                s--;
-       }
-       return bp;
+               while (s > 0 && *bp) {
+                       bp += strlen(bp) + 1;
+                       s--;
+               }
+
+               if (*bp != 0) {
+                       str = dmi_alloc(strlen(bp) + 1);
+                       if (str != NULL)
+                               strcpy(str, bp);
+                       else
+                               printk(KERN_ERR "dmi_string: out of memory.\n");
+               }
+       }
+
+       return str;
 }
 
 /*
@@ -44,7 +42,7 @@ static int __init dmi_table(u32 base, int len, int num,
        u8 *buf, *data;
        int i = 0;
                
-       buf = bt_ioremap(base, len);
+       buf = dmi_ioremap(base, len);
        if (buf == NULL)
                return -1;
 
@@ -69,7 +67,7 @@ static int __init dmi_table(u32 base, int len, int num,
                data += 2;
                i++;
        }
-       bt_iounmap(buf, len);
+       dmi_iounmap(buf, len);
        return 0;
 }
 
@@ -85,25 +83,75 @@ static int __init dmi_checksum(u8 *buf)
 }
 
 static char *dmi_ident[DMI_STRING_MAX];
+static LIST_HEAD(dmi_devices);
 
 /*
  *     Save a DMI string
  */
 static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
 {
-       char *d = (char*)dm;
-       char *p = dmi_string(dm, d[string]);
+       char *p, *d = (char*) dm;
 
-       if (p == NULL || *p == 0)
-               return;
        if (dmi_ident[slot])
                return;
 
-       dmi_ident[slot] = alloc_bootmem(strlen(p) + 1);
-       if(dmi_ident[slot])
-               strcpy(dmi_ident[slot], p);
-       else
-               printk(KERN_ERR "dmi_save_ident: out of memory.\n");
+       p = dmi_string(dm, d[string]);
+       if (p == NULL)
+               return;
+
+       dmi_ident[slot] = p;
+}
+
+static void __init dmi_save_devices(struct dmi_header *dm)
+{
+       int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
+       struct dmi_device *dev;
+
+       for (i = 0; i < count; i++) {
+               char *d = (char *)(dm + 1) + (i * 2);
+
+               /* Skip disabled device */
+               if ((*d & 0x80) == 0)
+                       continue;
+
+               dev = dmi_alloc(sizeof(*dev));
+               if (!dev) {
+                       printk(KERN_ERR "dmi_save_devices: out of memory.\n");
+                       break;
+               }
+
+               dev->type = *d++ & 0x7f;
+               dev->name = dmi_string(dm, *d);
+               dev->device_data = NULL;
+
+               list_add(&dev->list, &dmi_devices);
+       }
+}
+
+static void __init dmi_save_ipmi_device(struct dmi_header *dm)
+{
+       struct dmi_device *dev;
+       void * data;
+
+       data = dmi_alloc(dm->length);
+       if (data == NULL) {
+               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+               return;
+       }
+
+       memcpy(data, dm, dm->length);
+
+       dev = dmi_alloc(sizeof(*dev));
+       if (!dev) {
+               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+               return;
+       }
+
+       dev->type = DMI_DEV_TYPE_IPMI;
+       dev->name = "IPMI controller";
+       dev->device_data = data;
+
+       list_add(&dev->list, &dmi_devices);
 }
 
 /*
@@ -113,83 +161,97 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
  */
 static void __init dmi_decode(struct dmi_header *dm)
 {
-       u8 *data __attribute__((__unused__)) = (u8 *)dm;
-       
        switch(dm->type) {
-       case  0:
-               dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4])));
+       case 0:         /* BIOS Information */
                dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-               dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-               dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8])));
                dmi_save_ident(dm, DMI_BIOS_DATE, 8);
                break;
-       case 1:
-               dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4])));
+       case 1:         /* System Information */
                dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-               dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-               dmi_printk(("Version: %s\n", dmi_string(dm, data[6])));
                dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-               dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7])));
                dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
                break;
-       case 2:
-               dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4])));
+       case 2:         /* Base Board Information */
                dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-               dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5])));
                dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-               dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6])));
                dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
                break;
+       case 10:        /* Onboard Devices Information */
+               dmi_save_devices(dm);
+               break;
+       case 38:        /* IPMI Device Information */
+               dmi_save_ipmi_device(dm);
        }
 }
 
-void __init dmi_scan_machine(void)
+static int __init dmi_present(char __iomem *p)
 {
        u8 buf[15];
+       memcpy_fromio(buf, p, 15);
+       if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+               u16 num = (buf[13] << 8) | buf[12];
+               u16 len = (buf[7] << 8) | buf[6];
+               u32 base = (buf[11] << 24) | (buf[10] << 16) |
+                       (buf[9] << 8) | buf[8];
+
+               /*
+                * DMI version 0.0 means that the real version is taken from
+                * the SMBIOS version, which we don't know at this point.
+                */
+               if (buf[14] != 0)
+                       printk(KERN_INFO "DMI %d.%d present.\n",
+                              buf[14] >> 4, buf[14] & 0xF);
+               else
+                       printk(KERN_INFO "DMI present.\n");
+               if (dmi_table(base,len, num, dmi_decode) == 0)
+                       return 0;
+       }
+       return 1;
+}
+
+void __init dmi_scan_machine(void)
+{
        char __iomem *p, *q;
+       int rc;
 
-       /*
-        * no iounmap() for that ioremap(); it would be a no-op, but it's
-        * so early in setup that sucker gets confused into doing what
-        * it shouldn't if we actually call it.
-        */
-       p = ioremap(0xF0000, 0x10000);
-       if (p == NULL)
-               goto out;
-
-       for (q = p; q < p + 0x10000; q += 16) {
-               memcpy_fromio(buf, q, 15);
-               if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
-                       u16 num = (buf[13] << 8) | buf[12];
-                       u16 len = (buf[7] << 8) | buf[6];
-                       u32 base = (buf[11] << 24) | (buf[10] << 16) |
-                                  (buf[9] << 8) | buf[8];
-
-                       /*
-                        * DMI version 0.0 means that the real version is taken from
-                        * the SMBIOS version, which we don't know at this point.
-                        */
-                       if (buf[14] != 0)
-                               printk(KERN_INFO "DMI %d.%d present.\n",
-                                       buf[14] >> 4, buf[14] & 0xF);
-                       else
-                               printk(KERN_INFO "DMI present.\n");
+       if (efi_enabled) {
+               if (!efi.smbios)
+                       goto out;
 
-                       dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-                               num, len));
-                       dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+               /* This is called as a core_initcall() because it isn't
+                * needed during early boot.  This also means we can
+                * iounmap the space when we're done with it.
+               */
+               p = dmi_ioremap((unsigned long)efi.smbios, 32);
+               if (p == NULL)
+                       goto out;
 
-                       if (dmi_table(base,len, num, dmi_decode) == 0)
+               rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
+               iounmap(p);
+               if (!rc)
+                       return;
+       }
+       else {
+               /*
+                * no iounmap() for that ioremap(); it would be a no-op, but
+                * it's so early in setup that sucker gets confused into doing
+                * what it shouldn't if we actually call it.
+                */
+               p = dmi_ioremap(0xF0000, 0x10000);
+               if (p == NULL)
+                       goto out;
+
+               for (q = p; q < p + 0x10000; q += 16) {
+                       rc = dmi_present(q);
+                       if (!rc)
                                return;
                }
        }
-
-out:   printk(KERN_INFO "DMI not present.\n");
+ out:  printk(KERN_INFO "DMI not present or invalid.\n");
 }
 
-
 /**
  *     dmi_check_system - check system DMI data
  *     @list: array of dmi_system_id structures to match against
@@ -213,9 +275,9 @@ int dmi_check_system(struct dmi_system_id *list)
                        /* No match */
                        goto fail;
                }
+               count++;
                if (d->callback && d->callback(d))
                        break;
-               count++;
 fail:          d++;
        }
 
@@ -235,3 +297,62 @@ char *dmi_get_system_info(int field)
        return dmi_ident[field];
 }
 EXPORT_SYMBOL(dmi_get_system_info);
+
+/**
+ *     dmi_find_device - find onboard device by type/name
+ *     @type: device type or %DMI_DEV_TYPE_ANY to match all device types
+ *     @desc: device name string or %NULL to match all
+ *     @from: previous device found in search, or %NULL for new search.
+ *
+ *     Iterates through the list of known onboard devices. If a device is
+ *     found with a matching @vendor and @device, a pointer to its device
+ *     structure is returned.  Otherwise, %NULL is returned.
+ *     A new search is initiated by passing %NULL to the @from argument.
+ *     If @from is not %NULL, searches continue from next device.
+ */
+struct dmi_device * dmi_find_device(int type, const char *name,
+                                   struct dmi_device *from)
+{
+       struct list_head *d, *head = from ? &from->list : &dmi_devices;
+
+       for(d = head->next; d != &dmi_devices; d = d->next) {
+               struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+
+               if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
+                   ((name == NULL) || (strcmp(dev->name, name) == 0)))
+                       return dev;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(dmi_find_device);
+
+/**
+ *     dmi_get_year - Return year of a DMI date
+ *     @field: data index (like dmi_get_system_info)
+ *
+ *     Returns -1 when the field doesn't exist. 0 when it is broken.
+ */
+int dmi_get_year(int field)
+{
+       int year;
+       char *s = dmi_get_system_info(field);
+
+       if (!s)
+               return -1;
+       if (*s == '\0')
+               return 0;
+       s = strrchr(s, '/');
+       if (!s)
+               return 0;
+
+       s += 1;
+       year = simple_strtoul(s, NULL, 0);
+       if (year && year < 100) {       /* 2-digit year */
+               year += 1900;
+               if (year < 1996)        /* no dates < spec 1.0 */
+                       year += 100;
+       }
+
+       return year;
+}