18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci============================================== 48c2ecf20Sopenharmony_ciIntel(R) Management Engine (ME) Client bus API 58c2ecf20Sopenharmony_ci============================================== 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ciRationale 98c2ecf20Sopenharmony_ci========= 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ciThe MEI character device is useful for dedicated applications to send and receive 128c2ecf20Sopenharmony_cidata to the many FW appliance found in Intel's ME from the user space. 138c2ecf20Sopenharmony_ciHowever, for some of the ME functionalities it makes sense to leverage existing software 148c2ecf20Sopenharmony_cistack and expose them through existing kernel subsystems. 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciIn order to plug seamlessly into the kernel device driver model we add kernel virtual 178c2ecf20Sopenharmony_cibus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers 188c2ecf20Sopenharmony_cifor the various MEI features as a stand alone entities found in their respective subsystem. 198c2ecf20Sopenharmony_ciExisting device drivers can even potentially be re-used by adding an MEI CL bus layer to 208c2ecf20Sopenharmony_cithe existing code. 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ciMEI CL bus API 248c2ecf20Sopenharmony_ci============== 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciA driver implementation for an MEI Client is very similar to any other existing bus 278c2ecf20Sopenharmony_cibased device drivers. The driver registers itself as an MEI CL bus driver through 288c2ecf20Sopenharmony_cithe ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c` 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci.. code-block:: C 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci struct mei_cl_driver { 338c2ecf20Sopenharmony_ci struct device_driver driver; 348c2ecf20Sopenharmony_ci const char *name; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci const struct mei_cl_device_id *id_table; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id); 398c2ecf20Sopenharmony_ci int (*remove)(struct mei_cl_device *dev); 408c2ecf20Sopenharmony_ci }; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciThe mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a 458c2ecf20Sopenharmony_cidriver to bind itself against a device name. 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci.. code-block:: C 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci struct mei_cl_device_id { 508c2ecf20Sopenharmony_ci char name[MEI_CL_NAME_SIZE]; 518c2ecf20Sopenharmony_ci uuid_le uuid; 528c2ecf20Sopenharmony_ci __u8 version; 538c2ecf20Sopenharmony_ci kernel_ulong_t driver_info; 548c2ecf20Sopenharmony_ci }; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciTo actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver` 578c2ecf20Sopenharmony_ciAPI. This is typically called at module initialization time. 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciOnce the driver is registered and bound to the device, a driver will typically 608c2ecf20Sopenharmony_citry to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send` 618c2ecf20Sopenharmony_ciand :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section. 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciIn order for a driver to be notified about pending traffic or event, the driver 648c2ecf20Sopenharmony_cishould register a callback via :c:func:`mei_cl_devev_register_rx_cb` and 658c2ecf20Sopenharmony_ci:c:func:`mei_cldev_register_notify_cb` function respectively. 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci.. _api: 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciAPI: 708c2ecf20Sopenharmony_ci---- 718c2ecf20Sopenharmony_ci.. kernel-doc:: drivers/misc/mei/bus.c 728c2ecf20Sopenharmony_ci :export: drivers/misc/mei/bus.c 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciExample 778c2ecf20Sopenharmony_ci======= 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciAs a theoretical example let's pretend the ME comes with a "contact" NFC IP. 808c2ecf20Sopenharmony_ciThe driver init and exit routines for this device would look like: 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci.. code-block:: C 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci #define CONTACT_DRIVER_NAME "contact" 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci static struct mei_cl_device_id contact_mei_cl_tbl[] = { 878c2ecf20Sopenharmony_ci { CONTACT_DRIVER_NAME, }, 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* required last entry */ 908c2ecf20Sopenharmony_ci { } 918c2ecf20Sopenharmony_ci }; 928c2ecf20Sopenharmony_ci MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci static struct mei_cl_driver contact_driver = { 958c2ecf20Sopenharmony_ci .id_table = contact_mei_tbl, 968c2ecf20Sopenharmony_ci .name = CONTACT_DRIVER_NAME, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci .probe = contact_probe, 998c2ecf20Sopenharmony_ci .remove = contact_remove, 1008c2ecf20Sopenharmony_ci }; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci static int contact_init(void) 1038c2ecf20Sopenharmony_ci { 1048c2ecf20Sopenharmony_ci int r; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci r = mei_cl_driver_register(&contact_driver); 1078c2ecf20Sopenharmony_ci if (r) { 1088c2ecf20Sopenharmony_ci pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n"); 1098c2ecf20Sopenharmony_ci return r; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci static void __exit contact_exit(void) 1168c2ecf20Sopenharmony_ci { 1178c2ecf20Sopenharmony_ci mei_cl_driver_unregister(&contact_driver); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci module_init(contact_init); 1218c2ecf20Sopenharmony_ci module_exit(contact_exit); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciAnd the driver's simplified probe routine would look like that: 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci.. code-block:: C 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) 1288c2ecf20Sopenharmony_ci { 1298c2ecf20Sopenharmony_ci [...] 1308c2ecf20Sopenharmony_ci mei_cldev_enable(dev); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci mei_cldev_register_rx_cb(dev, contact_rx_cb); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciIn the probe routine the driver first enable the MEI device and then registers 1388c2ecf20Sopenharmony_cian rx handler which is as close as it can get to registering a threaded IRQ handler. 1398c2ecf20Sopenharmony_ciThe handler implementation will typically call :c:func:`mei_cldev_recv` and then 1408c2ecf20Sopenharmony_ciprocess received data. 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci.. code-block:: C 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci #define MAX_PAYLOAD 128 1458c2ecf20Sopenharmony_ci #define HDR_SIZE 4 1468c2ecf20Sopenharmony_ci static void conntact_rx_cb(struct mei_cl_device *cldev) 1478c2ecf20Sopenharmony_ci { 1488c2ecf20Sopenharmony_ci struct contact *c = mei_cldev_get_drvdata(cldev); 1498c2ecf20Sopenharmony_ci unsigned char payload[MAX_PAYLOAD]; 1508c2ecf20Sopenharmony_ci ssize_t payload_sz; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci payload_sz = mei_cldev_recv(cldev, payload, MAX_PAYLOAD) 1538c2ecf20Sopenharmony_ci if (reply_size < HDR_SIZE) { 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci c->process_rx(payload); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciMEI Client Bus Drivers 1628c2ecf20Sopenharmony_ci====================== 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci.. toctree:: 1658c2ecf20Sopenharmony_ci :maxdepth: 2 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci hdcp 1688c2ecf20Sopenharmony_ci nfc 169