17e527e11STomas Winkler.. SPDX-License-Identifier: GPL-2.0 27e527e11STomas Winkler 37e527e11STomas Winkler============================================== 47e527e11STomas WinklerIntel(R) Management Engine (ME) Client bus API 57e527e11STomas Winkler============================================== 67e527e11STomas Winkler 77e527e11STomas Winkler 87e527e11STomas WinklerRationale 97e527e11STomas Winkler========= 107e527e11STomas Winkler 116080e0cfSTomas WinklerThe MEI character device is useful for dedicated applications to send and receive 127e527e11STomas Winklerdata to the many FW appliance found in Intel's ME from the user space. 136080e0cfSTomas WinklerHowever, for some of the ME functionalities it makes sense to leverage existing software 147e527e11STomas Winklerstack and expose them through existing kernel subsystems. 157e527e11STomas Winkler 167e527e11STomas WinklerIn order to plug seamlessly into the kernel device driver model we add kernel virtual 176080e0cfSTomas Winklerbus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers 187e527e11STomas Winklerfor the various MEI features as a stand alone entities found in their respective subsystem. 197e527e11STomas WinklerExisting device drivers can even potentially be re-used by adding an MEI CL bus layer to 207e527e11STomas Winklerthe existing code. 217e527e11STomas Winkler 227e527e11STomas Winkler 237e527e11STomas WinklerMEI CL bus API 247e527e11STomas Winkler============== 257e527e11STomas Winkler 266080e0cfSTomas WinklerA driver implementation for an MEI Client is very similar to any other existing bus 277e527e11STomas Winklerbased device drivers. The driver registers itself as an MEI CL bus driver through 286080e0cfSTomas Winklerthe ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c` 297e527e11STomas Winkler 307e527e11STomas Winkler.. code-block:: C 317e527e11STomas Winkler 327e527e11STomas Winkler struct mei_cl_driver { 337e527e11STomas Winkler struct device_driver driver; 347e527e11STomas Winkler const char *name; 357e527e11STomas Winkler 367e527e11STomas Winkler const struct mei_cl_device_id *id_table; 377e527e11STomas Winkler 387e527e11STomas Winkler int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id); 397e527e11STomas Winkler int (*remove)(struct mei_cl_device *dev); 407e527e11STomas Winkler }; 417e527e11STomas Winkler 426080e0cfSTomas Winkler 436080e0cfSTomas Winkler 446080e0cfSTomas WinklerThe mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a 456080e0cfSTomas Winklerdriver to bind itself against a device name. 466080e0cfSTomas Winkler 476080e0cfSTomas Winkler.. code-block:: C 486080e0cfSTomas Winkler 496080e0cfSTomas Winkler struct mei_cl_device_id { 506080e0cfSTomas Winkler char name[MEI_CL_NAME_SIZE]; 516080e0cfSTomas Winkler uuid_le uuid; 526080e0cfSTomas Winkler __u8 version; 537e527e11STomas Winkler kernel_ulong_t driver_info; 547e527e11STomas Winkler }; 557e527e11STomas Winkler 566080e0cfSTomas WinklerTo actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver` 576080e0cfSTomas WinklerAPI. This is typically called at module initialization time. 587e527e11STomas Winkler 596080e0cfSTomas WinklerOnce the driver is registered and bound to the device, a driver will typically 606080e0cfSTomas Winklertry to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send` 616080e0cfSTomas Winklerand :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section. 627e527e11STomas Winkler 636080e0cfSTomas WinklerIn order for a driver to be notified about pending traffic or event, the driver 646080e0cfSTomas Winklershould register a callback via :c:func:`mei_cl_devev_register_rx_cb` and 656080e0cfSTomas Winkler:c:func:`mei_cldev_register_notify_cb` function respectively. 666080e0cfSTomas Winkler 676080e0cfSTomas Winkler.. _api: 686080e0cfSTomas Winkler 696080e0cfSTomas WinklerAPI: 706080e0cfSTomas Winkler---- 716080e0cfSTomas Winkler.. kernel-doc:: drivers/misc/mei/bus.c 726080e0cfSTomas Winkler :export: drivers/misc/mei/bus.c 736080e0cfSTomas Winkler 747e527e11STomas Winkler 757e527e11STomas Winkler 767e527e11STomas WinklerExample 777e527e11STomas Winkler======= 787e527e11STomas Winkler 797e527e11STomas WinklerAs a theoretical example let's pretend the ME comes with a "contact" NFC IP. 807e527e11STomas WinklerThe driver init and exit routines for this device would look like: 817e527e11STomas Winkler 827e527e11STomas Winkler.. code-block:: C 837e527e11STomas Winkler 847e527e11STomas Winkler #define CONTACT_DRIVER_NAME "contact" 857e527e11STomas Winkler 867e527e11STomas Winkler static struct mei_cl_device_id contact_mei_cl_tbl[] = { 877e527e11STomas Winkler { CONTACT_DRIVER_NAME, }, 887e527e11STomas Winkler 897e527e11STomas Winkler /* required last entry */ 907e527e11STomas Winkler { } 917e527e11STomas Winkler }; 927e527e11STomas Winkler MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); 937e527e11STomas Winkler 947e527e11STomas Winkler static struct mei_cl_driver contact_driver = { 957e527e11STomas Winkler .id_table = contact_mei_tbl, 967e527e11STomas Winkler .name = CONTACT_DRIVER_NAME, 977e527e11STomas Winkler 987e527e11STomas Winkler .probe = contact_probe, 997e527e11STomas Winkler .remove = contact_remove, 1007e527e11STomas Winkler }; 1017e527e11STomas Winkler 1027e527e11STomas Winkler static int contact_init(void) 1037e527e11STomas Winkler { 1047e527e11STomas Winkler int r; 1057e527e11STomas Winkler 1067e527e11STomas Winkler r = mei_cl_driver_register(&contact_driver); 1077e527e11STomas Winkler if (r) { 1087e527e11STomas Winkler pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n"); 1097e527e11STomas Winkler return r; 1107e527e11STomas Winkler } 1117e527e11STomas Winkler 1127e527e11STomas Winkler return 0; 1137e527e11STomas Winkler } 1147e527e11STomas Winkler 1157e527e11STomas Winkler static void __exit contact_exit(void) 1167e527e11STomas Winkler { 1177e527e11STomas Winkler mei_cl_driver_unregister(&contact_driver); 1187e527e11STomas Winkler } 1197e527e11STomas Winkler 1207e527e11STomas Winkler module_init(contact_init); 1217e527e11STomas Winkler module_exit(contact_exit); 1227e527e11STomas Winkler 1237e527e11STomas WinklerAnd the driver's simplified probe routine would look like that: 1247e527e11STomas Winkler 1257e527e11STomas Winkler.. code-block:: C 1267e527e11STomas Winkler 1277e527e11STomas Winkler int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) 1287e527e11STomas Winkler { 1297e527e11STomas Winkler [...] 1306080e0cfSTomas Winkler mei_cldev_enable(dev); 1317e527e11STomas Winkler 1326080e0cfSTomas Winkler mei_cldev_register_rx_cb(dev, contact_rx_cb); 1337e527e11STomas Winkler 1347e527e11STomas Winkler return 0; 1357e527e11STomas Winkler } 1367e527e11STomas Winkler 1377e527e11STomas WinklerIn the probe routine the driver first enable the MEI device and then registers 1386080e0cfSTomas Winkleran rx handler which is as close as it can get to registering a threaded IRQ handler. 1396080e0cfSTomas WinklerThe handler implementation will typically call :c:func:`mei_cldev_recv` and then 1406080e0cfSTomas Winklerprocess received data. 1417e527e11STomas Winkler 1427e527e11STomas Winkler.. code-block:: C 1437e527e11STomas Winkler 1446080e0cfSTomas Winkler #define MAX_PAYLOAD 128 1456080e0cfSTomas Winkler #define HDR_SIZE 4 1466080e0cfSTomas Winkler static void conntact_rx_cb(struct mei_cl_device *cldev) 1477e527e11STomas Winkler { 1486080e0cfSTomas Winkler struct contact *c = mei_cldev_get_drvdata(cldev); 1496080e0cfSTomas Winkler unsigned char payload[MAX_PAYLOAD]; 1506080e0cfSTomas Winkler ssize_t payload_sz; 1517e527e11STomas Winkler 1526080e0cfSTomas Winkler payload_sz = mei_cldev_recv(cldev, payload, MAX_PAYLOAD) 1536080e0cfSTomas Winkler if (reply_size < HDR_SIZE) { 1547e527e11STomas Winkler return; 1556080e0cfSTomas Winkler } 1567e527e11STomas Winkler 1576080e0cfSTomas Winkler c->process_rx(payload); 1586080e0cfSTomas Winkler 1597e527e11STomas Winkler } 1606080e0cfSTomas Winkler 1614e3d3b78STomas WinklerMEI Client Bus Drivers 1624e3d3b78STomas Winkler====================== 1634e3d3b78STomas Winkler 1644e3d3b78STomas Winkler.. toctree:: 1654e3d3b78STomas Winkler :maxdepth: 2 1664e3d3b78STomas Winkler 167*0475afd2STomas Winkler hdcp 1684e3d3b78STomas Winkler nfc 169