From: Corey Minyard <cminy...@mvista.com>

It makes more sense to be there, and it's cleaner with the
upcoming conversion of IPMI DMI to a platform device.

Signed-off-by: Corey Minyard <cminy...@mvista.com>
Cc: Jean Delvare <jdelv...@suse.de>
Cc: Andy Lutomirski <l...@kernel.org>
---
 drivers/char/ipmi/ipmi_si_intf.c | 119 +++++++--------------------------------
 drivers/char/ipmi/ipmi_ssif.c    |  40 +++++--------
 drivers/firmware/dmi_scan.c      | 108 +++++++++++++++++++++++++++++++++--
 include/linux/dmi.h              |  26 +++++++++
 4 files changed, 162 insertions(+), 131 deletions(-)

diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 9fda22e..22292e1 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2272,98 +2272,36 @@ static void spmi_find_bmc(void)
 #endif
 
 #ifdef CONFIG_DMI
-struct dmi_ipmi_data {
-       u8              type;
-       u8              addr_space;
-       unsigned long   base_addr;
-       u8              irq;
-       u8              offset;
-       u8              slave_addr;
-};
-
-static int decode_dmi(const struct dmi_header *dm,
-                               struct dmi_ipmi_data *dmi)
+static void try_init_dmi(struct dmi_device *dmi_dev)
 {
-       const u8        *data = (const u8 *)dm;
-       unsigned long   base_addr;
-       u8              reg_spacing;
-       u8              len = dm->length;
+       struct dmi_dev_ipmi *ipmi_data = to_dmi_dev_ipmi(dmi_dev);
+       struct smi_info *info;
 
-       dmi->type = data[4];
+       if (!ipmi_data)
+               return;
 
-       memcpy(&base_addr, data+8, sizeof(unsigned long));
-       if (len >= 0x11) {
-               if (base_addr & 1) {
-                       /* I/O */
-                       base_addr &= 0xFFFE;
-                       dmi->addr_space = IPMI_IO_ADDR_SPACE;
-               } else
-                       /* Memory */
-                       dmi->addr_space = IPMI_MEM_ADDR_SPACE;
-
-               /* If bit 4 of byte 0x10 is set, then the lsb for the address
-                  is odd. */
-               dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
-
-               dmi->irq = data[0x11];
-
-               /* The top two bits of byte 0x10 hold the register spacing. */
-               reg_spacing = (data[0x10] & 0xC0) >> 6;
-               switch (reg_spacing) {
-               case 0x00: /* Byte boundaries */
-                   dmi->offset = 1;
-                   break;
-               case 0x01: /* 32-bit boundaries */
-                   dmi->offset = 4;
-                   break;
-               case 0x02: /* 16-byte boundaries */
-                   dmi->offset = 16;
-                   break;
-               default:
-                   /* Some other interface, just ignore it. */
-                   return -EIO;
-               }
-       } else {
-               /* Old DMI spec. */
-               /*
-                * Note that technically, the lower bit of the base
-                * address should be 1 if the address is I/O and 0 if
-                * the address is in memory.  So many systems get that
-                * wrong (and all that I have seen are I/O) so we just
-                * ignore that bit and assume I/O.  Systems that use
-                * memory should use the newer spec, anyway.
-                */
-               dmi->base_addr = base_addr & 0xfffe;
-               dmi->addr_space = IPMI_IO_ADDR_SPACE;
-               dmi->offset = 1;
+       if (!ipmi_data->good_data) {
+               pr_err(PFX "DMI data for this device was invalid.\n");
+               return;
        }
 
-       dmi->slave_addr = data[6];
-
-       return 0;
-}
-
-static void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
-{
-       struct smi_info *info;
-
        info = smi_info_alloc();
        if (!info) {
-               printk(KERN_ERR PFX "Could not allocate SI data\n");
+               pr_err(PFX "Could not allocate SI data\n");
                return;
        }
 
        info->addr_source = SI_SMBIOS;
-       printk(KERN_INFO PFX "probing via SMBIOS\n");
+       pr_info(PFX "probing via SMBIOS\n");
 
        switch (ipmi_data->type) {
-       case 0x01: /* KCS */
+       case IPMI_DMI_TYPE_KCS:
                info->si_type = SI_KCS;
                break;
-       case 0x02: /* SMIC */
+       case IPMI_DMI_TYPE_SMIC:
                info->si_type = SI_SMIC;
                break;
-       case 0x03: /* BT */
+       case IPMI_DMI_TYPE_BT:
                info->si_type = SI_BT;
                break;
        default:
@@ -2371,22 +2309,12 @@ static void try_init_dmi(struct dmi_ipmi_data 
*ipmi_data)
                return;
        }
 
-       switch (ipmi_data->addr_space) {
-       case IPMI_MEM_ADDR_SPACE:
-               info->io_setup = mem_setup;
-               info->io.addr_type = IPMI_MEM_ADDR_SPACE;
-               break;
-
-       case IPMI_IO_ADDR_SPACE:
+       if (ipmi_data->is_io_space) {
                info->io_setup = port_setup;
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
-               break;
-
-       default:
-               kfree(info);
-               printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n",
-                      ipmi_data->addr_space);
-               return;
+       } else {
+               info->io_setup = mem_setup;
+               info->io.addr_type = IPMI_MEM_ADDR_SPACE;
        }
        info->io.addr_data = ipmi_data->base_addr;
 
@@ -2413,17 +2341,10 @@ static void try_init_dmi(struct dmi_ipmi_data 
*ipmi_data)
 
 static void dmi_find_bmc(void)
 {
-       const struct dmi_device *dev = NULL;
-       struct dmi_ipmi_data data;
-       int                  rv;
+       struct dmi_device *dev = NULL;
 
-       while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
-               memset(&data, 0, sizeof(data));
-               rv = decode_dmi((const struct dmi_header *) dev->device_data,
-                               &data);
-               if (!rv)
-                       try_init_dmi(&data);
-       }
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev)))
+               try_init_dmi(dev);
 }
 #endif /* CONFIG_DMI */
 
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 5f1c3d0..7be0109 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1906,42 +1906,28 @@ static void spmi_find_bmc(void) { }
 #endif
 
 #ifdef CONFIG_DMI
-static int decode_dmi(const struct dmi_device *dmi_dev)
+static int decode_dmi(struct dmi_device *dmi_dev)
 {
-       struct dmi_header *dm = dmi_dev->device_data;
-       u8             *data = (u8 *) dm;
-       u8             len = dm->length;
-       unsigned short myaddr;
-       int            slave_addr;
-
-       if (num_addrs >= MAX_SSIF_BMCS)
-               return -1;
+       struct dmi_dev_ipmi *ipmi_data = to_dmi_dev_ipmi(dmi_dev);
 
-       if (len < 9)
-               return -1;
-
-       if (data[0x04] != 4) /* Not SSIF */
-               return -1;
+       if (!ipmi_data)
+               return -ENODEV;
 
-       if ((data[8] >> 1) == 0) {
-               /*
-                * Some broken systems put the I2C address in
-                * the slave address field.  We try to
-                * accommodate them here.
-                */
-               myaddr = data[6] >> 1;
-               slave_addr = 0;
-       } else {
-               myaddr = data[8] >> 1;
-               slave_addr = data[6];
+       if (!ipmi_data->good_data) {
+               pr_err(PFX "DMI data for this device was invalid.\n");
+               return -EINVAL;
        }
 
-       return new_ssif_client(myaddr, NULL, 0, 0, SI_SMBIOS);
+       if (ipmi_data->type != IPMI_DMI_TYPE_SSIF)
+               return -ENODEV;
+
+       return new_ssif_client(ipmi_data->base_addr, NULL, 0,
+                              ipmi_data->slave_addr, SI_SMBIOS);
 }
 
 static void dmi_iterator(void)
 {
-       const struct dmi_device *dev = NULL;
+       struct dmi_device *dev = NULL;
 
        while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev)))
                decode_dmi(dev);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 13d9bca..6e4859d 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -313,9 +313,105 @@ static void __init dmi_save_oem_strings_devices(const 
struct dmi_header *dm)
        }
 }
 
+#define DMI_IPMI_MIN_LENGTH    0x10
+#define DMI_IPMI_VER2_LENGTH   0x12
+#define DMI_IPMI_TYPE          4
+#define DMI_IPMI_SLAVEADDR     6
+#define DMI_IPMI_ADDR          8
+#define DMI_IPMI_ACCESS                0x10
+#define DMI_IPMI_IRQ           0x11
+#define DMI_IPMI_IO_MASK       0xfffe
+
+static void __init dmi_decode_ipmi(struct dmi_dev_ipmi *dev,
+                                  const struct dmi_header *dm)
+{
+       const u8        *data = (const u8 *) dm;
+       unsigned long   base_addr;
+       u8              len = dm->length;
+       bool            slave_addr_set;
+
+       if (len < DMI_IPMI_MIN_LENGTH)
+               return;
+
+       dev->type = data[DMI_IPMI_TYPE];
+
+       memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long));
+       if (len >= DMI_IPMI_VER2_LENGTH) {
+               if (dev->type == IPMI_DMI_TYPE_SSIF) {
+                       if ((data[DMI_IPMI_ADDR] >> 1) == 0) {
+                               /*
+                                * Some broken systems put the I2C address in
+                                * the slave address field.  We try to
+                                * accommodate them here.
+                                */
+                               dev->base_addr = data[DMI_IPMI_SLAVEADDR] >> 1;
+                               dev->slave_addr = 0;
+                               slave_addr_set = true;
+                       } else {
+                               dev->base_addr = data[DMI_IPMI_ADDR] >> 1;
+                       }
+               } else {
+                       if (base_addr & 1) {
+                               /* I/O */
+                               base_addr &= DMI_IPMI_IO_MASK;
+                               dev->is_io_space = 1;
+                       } else {
+                               /* Memory */
+                               dev->is_io_space = 0;
+                       }
+
+                       /*
+                        * If bit 4 of byte 0x10 is set, then the lsb
+                        * for the address is odd.
+                        */
+                       base_addr |= (data[DMI_IPMI_ACCESS] >> 4) & 1;
+
+                       dev->base_addr = base_addr;
+                       dev->irq = data[DMI_IPMI_IRQ];
+
+                       /*
+                        * The top two bits of byte 0x10 hold the
+                        * register spacing.
+                        */
+                       switch ((data[DMI_IPMI_ACCESS] >> 6) & 3) {
+                       case 0: /* Byte boundaries */
+                               dev->offset = 1;
+                               break;
+                       case 1: /* 32-bit boundaries */
+                               dev->offset = 4;
+                               break;
+                       case 2: /* 16-byte boundaries */
+                               dev->offset = 16;
+                               break;
+                       default:
+                               /* Leave 0 for undefined. */
+                               return;
+                       }
+               }
+       } else {
+               /* Old DMI spec. */
+               /*
+                * Note that technically, the lower bit of the base
+                * address should be 1 if the address is I/O and 0 if
+                * the address is in memory.  So many systems get that
+                * wrong (and all that I have seen are I/O) so we just
+                * ignore that bit and assume I/O.  Systems that use
+                * memory should use the newer spec, anyway.
+                */
+               dev->base_addr = base_addr & DMI_IPMI_IO_MASK;
+               dev->is_io_space = 1;
+               dev->offset = 1;
+       }
+
+       if (!slave_addr_set)
+               dev->slave_addr = data[DMI_IPMI_SLAVEADDR];
+
+       dev->good_data = 1;
+}
+
 static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
 {
-       struct dmi_device *dev;
+       struct dmi_dev_ipmi *dev;
        void *data;
 
        data = dmi_alloc(dm->length);
@@ -328,11 +424,13 @@ static void __init dmi_save_ipmi_device(const struct 
dmi_header *dm)
        if (!dev)
                return;
 
-       dev->type = DMI_DEV_TYPE_IPMI;
-       dev->name = "IPMI controller";
-       dev->device_data = data;
+       dev->dev.type = DMI_DEV_TYPE_IPMI;
+       dev->dev.name = "IPMI controller";
+       dev->dev.device_data = data;
 
-       dmi_devices_list_add(dev);
+       dmi_decode_ipmi(dev, dm);
+
+       dmi_devices_list_add(&dev->dev);
 }
 
 static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus,
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index e130c38..ca37ba5 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -97,6 +97,24 @@ struct dmi_dev_onboard {
        int devfn;
 };
 
+/* Device data for an IPMI entry. */
+struct dmi_dev_ipmi {
+       struct dmi_device dev;
+       u8              good_data;
+       u8              type;
+       u8              is_io_space;
+       u8              irq;
+       u8              offset;
+       u8              slave_addr;
+       unsigned long   base_addr;
+};
+
+/* dmi_ipmi_data type field */
+#define IPMI_DMI_TYPE_KCS      0x01
+#define IPMI_DMI_TYPE_SMIC     0x02
+#define IPMI_DMI_TYPE_BT       0x03
+#define IPMI_DMI_TYPE_SSIF     0x04
+
 extern struct kobject *dmi_kobj;
 extern int dmi_check_system(const struct dmi_system_id *list);
 const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
@@ -127,6 +145,14 @@ static inline struct dmi_device *to_dmi_device(struct 
fwnode_handle *fwnode)
        return NULL;
 }
 
+static inline struct dmi_dev_ipmi *to_dmi_dev_ipmi(struct dmi_device *dev)
+{
+       if (!dev || dev->type != DMI_DEV_TYPE_IPMI)
+               return NULL;
+
+       return container_of(dev, struct dmi_dev_ipmi, dev);
+}
+
 #else
 
 static inline int dmi_check_system(const struct dmi_system_id *list) { return 
0; }
-- 
2.5.0

Reply via email to