0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) "%s" fmt, "ipmi:dmi: "
0008 #define dev_fmt pr_fmt
0009
0010 #include <linux/ipmi.h>
0011 #include <linux/init.h>
0012 #include <linux/dmi.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/property.h>
0015 #include "ipmi_dmi.h"
0016 #include "ipmi_plat_data.h"
0017
0018 #define IPMI_DMI_TYPE_KCS 0x01
0019 #define IPMI_DMI_TYPE_SMIC 0x02
0020 #define IPMI_DMI_TYPE_BT 0x03
0021 #define IPMI_DMI_TYPE_SSIF 0x04
0022
0023 struct ipmi_dmi_info {
0024 enum si_type si_type;
0025 unsigned int space;
0026 unsigned long addr;
0027 u8 slave_addr;
0028 struct ipmi_dmi_info *next;
0029 };
0030
0031 static struct ipmi_dmi_info *ipmi_dmi_infos;
0032
0033 static int ipmi_dmi_nr __initdata;
0034
0035 static void __init dmi_add_platform_ipmi(unsigned long base_addr,
0036 unsigned int space,
0037 u8 slave_addr,
0038 int irq,
0039 int offset,
0040 int type)
0041 {
0042 const char *name;
0043 struct ipmi_dmi_info *info;
0044 struct ipmi_plat_data p;
0045
0046 memset(&p, 0, sizeof(p));
0047
0048 name = "dmi-ipmi-si";
0049 p.iftype = IPMI_PLAT_IF_SI;
0050 switch (type) {
0051 case IPMI_DMI_TYPE_SSIF:
0052 name = "dmi-ipmi-ssif";
0053 p.iftype = IPMI_PLAT_IF_SSIF;
0054 p.type = SI_TYPE_INVALID;
0055 break;
0056 case IPMI_DMI_TYPE_BT:
0057 p.type = SI_BT;
0058 break;
0059 case IPMI_DMI_TYPE_KCS:
0060 p.type = SI_KCS;
0061 break;
0062 case IPMI_DMI_TYPE_SMIC:
0063 p.type = SI_SMIC;
0064 break;
0065 default:
0066 pr_err("Invalid IPMI type: %d\n", type);
0067 return;
0068 }
0069
0070 p.addr = base_addr;
0071 p.space = space;
0072 p.regspacing = offset;
0073 p.irq = irq;
0074 p.slave_addr = slave_addr;
0075 p.addr_source = SI_SMBIOS;
0076
0077 info = kmalloc(sizeof(*info), GFP_KERNEL);
0078 if (!info) {
0079 pr_warn("Could not allocate dmi info\n");
0080 } else {
0081 info->si_type = p.type;
0082 info->space = space;
0083 info->addr = base_addr;
0084 info->slave_addr = slave_addr;
0085 info->next = ipmi_dmi_infos;
0086 ipmi_dmi_infos = info;
0087 }
0088
0089 if (ipmi_platform_add(name, ipmi_dmi_nr, &p))
0090 ipmi_dmi_nr++;
0091 }
0092
0093
0094
0095
0096
0097
0098
0099
0100 int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
0101 unsigned long base_addr)
0102 {
0103 struct ipmi_dmi_info *info = ipmi_dmi_infos;
0104
0105 while (info) {
0106 if (info->si_type == si_type &&
0107 info->space == space &&
0108 info->addr == base_addr)
0109 return info->slave_addr;
0110 info = info->next;
0111 }
0112
0113 return 0;
0114 }
0115 EXPORT_SYMBOL(ipmi_dmi_get_slave_addr);
0116
0117 #define DMI_IPMI_MIN_LENGTH 0x10
0118 #define DMI_IPMI_VER2_LENGTH 0x12
0119 #define DMI_IPMI_TYPE 4
0120 #define DMI_IPMI_SLAVEADDR 6
0121 #define DMI_IPMI_ADDR 8
0122 #define DMI_IPMI_ACCESS 0x10
0123 #define DMI_IPMI_IRQ 0x11
0124 #define DMI_IPMI_IO_MASK 0xfffe
0125
0126 static void __init dmi_decode_ipmi(const struct dmi_header *dm)
0127 {
0128 const u8 *data = (const u8 *) dm;
0129 int space = IPMI_IO_ADDR_SPACE;
0130 unsigned long base_addr;
0131 u8 len = dm->length;
0132 u8 slave_addr;
0133 int irq = 0, offset = 0;
0134 int type;
0135
0136 if (len < DMI_IPMI_MIN_LENGTH)
0137 return;
0138
0139 type = data[DMI_IPMI_TYPE];
0140 slave_addr = data[DMI_IPMI_SLAVEADDR];
0141
0142 memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long));
0143 if (!base_addr) {
0144 pr_err("Base address is zero, assuming no IPMI interface\n");
0145 return;
0146 }
0147 if (len >= DMI_IPMI_VER2_LENGTH) {
0148 if (type == IPMI_DMI_TYPE_SSIF) {
0149 space = 0;
0150 base_addr = data[DMI_IPMI_ADDR] >> 1;
0151 if (base_addr == 0) {
0152
0153
0154
0155
0156
0157 base_addr = data[DMI_IPMI_SLAVEADDR] >> 1;
0158 slave_addr = 0;
0159 }
0160 } else {
0161 if (base_addr & 1) {
0162
0163 base_addr &= DMI_IPMI_IO_MASK;
0164 } else {
0165
0166 space = IPMI_MEM_ADDR_SPACE;
0167 }
0168
0169
0170
0171
0172
0173 base_addr |= (data[DMI_IPMI_ACCESS] >> 4) & 1;
0174
0175 irq = data[DMI_IPMI_IRQ];
0176
0177
0178
0179
0180
0181 switch ((data[DMI_IPMI_ACCESS] >> 6) & 3) {
0182 case 0:
0183 offset = 1;
0184 break;
0185 case 1:
0186 offset = 4;
0187 break;
0188 case 2:
0189 offset = 16;
0190 break;
0191 default:
0192 pr_err("Invalid offset: 0\n");
0193 return;
0194 }
0195 }
0196 } else {
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 base_addr = base_addr & DMI_IPMI_IO_MASK;
0207 offset = 1;
0208 }
0209
0210 dmi_add_platform_ipmi(base_addr, space, slave_addr, irq,
0211 offset, type);
0212 }
0213
0214 static int __init scan_for_dmi_ipmi(void)
0215 {
0216 const struct dmi_device *dev = NULL;
0217
0218 while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev)))
0219 dmi_decode_ipmi((const struct dmi_header *) dev->device_data);
0220
0221 return 0;
0222 }
0223 subsys_initcall(scan_for_dmi_ipmi);