xref: /openbmc/linux/drivers/misc/mei/bus-fixup.c (revision 89551fdd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2013-2020, Intel Corporation. All rights reserved.
4  * Intel Management Engine Interface (Intel MEI) Linux driver
5  */
6 
7 #include <linux/kernel.h>
8 #include <linux/sched.h>
9 #include <linux/module.h>
10 #include <linux/device.h>
11 #include <linux/slab.h>
12 #include <linux/uuid.h>
13 
14 #include <linux/mei_cl_bus.h>
15 
16 #include "mei_dev.h"
17 #include "client.h"
18 
19 #define MEI_UUID_NFC_INFO UUID_LE(0xd2de1625, 0x382d, 0x417d, \
20 			0x48, 0xa4, 0xef, 0xab, 0xba, 0x8a, 0x12, 0x06)
21 
22 static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO;
23 
24 #define MEI_UUID_NFC_HCI UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \
25 			0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
26 
27 #define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
28 			    0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
29 
30 #define MEI_UUID_MKHIF_FIX UUID_LE(0x55213584, 0x9a29, 0x4916, \
31 			0xba, 0xdf, 0xf, 0xb7, 0xed, 0x68, 0x2a, 0xeb)
32 
33 #define MEI_UUID_IGSC_MKHI UUID_LE(0xE2C2AFA2, 0x3817, 0x4D19, \
34 			0x9D, 0x95, 0x06, 0xB1, 0x6B, 0x58, 0x8A, 0x5D)
35 
36 #define MEI_UUID_IGSC_MKHI_FIX UUID_LE(0x46E0C1FB, 0xA546, 0x414F, \
37 			0x91, 0x70, 0xB7, 0xF4, 0x6D, 0x57, 0xB4, 0xAD)
38 
39 #define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, \
40 			      0xA5, 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04)
41 
42 #define MEI_UUID_PAVP UUID_LE(0xfbf6fcf1, 0x96cf, 0x4e2e, 0xA6, \
43 			      0xa6, 0x1b, 0xab, 0x8c, 0xbe, 0x36, 0xb1)
44 
45 #define MEI_UUID_ANY NULL_UUID_LE
46 
47 /**
48  * number_of_connections - determine whether an client be on the bus
49  *    according number of connections
50  *    We support only clients:
51  *       1. with single connection
52  *       2. and fixed clients (max_number_of_connections == 0)
53  *
54  * @cldev: me clients device
55  */
56 static void number_of_connections(struct mei_cl_device *cldev)
57 {
58 	if (cldev->me_cl->props.max_number_of_connections > 1)
59 		cldev->do_match = 0;
60 }
61 
62 /**
63  * blacklist - blacklist a client from the bus
64  *
65  * @cldev: me clients device
66  */
67 static void blacklist(struct mei_cl_device *cldev)
68 {
69 	cldev->do_match = 0;
70 }
71 
72 /**
73  * whitelist - forcefully whitelist client
74  *
75  * @cldev: me clients device
76  */
77 static void whitelist(struct mei_cl_device *cldev)
78 {
79 	cldev->do_match = 1;
80 }
81 
82 #define OSTYPE_LINUX    2
83 struct mei_os_ver {
84 	__le16 build;
85 	__le16 reserved1;
86 	u8  os_type;
87 	u8  major;
88 	u8  minor;
89 	u8  reserved2;
90 } __packed;
91 
92 #define MKHI_FEATURE_PTT 0x10
93 
94 struct mkhi_rule_id {
95 	__le16 rule_type;
96 	u8 feature_id;
97 	u8 reserved;
98 } __packed;
99 
100 struct mkhi_fwcaps {
101 	struct mkhi_rule_id id;
102 	u8 len;
103 	u8 data[];
104 } __packed;
105 
106 struct mkhi_fw_ver_block {
107 	u16 minor;
108 	u8 major;
109 	u8 platform;
110 	u16 buildno;
111 	u16 hotfix;
112 } __packed;
113 
114 struct mkhi_fw_ver {
115 	struct mkhi_fw_ver_block ver[MEI_MAX_FW_VER_BLOCKS];
116 } __packed;
117 
118 #define MKHI_FWCAPS_GROUP_ID 0x3
119 #define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6
120 #define MKHI_GEN_GROUP_ID 0xFF
121 #define MKHI_GEN_GET_FW_VERSION_CMD 0x2
122 struct mkhi_msg_hdr {
123 	u8  group_id;
124 	u8  command;
125 	u8  reserved;
126 	u8  result;
127 } __packed;
128 
129 struct mkhi_msg {
130 	struct mkhi_msg_hdr hdr;
131 	u8 data[];
132 } __packed;
133 
134 #define MKHI_OSVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
135 			    sizeof(struct mkhi_fwcaps) + \
136 			    sizeof(struct mei_os_ver))
137 static int mei_osver(struct mei_cl_device *cldev)
138 {
139 	const size_t size = MKHI_OSVER_BUF_LEN;
140 	char buf[MKHI_OSVER_BUF_LEN];
141 	struct mkhi_msg *req;
142 	struct mkhi_fwcaps *fwcaps;
143 	struct mei_os_ver *os_ver;
144 	unsigned int mode = MEI_CL_IO_TX_BLOCKING | MEI_CL_IO_TX_INTERNAL;
145 
146 	memset(buf, 0, size);
147 
148 	req = (struct mkhi_msg *)buf;
149 	req->hdr.group_id = MKHI_FWCAPS_GROUP_ID;
150 	req->hdr.command = MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD;
151 
152 	fwcaps = (struct mkhi_fwcaps *)req->data;
153 
154 	fwcaps->id.rule_type = 0x0;
155 	fwcaps->id.feature_id = MKHI_FEATURE_PTT;
156 	fwcaps->len = sizeof(*os_ver);
157 	os_ver = (struct mei_os_ver *)fwcaps->data;
158 	os_ver->os_type = OSTYPE_LINUX;
159 
160 	return __mei_cl_send(cldev->cl, buf, size, 0, mode);
161 }
162 
163 #define MKHI_FWVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
164 			    sizeof(struct mkhi_fw_ver))
165 #define MKHI_FWVER_LEN(__num) (sizeof(struct mkhi_msg_hdr) + \
166 			       sizeof(struct mkhi_fw_ver_block) * (__num))
167 #define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */
168 static int mei_fwver(struct mei_cl_device *cldev)
169 {
170 	char buf[MKHI_FWVER_BUF_LEN];
171 	struct mkhi_msg req;
172 	struct mkhi_msg *rsp;
173 	struct mkhi_fw_ver *fwver;
174 	int bytes_recv, ret, i;
175 
176 	memset(buf, 0, sizeof(buf));
177 
178 	req.hdr.group_id = MKHI_GEN_GROUP_ID;
179 	req.hdr.command = MKHI_GEN_GET_FW_VERSION_CMD;
180 
181 	ret = __mei_cl_send(cldev->cl, (u8 *)&req, sizeof(req), 0,
182 			    MEI_CL_IO_TX_BLOCKING);
183 	if (ret < 0) {
184 		dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n");
185 		return ret;
186 	}
187 
188 	ret = 0;
189 	bytes_recv = __mei_cl_recv(cldev->cl, buf, sizeof(buf), NULL, 0,
190 				   MKHI_RCV_TIMEOUT);
191 	if (bytes_recv < 0 || (size_t)bytes_recv < MKHI_FWVER_LEN(1)) {
192 		/*
193 		 * Should be at least one version block,
194 		 * error out if nothing found
195 		 */
196 		dev_err(&cldev->dev, "Could not read FW version\n");
197 		return -EIO;
198 	}
199 
200 	rsp = (struct mkhi_msg *)buf;
201 	fwver = (struct mkhi_fw_ver *)rsp->data;
202 	memset(cldev->bus->fw_ver, 0, sizeof(cldev->bus->fw_ver));
203 	for (i = 0; i < MEI_MAX_FW_VER_BLOCKS; i++) {
204 		if ((size_t)bytes_recv < MKHI_FWVER_LEN(i + 1))
205 			break;
206 		dev_dbg(&cldev->dev, "FW version%d %d:%d.%d.%d.%d\n",
207 			i, fwver->ver[i].platform,
208 			fwver->ver[i].major, fwver->ver[i].minor,
209 			fwver->ver[i].hotfix, fwver->ver[i].buildno);
210 
211 		cldev->bus->fw_ver[i].platform = fwver->ver[i].platform;
212 		cldev->bus->fw_ver[i].major = fwver->ver[i].major;
213 		cldev->bus->fw_ver[i].minor = fwver->ver[i].minor;
214 		cldev->bus->fw_ver[i].hotfix = fwver->ver[i].hotfix;
215 		cldev->bus->fw_ver[i].buildno = fwver->ver[i].buildno;
216 	}
217 
218 	return ret;
219 }
220 
221 static void mei_mkhi_fix(struct mei_cl_device *cldev)
222 {
223 	int ret;
224 
225 	/* No need to enable the client if nothing is needed from it */
226 	if (!cldev->bus->fw_f_fw_ver_supported &&
227 	    !cldev->bus->hbm_f_os_supported)
228 		return;
229 
230 	ret = mei_cldev_enable(cldev);
231 	if (ret)
232 		return;
233 
234 	if (cldev->bus->fw_f_fw_ver_supported) {
235 		ret = mei_fwver(cldev);
236 		if (ret < 0)
237 			dev_err(&cldev->dev, "FW version command failed %d\n",
238 				ret);
239 	}
240 
241 	if (cldev->bus->hbm_f_os_supported) {
242 		ret = mei_osver(cldev);
243 		if (ret < 0)
244 			dev_err(&cldev->dev, "OS version command failed %d\n",
245 				ret);
246 	}
247 	mei_cldev_disable(cldev);
248 }
249 
250 static void mei_gsc_mkhi_ver(struct mei_cl_device *cldev)
251 {
252 	int ret;
253 
254 	/* No need to enable the client if nothing is needed from it */
255 	if (!cldev->bus->fw_f_fw_ver_supported)
256 		return;
257 
258 	ret = mei_cldev_enable(cldev);
259 	if (ret)
260 		return;
261 
262 	ret = mei_fwver(cldev);
263 	if (ret < 0)
264 		dev_err(&cldev->dev, "FW version command failed %d\n", ret);
265 	mei_cldev_disable(cldev);
266 }
267 /**
268  * mei_wd - wd client on the bus, change protocol version
269  *   as the API has changed.
270  *
271  * @cldev: me clients device
272  */
273 #if IS_ENABLED(CONFIG_INTEL_MEI_ME)
274 #include <linux/pci.h>
275 #include "hw-me-regs.h"
276 static void mei_wd(struct mei_cl_device *cldev)
277 {
278 	struct pci_dev *pdev = to_pci_dev(cldev->dev.parent);
279 
280 	if (pdev->device == MEI_DEV_ID_WPT_LP ||
281 	    pdev->device == MEI_DEV_ID_SPT ||
282 	    pdev->device == MEI_DEV_ID_SPT_H)
283 		cldev->me_cl->props.protocol_version = 0x2;
284 
285 	cldev->do_match = 1;
286 }
287 #else
288 static inline void mei_wd(struct mei_cl_device *cldev) {}
289 #endif /* CONFIG_INTEL_MEI_ME */
290 
291 struct mei_nfc_cmd {
292 	u8 command;
293 	u8 status;
294 	u16 req_id;
295 	u32 reserved;
296 	u16 data_size;
297 	u8 sub_command;
298 	u8 data[];
299 } __packed;
300 
301 struct mei_nfc_reply {
302 	u8 command;
303 	u8 status;
304 	u16 req_id;
305 	u32 reserved;
306 	u16 data_size;
307 	u8 sub_command;
308 	u8 reply_status;
309 	u8 data[];
310 } __packed;
311 
312 struct mei_nfc_if_version {
313 	u8 radio_version_sw[3];
314 	u8 reserved[3];
315 	u8 radio_version_hw[3];
316 	u8 i2c_addr;
317 	u8 fw_ivn;
318 	u8 vendor_id;
319 	u8 radio_type;
320 } __packed;
321 
322 
323 #define MEI_NFC_CMD_MAINTENANCE 0x00
324 #define MEI_NFC_SUBCMD_IF_VERSION 0x01
325 
326 /* Vendors */
327 #define MEI_NFC_VENDOR_INSIDE 0x00
328 #define MEI_NFC_VENDOR_NXP    0x01
329 
330 /* Radio types */
331 #define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
332 #define MEI_NFC_VENDOR_NXP_PN544    0x01
333 
334 /**
335  * mei_nfc_if_version - get NFC interface version
336  *
337  * @cl: host client (nfc info)
338  * @ver: NFC interface version to be filled in
339  *
340  * Return: 0 on success; < 0 otherwise
341  */
342 static int mei_nfc_if_version(struct mei_cl *cl,
343 			      struct mei_nfc_if_version *ver)
344 {
345 	struct mei_device *bus;
346 	struct mei_nfc_cmd cmd = {
347 		.command = MEI_NFC_CMD_MAINTENANCE,
348 		.data_size = 1,
349 		.sub_command = MEI_NFC_SUBCMD_IF_VERSION,
350 	};
351 	struct mei_nfc_reply *reply = NULL;
352 	size_t if_version_length;
353 	u8 vtag;
354 	int bytes_recv, ret;
355 
356 	bus = cl->dev;
357 
358 	WARN_ON(mutex_is_locked(&bus->device_lock));
359 
360 	ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(cmd), 0,
361 			    MEI_CL_IO_TX_BLOCKING);
362 	if (ret < 0) {
363 		dev_err(bus->dev, "Could not send IF version cmd\n");
364 		return ret;
365 	}
366 
367 	/* to be sure on the stack we alloc memory */
368 	if_version_length = sizeof(*reply) + sizeof(*ver);
369 
370 	reply = kzalloc(if_version_length, GFP_KERNEL);
371 	if (!reply)
372 		return -ENOMEM;
373 
374 	ret = 0;
375 	bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, &vtag,
376 				   0, 0);
377 	if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) {
378 		dev_err(bus->dev, "Could not read IF version\n");
379 		ret = -EIO;
380 		goto err;
381 	}
382 
383 	memcpy(ver, reply->data, sizeof(*ver));
384 
385 	dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
386 		ver->fw_ivn, ver->vendor_id, ver->radio_type);
387 
388 err:
389 	kfree(reply);
390 	return ret;
391 }
392 
393 /**
394  * mei_nfc_radio_name - derive nfc radio name from the interface version
395  *
396  * @ver: NFC radio version
397  *
398  * Return: radio name string
399  */
400 static const char *mei_nfc_radio_name(struct mei_nfc_if_version *ver)
401 {
402 
403 	if (ver->vendor_id == MEI_NFC_VENDOR_INSIDE) {
404 		if (ver->radio_type == MEI_NFC_VENDOR_INSIDE_UREAD)
405 			return "microread";
406 	}
407 
408 	if (ver->vendor_id == MEI_NFC_VENDOR_NXP) {
409 		if (ver->radio_type == MEI_NFC_VENDOR_NXP_PN544)
410 			return "pn544";
411 	}
412 
413 	return NULL;
414 }
415 
416 /**
417  * mei_nfc - The nfc fixup function. The function retrieves nfc radio
418  *    name and set is as device attribute so we can load
419  *    the proper device driver for it
420  *
421  * @cldev: me client device (nfc)
422  */
423 static void mei_nfc(struct mei_cl_device *cldev)
424 {
425 	struct mei_device *bus;
426 	struct mei_cl *cl;
427 	struct mei_me_client *me_cl = NULL;
428 	struct mei_nfc_if_version ver;
429 	const char *radio_name = NULL;
430 	int ret;
431 
432 	bus = cldev->bus;
433 
434 	mutex_lock(&bus->device_lock);
435 	/* we need to connect to INFO GUID */
436 	cl = mei_cl_alloc_linked(bus);
437 	if (IS_ERR(cl)) {
438 		ret = PTR_ERR(cl);
439 		cl = NULL;
440 		dev_err(bus->dev, "nfc hook alloc failed %d\n", ret);
441 		goto out;
442 	}
443 
444 	me_cl = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid);
445 	if (!me_cl) {
446 		ret = -ENOTTY;
447 		dev_err(bus->dev, "Cannot find nfc info %d\n", ret);
448 		goto out;
449 	}
450 
451 	ret = mei_cl_connect(cl, me_cl, NULL);
452 	if (ret < 0) {
453 		dev_err(&cldev->dev, "Can't connect to the NFC INFO ME ret = %d\n",
454 			ret);
455 		goto out;
456 	}
457 
458 	mutex_unlock(&bus->device_lock);
459 
460 	ret = mei_nfc_if_version(cl, &ver);
461 	if (ret)
462 		goto disconnect;
463 
464 	radio_name = mei_nfc_radio_name(&ver);
465 
466 	if (!radio_name) {
467 		ret = -ENOENT;
468 		dev_err(&cldev->dev, "Can't get the NFC interface version ret = %d\n",
469 			ret);
470 		goto disconnect;
471 	}
472 
473 	dev_dbg(bus->dev, "nfc radio %s\n", radio_name);
474 	strlcpy(cldev->name, radio_name, sizeof(cldev->name));
475 
476 disconnect:
477 	mutex_lock(&bus->device_lock);
478 	if (mei_cl_disconnect(cl) < 0)
479 		dev_err(bus->dev, "Can't disconnect the NFC INFO ME\n");
480 
481 	mei_cl_flush_queues(cl, NULL);
482 
483 out:
484 	mei_cl_unlink(cl);
485 	mutex_unlock(&bus->device_lock);
486 	mei_me_cl_put(me_cl);
487 	kfree(cl);
488 
489 	if (ret)
490 		cldev->do_match = 0;
491 
492 	dev_dbg(bus->dev, "end of fixup match = %d\n", cldev->do_match);
493 }
494 
495 /**
496  * vt_support - enable on bus clients with vtag support
497  *
498  * @cldev: me clients device
499  */
500 static void vt_support(struct mei_cl_device *cldev)
501 {
502 	if (cldev->me_cl->props.vt_supported == 1)
503 		cldev->do_match = 1;
504 }
505 
506 #define MEI_FIXUP(_uuid, _hook) { _uuid, _hook }
507 
508 static struct mei_fixup {
509 
510 	const uuid_le uuid;
511 	void (*hook)(struct mei_cl_device *cldev);
512 } mei_fixups[] = {
513 	MEI_FIXUP(MEI_UUID_ANY, number_of_connections),
514 	MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist),
515 	MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc),
516 	MEI_FIXUP(MEI_UUID_WD, mei_wd),
517 	MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix),
518 	MEI_FIXUP(MEI_UUID_IGSC_MKHI, mei_gsc_mkhi_ver),
519 	MEI_FIXUP(MEI_UUID_IGSC_MKHI_FIX, mei_gsc_mkhi_ver),
520 	MEI_FIXUP(MEI_UUID_HDCP, whitelist),
521 	MEI_FIXUP(MEI_UUID_ANY, vt_support),
522 	MEI_FIXUP(MEI_UUID_PAVP, whitelist),
523 };
524 
525 /**
526  * mei_cl_bus_dev_fixup - run fixup handlers
527  *
528  * @cldev: me client device
529  */
530 void mei_cl_bus_dev_fixup(struct mei_cl_device *cldev)
531 {
532 	struct mei_fixup *f;
533 	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
534 	size_t i;
535 
536 	for (i = 0; i < ARRAY_SIZE(mei_fixups); i++) {
537 
538 		f = &mei_fixups[i];
539 		if (uuid_le_cmp(f->uuid, MEI_UUID_ANY) == 0 ||
540 		    uuid_le_cmp(f->uuid, *uuid) == 0)
541 			f->hook(cldev);
542 	}
543 }
544 
545