xref: /openbmc/linux/drivers/char/ipmi/ipmi_dmi.c (revision e2c75e76)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * A hack to create a platform device from a DMI entry.  This will
4  * allow autoloading of the IPMI drive based on SMBIOS entries.
5  */
6 
7 #include <linux/ipmi.h>
8 #include <linux/init.h>
9 #include <linux/dmi.h>
10 #include <linux/platform_device.h>
11 #include <linux/property.h>
12 #include "ipmi_si_sm.h"
13 #include "ipmi_dmi.h"
14 
15 #define IPMI_DMI_TYPE_KCS	0x01
16 #define IPMI_DMI_TYPE_SMIC	0x02
17 #define IPMI_DMI_TYPE_BT	0x03
18 #define IPMI_DMI_TYPE_SSIF	0x04
19 
20 struct ipmi_dmi_info {
21 	enum si_type si_type;
22 	u32 flags;
23 	unsigned long addr;
24 	u8 slave_addr;
25 	struct ipmi_dmi_info *next;
26 };
27 
28 static struct ipmi_dmi_info *ipmi_dmi_infos;
29 
30 static int ipmi_dmi_nr __initdata;
31 
32 #define set_prop_entry(_p_, _name_, type, val)	\
33 do {					\
34 	struct property_entry *_p = &_p_;	\
35 	_p->name = _name_;			\
36 	_p->length = sizeof(type);		\
37 	_p->is_string = false;			\
38 	_p->value.type##_data = val;		\
39 } while(0)
40 
41 static void __init dmi_add_platform_ipmi(unsigned long base_addr,
42 					 u32 flags,
43 					 u8 slave_addr,
44 					 int irq,
45 					 int offset,
46 					 int type)
47 {
48 	struct platform_device *pdev;
49 	struct resource r[4];
50 	unsigned int num_r = 1, size;
51 	struct property_entry p[5];
52 	unsigned int pidx = 0;
53 	char *name, *override;
54 	int rv;
55 	enum si_type si_type;
56 	struct ipmi_dmi_info *info;
57 
58 	memset(p, 0, sizeof(p));
59 
60 	name = "dmi-ipmi-si";
61 	override = "ipmi_si";
62 	switch (type) {
63 	case IPMI_DMI_TYPE_SSIF:
64 		name = "dmi-ipmi-ssif";
65 		override = "ipmi_ssif";
66 		offset = 1;
67 		size = 1;
68 		si_type = SI_TYPE_INVALID;
69 		break;
70 	case IPMI_DMI_TYPE_BT:
71 		size = 3;
72 		si_type = SI_BT;
73 		break;
74 	case IPMI_DMI_TYPE_KCS:
75 		size = 2;
76 		si_type = SI_KCS;
77 		break;
78 	case IPMI_DMI_TYPE_SMIC:
79 		size = 2;
80 		si_type = SI_SMIC;
81 		break;
82 	default:
83 		pr_err("ipmi:dmi: Invalid IPMI type: %d\n", type);
84 		return;
85 	}
86 
87 	if (si_type != SI_TYPE_INVALID)
88 		set_prop_entry(p[pidx++], "ipmi-type", u8, si_type);
89 	set_prop_entry(p[pidx++], "slave-addr", u8, slave_addr);
90 	set_prop_entry(p[pidx++], "addr-source", u8, SI_SMBIOS);
91 
92 	info = kmalloc(sizeof(*info), GFP_KERNEL);
93 	if (!info) {
94 		pr_warn("ipmi:dmi: Could not allocate dmi info\n");
95 	} else {
96 		info->si_type = si_type;
97 		info->flags = flags;
98 		info->addr = base_addr;
99 		info->slave_addr = slave_addr;
100 		info->next = ipmi_dmi_infos;
101 		ipmi_dmi_infos = info;
102 	}
103 
104 	pdev = platform_device_alloc(name, ipmi_dmi_nr);
105 	if (!pdev) {
106 		pr_err("ipmi:dmi: Error allocation IPMI platform device\n");
107 		return;
108 	}
109 	pdev->driver_override = kasprintf(GFP_KERNEL, "%s",
110 					  override);
111 	if (!pdev->driver_override)
112 		goto err;
113 
114 	if (type == IPMI_DMI_TYPE_SSIF) {
115 		set_prop_entry(p[pidx++], "i2c-addr", u16, base_addr);
116 		goto add_properties;
117 	}
118 
119 	memset(r, 0, sizeof(r));
120 
121 	r[0].start = base_addr;
122 	r[0].end = r[0].start + offset - 1;
123 	r[0].name = "IPMI Address 1";
124 	r[0].flags = flags;
125 
126 	if (size > 1) {
127 		r[1].start = r[0].start + offset;
128 		r[1].end = r[1].start + offset - 1;
129 		r[1].name = "IPMI Address 2";
130 		r[1].flags = flags;
131 		num_r++;
132 	}
133 
134 	if (size > 2) {
135 		r[2].start = r[1].start + offset;
136 		r[2].end = r[2].start + offset - 1;
137 		r[2].name = "IPMI Address 3";
138 		r[2].flags = flags;
139 		num_r++;
140 	}
141 
142 	if (irq) {
143 		r[num_r].start = irq;
144 		r[num_r].end = irq;
145 		r[num_r].name = "IPMI IRQ";
146 		r[num_r].flags = IORESOURCE_IRQ;
147 		num_r++;
148 	}
149 
150 	rv = platform_device_add_resources(pdev, r, num_r);
151 	if (rv) {
152 		dev_err(&pdev->dev,
153 			"ipmi:dmi: Unable to add resources: %d\n", rv);
154 		goto err;
155 	}
156 
157 add_properties:
158 	rv = platform_device_add_properties(pdev, p);
159 	if (rv) {
160 		dev_err(&pdev->dev,
161 			"ipmi:dmi: Unable to add properties: %d\n", rv);
162 		goto err;
163 	}
164 
165 	rv = platform_device_add(pdev);
166 	if (rv) {
167 		dev_err(&pdev->dev, "ipmi:dmi: Unable to add device: %d\n", rv);
168 		goto err;
169 	}
170 
171 	ipmi_dmi_nr++;
172 	return;
173 
174 err:
175 	platform_device_put(pdev);
176 }
177 
178 /*
179  * Look up the slave address for a given interface.  This is here
180  * because ACPI doesn't have a slave address while SMBIOS does, but we
181  * prefer using ACPI so the ACPI code can use the IPMI namespace.
182  * This function allows an ACPI-specified IPMI device to look up the
183  * slave address from the DMI table.
184  */
185 int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
186 			    unsigned long base_addr)
187 {
188 	struct ipmi_dmi_info *info = ipmi_dmi_infos;
189 
190 	while (info) {
191 		if (info->si_type == si_type &&
192 		    info->flags == flags &&
193 		    info->addr == base_addr)
194 			return info->slave_addr;
195 		info = info->next;
196 	}
197 
198 	return 0;
199 }
200 EXPORT_SYMBOL(ipmi_dmi_get_slave_addr);
201 
202 #define DMI_IPMI_MIN_LENGTH	0x10
203 #define DMI_IPMI_VER2_LENGTH	0x12
204 #define DMI_IPMI_TYPE		4
205 #define DMI_IPMI_SLAVEADDR	6
206 #define DMI_IPMI_ADDR		8
207 #define DMI_IPMI_ACCESS		0x10
208 #define DMI_IPMI_IRQ		0x11
209 #define DMI_IPMI_IO_MASK	0xfffe
210 
211 static void __init dmi_decode_ipmi(const struct dmi_header *dm)
212 {
213 	const u8	*data = (const u8 *) dm;
214 	u32             flags = IORESOURCE_IO;
215 	unsigned long	base_addr;
216 	u8              len = dm->length;
217 	u8              slave_addr;
218 	int             irq = 0, offset;
219 	int             type;
220 
221 	if (len < DMI_IPMI_MIN_LENGTH)
222 		return;
223 
224 	type = data[DMI_IPMI_TYPE];
225 	slave_addr = data[DMI_IPMI_SLAVEADDR];
226 
227 	memcpy(&base_addr, data + DMI_IPMI_ADDR, sizeof(unsigned long));
228 	if (len >= DMI_IPMI_VER2_LENGTH) {
229 		if (type == IPMI_DMI_TYPE_SSIF) {
230 			offset = 0;
231 			flags = 0;
232 			base_addr = data[DMI_IPMI_ADDR] >> 1;
233 			if (base_addr == 0) {
234 				/*
235 				 * Some broken systems put the I2C address in
236 				 * the slave address field.  We try to
237 				 * accommodate them here.
238 				 */
239 				base_addr = data[DMI_IPMI_SLAVEADDR] >> 1;
240 				slave_addr = 0;
241 			}
242 		} else {
243 			if (base_addr & 1) {
244 				/* I/O */
245 				base_addr &= DMI_IPMI_IO_MASK;
246 			} else {
247 				/* Memory */
248 				flags = IORESOURCE_MEM;
249 			}
250 
251 			/*
252 			 * If bit 4 of byte 0x10 is set, then the lsb
253 			 * for the address is odd.
254 			 */
255 			base_addr |= (data[DMI_IPMI_ACCESS] >> 4) & 1;
256 
257 			irq = data[DMI_IPMI_IRQ];
258 
259 			/*
260 			 * The top two bits of byte 0x10 hold the
261 			 * register spacing.
262 			 */
263 			switch ((data[DMI_IPMI_ACCESS] >> 6) & 3) {
264 			case 0: /* Byte boundaries */
265 				offset = 1;
266 				break;
267 			case 1: /* 32-bit boundaries */
268 				offset = 4;
269 				break;
270 			case 2: /* 16-byte boundaries */
271 				offset = 16;
272 				break;
273 			default:
274 				pr_err("ipmi:dmi: Invalid offset: 0\n");
275 				return;
276 			}
277 		}
278 	} else {
279 		/* Old DMI spec. */
280 		/*
281 		 * Note that technically, the lower bit of the base
282 		 * address should be 1 if the address is I/O and 0 if
283 		 * the address is in memory.  So many systems get that
284 		 * wrong (and all that I have seen are I/O) so we just
285 		 * ignore that bit and assume I/O.  Systems that use
286 		 * memory should use the newer spec, anyway.
287 		 */
288 		base_addr = base_addr & DMI_IPMI_IO_MASK;
289 		offset = 1;
290 	}
291 
292 	dmi_add_platform_ipmi(base_addr, flags, slave_addr, irq,
293 			      offset, type);
294 }
295 
296 static int __init scan_for_dmi_ipmi(void)
297 {
298 	const struct dmi_device *dev = NULL;
299 
300 	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev)))
301 		dmi_decode_ipmi((const struct dmi_header *) dev->device_data);
302 
303 	return 0;
304 }
305 subsys_initcall(scan_for_dmi_ipmi);
306