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