Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0
0002 
0003 ==============================================
0004 Intel(R) Management Engine (ME) Client bus API
0005 ==============================================
0006 
0007 
0008 Rationale
0009 =========
0010 
0011 The MEI character device is useful for dedicated applications to send and receive
0012 data to the many FW appliance found in Intel's ME from the user space.
0013 However, for some of the ME functionalities it makes sense to leverage existing software
0014 stack and expose them through existing kernel subsystems.
0015 
0016 In order to plug seamlessly into the kernel device driver model we add kernel virtual
0017 bus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers
0018 for the various MEI features as a stand alone entities found in their respective subsystem.
0019 Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
0020 the existing code.
0021 
0022 
0023 MEI CL bus API
0024 ==============
0025 
0026 A driver implementation for an MEI Client is very similar to any other existing bus
0027 based device drivers. The driver registers itself as an MEI CL bus driver through
0028 the ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c`
0029 
0030 .. code-block:: C
0031 
0032         struct mei_cl_driver {
0033                 struct device_driver driver;
0034                 const char *name;
0035 
0036                 const struct mei_cl_device_id *id_table;
0037 
0038                 int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
0039                 int (*remove)(struct mei_cl_device *dev);
0040         };
0041 
0042 
0043 
0044 The mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a
0045 driver to bind itself against a device name.
0046 
0047 .. code-block:: C
0048 
0049         struct mei_cl_device_id {
0050                 char name[MEI_CL_NAME_SIZE];
0051                 uuid_le uuid;
0052                 __u8    version;
0053                 kernel_ulong_t driver_info;
0054         };
0055 
0056 To actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver`
0057 API. This is typically called at module initialization time.
0058 
0059 Once the driver is registered and bound to the device, a driver will typically
0060 try to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send`
0061 and :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section.
0062 
0063 In order for a driver to be notified about pending traffic or event, the driver
0064 should register a callback via :c:func:`mei_cl_devev_register_rx_cb` and
0065 :c:func:`mei_cldev_register_notify_cb` function respectively.
0066 
0067 .. _api:
0068 
0069 API:
0070 ----
0071 .. kernel-doc:: drivers/misc/mei/bus.c
0072     :export: drivers/misc/mei/bus.c
0073 
0074 
0075 
0076 Example
0077 =======
0078 
0079 As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
0080 The driver init and exit routines for this device would look like:
0081 
0082 .. code-block:: C
0083 
0084         #define CONTACT_DRIVER_NAME "contact"
0085 
0086         static struct mei_cl_device_id contact_mei_cl_tbl[] = {
0087                 { CONTACT_DRIVER_NAME, },
0088 
0089                 /* required last entry */
0090                 { }
0091         };
0092         MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
0093 
0094         static struct mei_cl_driver contact_driver = {
0095                 .id_table = contact_mei_tbl,
0096                 .name = CONTACT_DRIVER_NAME,
0097 
0098                 .probe = contact_probe,
0099                 .remove = contact_remove,
0100         };
0101 
0102         static int contact_init(void)
0103         {
0104                 int r;
0105 
0106                 r = mei_cl_driver_register(&contact_driver);
0107                 if (r) {
0108                         pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
0109                         return r;
0110                 }
0111 
0112                 return 0;
0113         }
0114 
0115         static void __exit contact_exit(void)
0116         {
0117                 mei_cl_driver_unregister(&contact_driver);
0118         }
0119 
0120         module_init(contact_init);
0121         module_exit(contact_exit);
0122 
0123 And the driver's simplified probe routine would look like that:
0124 
0125 .. code-block:: C
0126 
0127         int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
0128         {
0129                 [...]
0130                 mei_cldev_enable(dev);
0131 
0132                 mei_cldev_register_rx_cb(dev, contact_rx_cb);
0133 
0134                 return 0;
0135         }
0136 
0137 In the probe routine the driver first enable the MEI device and then registers
0138 an rx handler which is as close as it can get to registering a threaded IRQ handler.
0139 The handler implementation will typically call :c:func:`mei_cldev_recv` and then
0140 process received data.
0141 
0142 .. code-block:: C
0143 
0144         #define MAX_PAYLOAD 128
0145         #define HDR_SIZE 4
0146         static void conntact_rx_cb(struct mei_cl_device *cldev)
0147         {
0148                 struct contact *c = mei_cldev_get_drvdata(cldev);
0149                 unsigned char payload[MAX_PAYLOAD];
0150                 ssize_t payload_sz;
0151 
0152                 payload_sz = mei_cldev_recv(cldev, payload,  MAX_PAYLOAD)
0153                 if (reply_size < HDR_SIZE) {
0154                         return;
0155                 }
0156 
0157                 c->process_rx(payload);
0158 
0159         }
0160 
0161 MEI Client Bus Drivers
0162 ======================
0163 
0164 .. toctree::
0165    :maxdepth: 2
0166 
0167    hdcp
0168    nfc