xref: /openbmc/linux/Documentation/driver-api/mei/mei-client-bus.rst (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
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