162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci============================================== 462306a36Sopenharmony_ciIntel(R) Management Engine (ME) Client bus API 562306a36Sopenharmony_ci============================================== 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciRationale 962306a36Sopenharmony_ci========= 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciThe MEI character device is useful for dedicated applications to send and receive 1262306a36Sopenharmony_cidata to the many FW appliance found in Intel's ME from the user space. 1362306a36Sopenharmony_ciHowever, for some of the ME functionalities it makes sense to leverage existing software 1462306a36Sopenharmony_cistack and expose them through existing kernel subsystems. 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciIn order to plug seamlessly into the kernel device driver model we add kernel virtual 1762306a36Sopenharmony_cibus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers 1862306a36Sopenharmony_cifor the various MEI features as a stand alone entities found in their respective subsystem. 1962306a36Sopenharmony_ciExisting device drivers can even potentially be re-used by adding an MEI CL bus layer to 2062306a36Sopenharmony_cithe existing code. 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciMEI CL bus API 2462306a36Sopenharmony_ci============== 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciA driver implementation for an MEI Client is very similar to any other existing bus 2762306a36Sopenharmony_cibased device drivers. The driver registers itself as an MEI CL bus driver through 2862306a36Sopenharmony_cithe ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c` 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci.. code-block:: C 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci struct mei_cl_driver { 3362306a36Sopenharmony_ci struct device_driver driver; 3462306a36Sopenharmony_ci const char *name; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci const struct mei_cl_device_id *id_table; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id); 3962306a36Sopenharmony_ci int (*remove)(struct mei_cl_device *dev); 4062306a36Sopenharmony_ci }; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciThe mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a 4562306a36Sopenharmony_cidriver to bind itself against a device name. 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci.. code-block:: C 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci struct mei_cl_device_id { 5062306a36Sopenharmony_ci char name[MEI_CL_NAME_SIZE]; 5162306a36Sopenharmony_ci uuid_le uuid; 5262306a36Sopenharmony_ci __u8 version; 5362306a36Sopenharmony_ci kernel_ulong_t driver_info; 5462306a36Sopenharmony_ci }; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciTo actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver` 5762306a36Sopenharmony_ciAPI. This is typically called at module initialization time. 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciOnce the driver is registered and bound to the device, a driver will typically 6062306a36Sopenharmony_citry to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send` 6162306a36Sopenharmony_ciand :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section. 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciIn order for a driver to be notified about pending traffic or event, the driver 6462306a36Sopenharmony_cishould register a callback via :c:func:`mei_cl_devev_register_rx_cb` and 6562306a36Sopenharmony_ci:c:func:`mei_cldev_register_notify_cb` function respectively. 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci.. _api: 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciAPI: 7062306a36Sopenharmony_ci---- 7162306a36Sopenharmony_ci.. kernel-doc:: drivers/misc/mei/bus.c 7262306a36Sopenharmony_ci :export: drivers/misc/mei/bus.c 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciExample 7762306a36Sopenharmony_ci======= 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciAs a theoretical example let's pretend the ME comes with a "contact" NFC IP. 8062306a36Sopenharmony_ciThe driver init and exit routines for this device would look like: 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci.. code-block:: C 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci #define CONTACT_DRIVER_NAME "contact" 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci static struct mei_cl_device_id contact_mei_cl_tbl[] = { 8762306a36Sopenharmony_ci { CONTACT_DRIVER_NAME, }, 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* required last entry */ 9062306a36Sopenharmony_ci { } 9162306a36Sopenharmony_ci }; 9262306a36Sopenharmony_ci MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci static struct mei_cl_driver contact_driver = { 9562306a36Sopenharmony_ci .id_table = contact_mei_tbl, 9662306a36Sopenharmony_ci .name = CONTACT_DRIVER_NAME, 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci .probe = contact_probe, 9962306a36Sopenharmony_ci .remove = contact_remove, 10062306a36Sopenharmony_ci }; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci static int contact_init(void) 10362306a36Sopenharmony_ci { 10462306a36Sopenharmony_ci int r; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci r = mei_cl_driver_register(&contact_driver); 10762306a36Sopenharmony_ci if (r) { 10862306a36Sopenharmony_ci pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n"); 10962306a36Sopenharmony_ci return r; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci static void __exit contact_exit(void) 11662306a36Sopenharmony_ci { 11762306a36Sopenharmony_ci mei_cl_driver_unregister(&contact_driver); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci module_init(contact_init); 12162306a36Sopenharmony_ci module_exit(contact_exit); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciAnd the driver's simplified probe routine would look like that: 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci.. code-block:: C 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) 12862306a36Sopenharmony_ci { 12962306a36Sopenharmony_ci [...] 13062306a36Sopenharmony_ci mei_cldev_enable(dev); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci mei_cldev_register_rx_cb(dev, contact_rx_cb); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciIn the probe routine the driver first enable the MEI device and then registers 13862306a36Sopenharmony_cian rx handler which is as close as it can get to registering a threaded IRQ handler. 13962306a36Sopenharmony_ciThe handler implementation will typically call :c:func:`mei_cldev_recv` and then 14062306a36Sopenharmony_ciprocess received data. 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci.. code-block:: C 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci #define MAX_PAYLOAD 128 14562306a36Sopenharmony_ci #define HDR_SIZE 4 14662306a36Sopenharmony_ci static void conntact_rx_cb(struct mei_cl_device *cldev) 14762306a36Sopenharmony_ci { 14862306a36Sopenharmony_ci struct contact *c = mei_cldev_get_drvdata(cldev); 14962306a36Sopenharmony_ci unsigned char payload[MAX_PAYLOAD]; 15062306a36Sopenharmony_ci ssize_t payload_sz; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci payload_sz = mei_cldev_recv(cldev, payload, MAX_PAYLOAD) 15362306a36Sopenharmony_ci if (reply_size < HDR_SIZE) { 15462306a36Sopenharmony_ci return; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci c->process_rx(payload); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciMEI Client Bus Drivers 16262306a36Sopenharmony_ci====================== 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci.. toctree:: 16562306a36Sopenharmony_ci :maxdepth: 2 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci hdcp 16862306a36Sopenharmony_ci nfc 169