xref: /OK3568_Linux_fs/kernel/Documentation/driver-api/mei/mei-client-bus.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun==============================================
4*4882a593SmuzhiyunIntel(R) Management Engine (ME) Client bus API
5*4882a593Smuzhiyun==============================================
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun
8*4882a593SmuzhiyunRationale
9*4882a593Smuzhiyun=========
10*4882a593Smuzhiyun
11*4882a593SmuzhiyunThe MEI character device is useful for dedicated applications to send and receive
12*4882a593Smuzhiyundata to the many FW appliance found in Intel's ME from the user space.
13*4882a593SmuzhiyunHowever, for some of the ME functionalities it makes sense to leverage existing software
14*4882a593Smuzhiyunstack and expose them through existing kernel subsystems.
15*4882a593Smuzhiyun
16*4882a593SmuzhiyunIn order to plug seamlessly into the kernel device driver model we add kernel virtual
17*4882a593Smuzhiyunbus abstraction on top of the MEI driver. This allows implementing Linux kernel drivers
18*4882a593Smuzhiyunfor the various MEI features as a stand alone entities found in their respective subsystem.
19*4882a593SmuzhiyunExisting device drivers can even potentially be re-used by adding an MEI CL bus layer to
20*4882a593Smuzhiyunthe existing code.
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun
23*4882a593SmuzhiyunMEI CL bus API
24*4882a593Smuzhiyun==============
25*4882a593Smuzhiyun
26*4882a593SmuzhiyunA driver implementation for an MEI Client is very similar to any other existing bus
27*4882a593Smuzhiyunbased device drivers. The driver registers itself as an MEI CL bus driver through
28*4882a593Smuzhiyunthe ``struct mei_cl_driver`` structure defined in :file:`include/linux/mei_cl_bus.c`
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun.. code-block:: C
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun        struct mei_cl_driver {
33*4882a593Smuzhiyun                struct device_driver driver;
34*4882a593Smuzhiyun                const char *name;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun                const struct mei_cl_device_id *id_table;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun                int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
39*4882a593Smuzhiyun                int (*remove)(struct mei_cl_device *dev);
40*4882a593Smuzhiyun        };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun
44*4882a593SmuzhiyunThe mei_cl_device_id structure defined in :file:`include/linux/mod_devicetable.h` allows a
45*4882a593Smuzhiyundriver to bind itself against a device name.
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun.. code-block:: C
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun        struct mei_cl_device_id {
50*4882a593Smuzhiyun                char name[MEI_CL_NAME_SIZE];
51*4882a593Smuzhiyun                uuid_le uuid;
52*4882a593Smuzhiyun                __u8    version;
53*4882a593Smuzhiyun                kernel_ulong_t driver_info;
54*4882a593Smuzhiyun        };
55*4882a593Smuzhiyun
56*4882a593SmuzhiyunTo actually register a driver on the ME Client bus one must call the :c:func:`mei_cl_add_driver`
57*4882a593SmuzhiyunAPI. This is typically called at module initialization time.
58*4882a593Smuzhiyun
59*4882a593SmuzhiyunOnce the driver is registered and bound to the device, a driver will typically
60*4882a593Smuzhiyuntry to do some I/O on this bus and this should be done through the :c:func:`mei_cl_send`
61*4882a593Smuzhiyunand :c:func:`mei_cl_recv` functions. More detailed information is in :ref:`api` section.
62*4882a593Smuzhiyun
63*4882a593SmuzhiyunIn order for a driver to be notified about pending traffic or event, the driver
64*4882a593Smuzhiyunshould register a callback via :c:func:`mei_cl_devev_register_rx_cb` and
65*4882a593Smuzhiyun:c:func:`mei_cldev_register_notify_cb` function respectively.
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun.. _api:
68*4882a593Smuzhiyun
69*4882a593SmuzhiyunAPI:
70*4882a593Smuzhiyun----
71*4882a593Smuzhiyun.. kernel-doc:: drivers/misc/mei/bus.c
72*4882a593Smuzhiyun    :export: drivers/misc/mei/bus.c
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun
76*4882a593SmuzhiyunExample
77*4882a593Smuzhiyun=======
78*4882a593Smuzhiyun
79*4882a593SmuzhiyunAs a theoretical example let's pretend the ME comes with a "contact" NFC IP.
80*4882a593SmuzhiyunThe driver init and exit routines for this device would look like:
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun.. code-block:: C
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun        #define CONTACT_DRIVER_NAME "contact"
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun        static struct mei_cl_device_id contact_mei_cl_tbl[] = {
87*4882a593Smuzhiyun                { CONTACT_DRIVER_NAME, },
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun                /* required last entry */
90*4882a593Smuzhiyun                { }
91*4882a593Smuzhiyun        };
92*4882a593Smuzhiyun        MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun        static struct mei_cl_driver contact_driver = {
95*4882a593Smuzhiyun                .id_table = contact_mei_tbl,
96*4882a593Smuzhiyun                .name = CONTACT_DRIVER_NAME,
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun                .probe = contact_probe,
99*4882a593Smuzhiyun                .remove = contact_remove,
100*4882a593Smuzhiyun        };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun        static int contact_init(void)
103*4882a593Smuzhiyun        {
104*4882a593Smuzhiyun                int r;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun                r = mei_cl_driver_register(&contact_driver);
107*4882a593Smuzhiyun                if (r) {
108*4882a593Smuzhiyun                        pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
109*4882a593Smuzhiyun                        return r;
110*4882a593Smuzhiyun                }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun                return 0;
113*4882a593Smuzhiyun        }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun        static void __exit contact_exit(void)
116*4882a593Smuzhiyun        {
117*4882a593Smuzhiyun                mei_cl_driver_unregister(&contact_driver);
118*4882a593Smuzhiyun        }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun        module_init(contact_init);
121*4882a593Smuzhiyun        module_exit(contact_exit);
122*4882a593Smuzhiyun
123*4882a593SmuzhiyunAnd the driver's simplified probe routine would look like that:
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun.. code-block:: C
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun        int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
128*4882a593Smuzhiyun        {
129*4882a593Smuzhiyun                [...]
130*4882a593Smuzhiyun                mei_cldev_enable(dev);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun                mei_cldev_register_rx_cb(dev, contact_rx_cb);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun                return 0;
135*4882a593Smuzhiyun        }
136*4882a593Smuzhiyun
137*4882a593SmuzhiyunIn the probe routine the driver first enable the MEI device and then registers
138*4882a593Smuzhiyunan rx handler which is as close as it can get to registering a threaded IRQ handler.
139*4882a593SmuzhiyunThe handler implementation will typically call :c:func:`mei_cldev_recv` and then
140*4882a593Smuzhiyunprocess received data.
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun.. code-block:: C
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun        #define MAX_PAYLOAD 128
145*4882a593Smuzhiyun        #define HDR_SIZE 4
146*4882a593Smuzhiyun        static void conntact_rx_cb(struct mei_cl_device *cldev)
147*4882a593Smuzhiyun        {
148*4882a593Smuzhiyun                struct contact *c = mei_cldev_get_drvdata(cldev);
149*4882a593Smuzhiyun                unsigned char payload[MAX_PAYLOAD];
150*4882a593Smuzhiyun                ssize_t payload_sz;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun                payload_sz = mei_cldev_recv(cldev, payload,  MAX_PAYLOAD)
153*4882a593Smuzhiyun                if (reply_size < HDR_SIZE) {
154*4882a593Smuzhiyun                        return;
155*4882a593Smuzhiyun                }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun                c->process_rx(payload);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun        }
160*4882a593Smuzhiyun
161*4882a593SmuzhiyunMEI Client Bus Drivers
162*4882a593Smuzhiyun======================
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun.. toctree::
165*4882a593Smuzhiyun   :maxdepth: 2
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun   hdcp
168*4882a593Smuzhiyun   nfc
169