Commit e46980a10a76ec3282dd6832c1974b880acd23d3
Committed by
Greg Kroah-Hartman
1 parent
d6c36a475f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mei: bus: Add device enabling and disabling API
It should be left to the drivers to enable and disable the device on the MEI bus when e.g getting probed. For drivers to be able to safely call the enable and disable hooks, the mei_cl_ops must be set before it's probed and thus this should happen before registering the device on the MEI bus. Hence the mei_cl_add_device() prototype change. Signed-off-by: Samuel Ortiz <sameo@linux.intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 4 changed files with 123 additions and 14 deletions Inline Diff
Documentation/misc-devices/mei/mei-client-bus.txt
1 | Intel(R) Management Engine (ME) Client bus API | 1 | Intel(R) Management Engine (ME) Client bus API |
2 | =============================================== | 2 | =============================================== |
3 | 3 | ||
4 | 4 | ||
5 | Rationale | 5 | Rationale |
6 | ========= | 6 | ========= |
7 | MEI misc character device is useful for dedicated applications to send and receive | 7 | MEI misc character device is useful for dedicated applications to send and receive |
8 | data to the many FW appliance found in Intel's ME from the user space. | 8 | data to the many FW appliance found in Intel's ME from the user space. |
9 | However for some of the ME functionalities it make sense to leverage existing software | 9 | However for some of the ME functionalities it make sense to leverage existing software |
10 | stack and expose them through existing kernel subsystems. | 10 | stack and expose them through existing kernel subsystems. |
11 | 11 | ||
12 | In order to plug seamlessly into the kernel device driver model we add kernel virtual | 12 | In order to plug seamlessly into the kernel device driver model we add kernel virtual |
13 | bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers | 13 | bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers |
14 | for the various MEI features as a stand alone entities found in their respective subsystem. | 14 | for the various MEI features as a stand alone entities found in their respective subsystem. |
15 | Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to | 15 | Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to |
16 | the existing code. | 16 | the existing code. |
17 | 17 | ||
18 | 18 | ||
19 | MEI CL bus API | 19 | MEI CL bus API |
20 | =========== | 20 | =========== |
21 | A driver implementation for an MEI Client is very similar to existing bus | 21 | A driver implementation for an MEI Client is very similar to existing bus |
22 | based device drivers. The driver registers itself as an MEI CL bus driver through | 22 | based device drivers. The driver registers itself as an MEI CL bus driver through |
23 | the mei_cl_driver structure: | 23 | the mei_cl_driver structure: |
24 | 24 | ||
25 | struct mei_cl_driver { | 25 | struct mei_cl_driver { |
26 | struct device_driver driver; | 26 | struct device_driver driver; |
27 | const char *name; | 27 | const char *name; |
28 | 28 | ||
29 | const struct mei_cl_device_id *id_table; | 29 | const struct mei_cl_device_id *id_table; |
30 | 30 | ||
31 | int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id); | 31 | int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id); |
32 | int (*remove)(struct mei_cl_device *dev); | 32 | int (*remove)(struct mei_cl_device *dev); |
33 | }; | 33 | }; |
34 | 34 | ||
35 | struct mei_cl_id { | 35 | struct mei_cl_id { |
36 | char name[MEI_NAME_SIZE]; | 36 | char name[MEI_NAME_SIZE]; |
37 | kernel_ulong_t driver_info; | 37 | kernel_ulong_t driver_info; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | The mei_cl_id structure allows the driver to bind itself against a device name. | 40 | The mei_cl_id structure allows the driver to bind itself against a device name. |
41 | 41 | ||
42 | To actually register a driver on the ME Client bus one must call the mei_cl_add_driver() | 42 | To actually register a driver on the ME Client bus one must call the mei_cl_add_driver() |
43 | API. This is typically called at module init time. | 43 | API. This is typically called at module init time. |
44 | 44 | ||
45 | Once registered on the ME Client bus, a driver will typically try to do some I/O on | 45 | Once registered on the ME Client bus, a driver will typically try to do some I/O on |
46 | this bus and this should be done through the mei_cl_send() and mei_cl_recv() | 46 | this bus and this should be done through the mei_cl_send() and mei_cl_recv() |
47 | routines. The latter is synchronous (blocks and sleeps until data shows up). | 47 | routines. The latter is synchronous (blocks and sleeps until data shows up). |
48 | In order for drivers to be notified of pending events waiting for them (e.g. | 48 | In order for drivers to be notified of pending events waiting for them (e.g. |
49 | an Rx event) they can register an event handler through the | 49 | an Rx event) they can register an event handler through the |
50 | mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event | 50 | mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event |
51 | will trigger an event handler call and the driver implementation is supposed | 51 | will trigger an event handler call and the driver implementation is supposed |
52 | to call mei_recv() from the event handler in order to fetch the pending | 52 | to call mei_recv() from the event handler in order to fetch the pending |
53 | received buffers. | 53 | received buffers. |
54 | 54 | ||
55 | 55 | ||
56 | Example | 56 | Example |
57 | ======= | 57 | ======= |
58 | As a theoretical example let's pretend the ME comes with a "contact" NFC IP. | 58 | As a theoretical example let's pretend the ME comes with a "contact" NFC IP. |
59 | The driver init and exit routines for this device would look like: | 59 | The driver init and exit routines for this device would look like: |
60 | 60 | ||
61 | #define CONTACT_DRIVER_NAME "contact" | 61 | #define CONTACT_DRIVER_NAME "contact" |
62 | 62 | ||
63 | static struct mei_cl_device_id contact_mei_cl_tbl[] = { | 63 | static struct mei_cl_device_id contact_mei_cl_tbl[] = { |
64 | { CONTACT_DRIVER_NAME, }, | 64 | { CONTACT_DRIVER_NAME, }, |
65 | 65 | ||
66 | /* required last entry */ | 66 | /* required last entry */ |
67 | { } | 67 | { } |
68 | }; | 68 | }; |
69 | MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); | 69 | MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl); |
70 | 70 | ||
71 | static struct mei_cl_driver contact_driver = { | 71 | static struct mei_cl_driver contact_driver = { |
72 | .id_table = contact_mei_tbl, | 72 | .id_table = contact_mei_tbl, |
73 | .name = CONTACT_DRIVER_NAME, | 73 | .name = CONTACT_DRIVER_NAME, |
74 | 74 | ||
75 | .probe = contact_probe, | 75 | .probe = contact_probe, |
76 | .remove = contact_remove, | 76 | .remove = contact_remove, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static int contact_init(void) | 79 | static int contact_init(void) |
80 | { | 80 | { |
81 | int r; | 81 | int r; |
82 | 82 | ||
83 | r = mei_cl_driver_register(&contact_driver); | 83 | r = mei_cl_driver_register(&contact_driver); |
84 | if (r) { | 84 | if (r) { |
85 | pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n"); | 85 | pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n"); |
86 | return r; | 86 | return r; |
87 | } | 87 | } |
88 | 88 | ||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | static void __exit contact_exit(void) | 92 | static void __exit contact_exit(void) |
93 | { | 93 | { |
94 | mei_cl_driver_unregister(&contact_driver); | 94 | mei_cl_driver_unregister(&contact_driver); |
95 | } | 95 | } |
96 | 96 | ||
97 | module_init(contact_init); | 97 | module_init(contact_init); |
98 | module_exit(contact_exit); | 98 | module_exit(contact_exit); |
99 | 99 | ||
100 | And the driver's simplified probe routine would look like that: | 100 | And the driver's simplified probe routine would look like that: |
101 | 101 | ||
102 | int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) | 102 | int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id) |
103 | { | 103 | { |
104 | struct contact_driver *contact; | 104 | struct contact_driver *contact; |
105 | 105 | ||
106 | [...] | 106 | [...] |
107 | mei_cl_enable_device(dev); | ||
108 | |||
107 | mei_cl_register_event_cb(dev, contact_event_cb, contact); | 109 | mei_cl_register_event_cb(dev, contact_event_cb, contact); |
108 | 110 | ||
109 | return 0; | 111 | return 0; |
110 | } | 112 | } |
111 | 113 | ||
112 | In the probe routine the driver basically registers an ME bus event handler | 114 | In the probe routine the driver first enable the MEI device and then registers |
113 | which is as close as it can get to registering a threaded IRQ handler. | 115 | an ME bus event handler which is as close as it can get to registering a |
116 | threaded IRQ handler. | ||
114 | The handler implementation will typically call some I/O routine depending on | 117 | The handler implementation will typically call some I/O routine depending on |
115 | the pending events: | 118 | the pending events: |
116 | 119 | ||
117 | #define MAX_NFC_PAYLOAD 128 | 120 | #define MAX_NFC_PAYLOAD 128 |
118 | 121 | ||
119 | static void contact_event_cb(struct mei_cl_device *dev, u32 events, | 122 | static void contact_event_cb(struct mei_cl_device *dev, u32 events, |
120 | void *context) | 123 | void *context) |
121 | { | 124 | { |
122 | struct contact_driver *contact = context; | 125 | struct contact_driver *contact = context; |
123 | 126 | ||
124 | if (events & BIT(MEI_EVENT_RX)) { | 127 | if (events & BIT(MEI_EVENT_RX)) { |
125 | u8 payload[MAX_NFC_PAYLOAD]; | 128 | u8 payload[MAX_NFC_PAYLOAD]; |
126 | int payload_size; | 129 | int payload_size; |
127 | 130 | ||
128 | payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD); | 131 | payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD); |
129 | if (payload_size <= 0) | 132 | if (payload_size <= 0) |
130 | return; | 133 | return; |
131 | 134 | ||
132 | /* Hook to the NFC subsystem */ | 135 | /* Hook to the NFC subsystem */ |
133 | nfc_hci_recv_frame(contact->hdev, payload, payload_size); | 136 | nfc_hci_recv_frame(contact->hdev, payload, payload_size); |
134 | } | 137 | } |
135 | } | 138 | } |
136 | 139 |
drivers/misc/mei/bus.c
1 | /* | 1 | /* |
2 | * Intel Management Engine Interface (Intel MEI) Linux driver | 2 | * Intel Management Engine Interface (Intel MEI) Linux driver |
3 | * Copyright (c) 2012-2013, Intel Corporation. | 3 | * Copyright (c) 2012-2013, Intel Corporation. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms and conditions of the GNU General Public License, | 6 | * under the terms and conditions of the GNU General Public License, |
7 | * version 2, as published by the Free Software Foundation. | 7 | * version 2, as published by the Free Software Foundation. |
8 | * | 8 | * |
9 | * This program is distributed in the hope it will be useful, but WITHOUT | 9 | * This program is distributed in the hope it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/mei_cl_bus.h> | 26 | #include <linux/mei_cl_bus.h> |
27 | 27 | ||
28 | #include "mei_dev.h" | 28 | #include "mei_dev.h" |
29 | #include "hw-me.h" | 29 | #include "hw-me.h" |
30 | #include "client.h" | 30 | #include "client.h" |
31 | 31 | ||
32 | #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver) | 32 | #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver) |
33 | #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev) | 33 | #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev) |
34 | 34 | ||
35 | static int mei_cl_device_match(struct device *dev, struct device_driver *drv) | 35 | static int mei_cl_device_match(struct device *dev, struct device_driver *drv) |
36 | { | 36 | { |
37 | struct mei_cl_device *device = to_mei_cl_device(dev); | 37 | struct mei_cl_device *device = to_mei_cl_device(dev); |
38 | struct mei_cl_driver *driver = to_mei_cl_driver(drv); | 38 | struct mei_cl_driver *driver = to_mei_cl_driver(drv); |
39 | const struct mei_cl_device_id *id; | 39 | const struct mei_cl_device_id *id; |
40 | 40 | ||
41 | if (!device) | 41 | if (!device) |
42 | return 0; | 42 | return 0; |
43 | 43 | ||
44 | if (!driver || !driver->id_table) | 44 | if (!driver || !driver->id_table) |
45 | return 0; | 45 | return 0; |
46 | 46 | ||
47 | id = driver->id_table; | 47 | id = driver->id_table; |
48 | 48 | ||
49 | while (id->name[0]) { | 49 | while (id->name[0]) { |
50 | if (!strcmp(dev_name(dev), id->name)) | 50 | if (!strcmp(dev_name(dev), id->name)) |
51 | return 1; | 51 | return 1; |
52 | 52 | ||
53 | id++; | 53 | id++; |
54 | } | 54 | } |
55 | 55 | ||
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
58 | 58 | ||
59 | static int mei_cl_device_probe(struct device *dev) | 59 | static int mei_cl_device_probe(struct device *dev) |
60 | { | 60 | { |
61 | struct mei_cl_device *device = to_mei_cl_device(dev); | 61 | struct mei_cl_device *device = to_mei_cl_device(dev); |
62 | struct mei_cl_driver *driver; | 62 | struct mei_cl_driver *driver; |
63 | struct mei_cl_device_id id; | 63 | struct mei_cl_device_id id; |
64 | 64 | ||
65 | if (!device) | 65 | if (!device) |
66 | return 0; | 66 | return 0; |
67 | 67 | ||
68 | driver = to_mei_cl_driver(dev->driver); | 68 | driver = to_mei_cl_driver(dev->driver); |
69 | if (!driver || !driver->probe) | 69 | if (!driver || !driver->probe) |
70 | return -ENODEV; | 70 | return -ENODEV; |
71 | 71 | ||
72 | dev_dbg(dev, "Device probe\n"); | 72 | dev_dbg(dev, "Device probe\n"); |
73 | 73 | ||
74 | strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE); | 74 | strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE); |
75 | 75 | ||
76 | return driver->probe(device, &id); | 76 | return driver->probe(device, &id); |
77 | } | 77 | } |
78 | 78 | ||
79 | static int mei_cl_device_remove(struct device *dev) | 79 | static int mei_cl_device_remove(struct device *dev) |
80 | { | 80 | { |
81 | struct mei_cl_device *device = to_mei_cl_device(dev); | 81 | struct mei_cl_device *device = to_mei_cl_device(dev); |
82 | struct mei_cl_driver *driver; | 82 | struct mei_cl_driver *driver; |
83 | 83 | ||
84 | if (!device || !dev->driver) | 84 | if (!device || !dev->driver) |
85 | return 0; | 85 | return 0; |
86 | 86 | ||
87 | if (device->event_cb) { | 87 | if (device->event_cb) { |
88 | device->event_cb = NULL; | 88 | device->event_cb = NULL; |
89 | cancel_work_sync(&device->event_work); | 89 | cancel_work_sync(&device->event_work); |
90 | } | 90 | } |
91 | 91 | ||
92 | driver = to_mei_cl_driver(dev->driver); | 92 | driver = to_mei_cl_driver(dev->driver); |
93 | if (!driver->remove) { | 93 | if (!driver->remove) { |
94 | dev->driver = NULL; | 94 | dev->driver = NULL; |
95 | 95 | ||
96 | return 0; | 96 | return 0; |
97 | } | 97 | } |
98 | 98 | ||
99 | return driver->remove(device); | 99 | return driver->remove(device); |
100 | } | 100 | } |
101 | 101 | ||
102 | static ssize_t modalias_show(struct device *dev, struct device_attribute *a, | 102 | static ssize_t modalias_show(struct device *dev, struct device_attribute *a, |
103 | char *buf) | 103 | char *buf) |
104 | { | 104 | { |
105 | int len; | 105 | int len; |
106 | 106 | ||
107 | len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev)); | 107 | len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev)); |
108 | 108 | ||
109 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | 109 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; |
110 | } | 110 | } |
111 | 111 | ||
112 | static struct device_attribute mei_cl_dev_attrs[] = { | 112 | static struct device_attribute mei_cl_dev_attrs[] = { |
113 | __ATTR_RO(modalias), | 113 | __ATTR_RO(modalias), |
114 | __ATTR_NULL, | 114 | __ATTR_NULL, |
115 | }; | 115 | }; |
116 | 116 | ||
117 | static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) | 117 | static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) |
118 | { | 118 | { |
119 | if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev))) | 119 | if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev))) |
120 | return -ENOMEM; | 120 | return -ENOMEM; |
121 | 121 | ||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | static struct bus_type mei_cl_bus_type = { | 125 | static struct bus_type mei_cl_bus_type = { |
126 | .name = "mei", | 126 | .name = "mei", |
127 | .dev_attrs = mei_cl_dev_attrs, | 127 | .dev_attrs = mei_cl_dev_attrs, |
128 | .match = mei_cl_device_match, | 128 | .match = mei_cl_device_match, |
129 | .probe = mei_cl_device_probe, | 129 | .probe = mei_cl_device_probe, |
130 | .remove = mei_cl_device_remove, | 130 | .remove = mei_cl_device_remove, |
131 | .uevent = mei_cl_uevent, | 131 | .uevent = mei_cl_uevent, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static void mei_cl_dev_release(struct device *dev) | 134 | static void mei_cl_dev_release(struct device *dev) |
135 | { | 135 | { |
136 | kfree(to_mei_cl_device(dev)); | 136 | kfree(to_mei_cl_device(dev)); |
137 | } | 137 | } |
138 | 138 | ||
139 | static struct device_type mei_cl_device_type = { | 139 | static struct device_type mei_cl_device_type = { |
140 | .release = mei_cl_dev_release, | 140 | .release = mei_cl_dev_release, |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev, | 143 | static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev, |
144 | uuid_le uuid) | 144 | uuid_le uuid) |
145 | { | 145 | { |
146 | struct mei_cl *cl, *next; | 146 | struct mei_cl *cl, *next; |
147 | 147 | ||
148 | list_for_each_entry_safe(cl, next, &dev->device_list, device_link) { | 148 | list_for_each_entry_safe(cl, next, &dev->device_list, device_link) { |
149 | if (!uuid_le_cmp(uuid, cl->device_uuid)) | 149 | if (!uuid_le_cmp(uuid, cl->device_uuid)) |
150 | return cl; | 150 | return cl; |
151 | } | 151 | } |
152 | 152 | ||
153 | return NULL; | 153 | return NULL; |
154 | } | 154 | } |
155 | struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, | 155 | struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, |
156 | uuid_le uuid, char *name) | 156 | uuid_le uuid, char *name, |
157 | struct mei_cl_ops *ops) | ||
157 | { | 158 | { |
158 | struct mei_cl_device *device; | 159 | struct mei_cl_device *device; |
159 | struct mei_cl *cl; | 160 | struct mei_cl *cl; |
160 | int status; | 161 | int status; |
161 | 162 | ||
162 | cl = mei_bus_find_mei_cl_by_uuid(dev, uuid); | 163 | cl = mei_bus_find_mei_cl_by_uuid(dev, uuid); |
163 | if (cl == NULL) | 164 | if (cl == NULL) |
164 | return NULL; | 165 | return NULL; |
165 | 166 | ||
166 | device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); | 167 | device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); |
167 | if (!device) | 168 | if (!device) |
168 | return NULL; | 169 | return NULL; |
169 | 170 | ||
170 | device->cl = cl; | 171 | device->cl = cl; |
172 | device->ops = ops; | ||
171 | 173 | ||
172 | device->dev.parent = &dev->pdev->dev; | 174 | device->dev.parent = &dev->pdev->dev; |
173 | device->dev.bus = &mei_cl_bus_type; | 175 | device->dev.bus = &mei_cl_bus_type; |
174 | device->dev.type = &mei_cl_device_type; | 176 | device->dev.type = &mei_cl_device_type; |
175 | 177 | ||
176 | dev_set_name(&device->dev, "%s", name); | 178 | dev_set_name(&device->dev, "%s", name); |
177 | 179 | ||
178 | status = device_register(&device->dev); | 180 | status = device_register(&device->dev); |
179 | if (status) { | 181 | if (status) { |
180 | dev_err(&dev->pdev->dev, "Failed to register MEI device\n"); | 182 | dev_err(&dev->pdev->dev, "Failed to register MEI device\n"); |
181 | kfree(device); | 183 | kfree(device); |
182 | return NULL; | 184 | return NULL; |
183 | } | 185 | } |
184 | 186 | ||
185 | cl->device = device; | 187 | cl->device = device; |
186 | 188 | ||
187 | dev_dbg(&device->dev, "client %s registered\n", name); | 189 | dev_dbg(&device->dev, "client %s registered\n", name); |
188 | 190 | ||
189 | return device; | 191 | return device; |
190 | } | 192 | } |
191 | EXPORT_SYMBOL_GPL(mei_cl_add_device); | 193 | EXPORT_SYMBOL_GPL(mei_cl_add_device); |
192 | 194 | ||
193 | void mei_cl_remove_device(struct mei_cl_device *device) | 195 | void mei_cl_remove_device(struct mei_cl_device *device) |
194 | { | 196 | { |
195 | device_unregister(&device->dev); | 197 | device_unregister(&device->dev); |
196 | } | 198 | } |
197 | EXPORT_SYMBOL_GPL(mei_cl_remove_device); | 199 | EXPORT_SYMBOL_GPL(mei_cl_remove_device); |
198 | 200 | ||
199 | int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner) | 201 | int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner) |
200 | { | 202 | { |
201 | int err; | 203 | int err; |
202 | 204 | ||
203 | driver->driver.name = driver->name; | 205 | driver->driver.name = driver->name; |
204 | driver->driver.owner = owner; | 206 | driver->driver.owner = owner; |
205 | driver->driver.bus = &mei_cl_bus_type; | 207 | driver->driver.bus = &mei_cl_bus_type; |
206 | 208 | ||
207 | err = driver_register(&driver->driver); | 209 | err = driver_register(&driver->driver); |
208 | if (err) | 210 | if (err) |
209 | return err; | 211 | return err; |
210 | 212 | ||
211 | pr_debug("mei: driver [%s] registered\n", driver->driver.name); | 213 | pr_debug("mei: driver [%s] registered\n", driver->driver.name); |
212 | 214 | ||
213 | return 0; | 215 | return 0; |
214 | } | 216 | } |
215 | EXPORT_SYMBOL_GPL(__mei_cl_driver_register); | 217 | EXPORT_SYMBOL_GPL(__mei_cl_driver_register); |
216 | 218 | ||
217 | void mei_cl_driver_unregister(struct mei_cl_driver *driver) | 219 | void mei_cl_driver_unregister(struct mei_cl_driver *driver) |
218 | { | 220 | { |
219 | driver_unregister(&driver->driver); | 221 | driver_unregister(&driver->driver); |
220 | 222 | ||
221 | pr_debug("mei: driver [%s] unregistered\n", driver->driver.name); | 223 | pr_debug("mei: driver [%s] unregistered\n", driver->driver.name); |
222 | } | 224 | } |
223 | EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); | 225 | EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); |
224 | 226 | ||
225 | static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, | 227 | static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, |
226 | bool blocking) | 228 | bool blocking) |
227 | { | 229 | { |
228 | struct mei_device *dev; | 230 | struct mei_device *dev; |
229 | struct mei_cl_cb *cb; | 231 | struct mei_cl_cb *cb; |
230 | int id; | 232 | int id; |
231 | int rets; | 233 | int rets; |
232 | 234 | ||
233 | if (WARN_ON(!cl || !cl->dev)) | 235 | if (WARN_ON(!cl || !cl->dev)) |
234 | return -ENODEV; | 236 | return -ENODEV; |
235 | 237 | ||
236 | dev = cl->dev; | 238 | dev = cl->dev; |
237 | 239 | ||
238 | if (cl->state != MEI_FILE_CONNECTED) | 240 | if (cl->state != MEI_FILE_CONNECTED) |
239 | return -ENODEV; | 241 | return -ENODEV; |
240 | 242 | ||
241 | /* Check if we have an ME client device */ | 243 | /* Check if we have an ME client device */ |
242 | id = mei_me_cl_by_id(dev, cl->me_client_id); | 244 | id = mei_me_cl_by_id(dev, cl->me_client_id); |
243 | if (id < 0) | 245 | if (id < 0) |
244 | return -ENODEV; | 246 | return -ENODEV; |
245 | 247 | ||
246 | if (length > dev->me_clients[id].props.max_msg_length) | 248 | if (length > dev->me_clients[id].props.max_msg_length) |
247 | return -EINVAL; | 249 | return -EINVAL; |
248 | 250 | ||
249 | cb = mei_io_cb_init(cl, NULL); | 251 | cb = mei_io_cb_init(cl, NULL); |
250 | if (!cb) | 252 | if (!cb) |
251 | return -ENOMEM; | 253 | return -ENOMEM; |
252 | 254 | ||
253 | rets = mei_io_cb_alloc_req_buf(cb, length); | 255 | rets = mei_io_cb_alloc_req_buf(cb, length); |
254 | if (rets < 0) { | 256 | if (rets < 0) { |
255 | mei_io_cb_free(cb); | 257 | mei_io_cb_free(cb); |
256 | return rets; | 258 | return rets; |
257 | } | 259 | } |
258 | 260 | ||
259 | memcpy(cb->request_buffer.data, buf, length); | 261 | memcpy(cb->request_buffer.data, buf, length); |
260 | 262 | ||
261 | mutex_lock(&dev->device_lock); | 263 | mutex_lock(&dev->device_lock); |
262 | 264 | ||
263 | rets = mei_cl_write(cl, cb, blocking); | 265 | rets = mei_cl_write(cl, cb, blocking); |
264 | 266 | ||
265 | mutex_unlock(&dev->device_lock); | 267 | mutex_unlock(&dev->device_lock); |
266 | if (rets < 0) | 268 | if (rets < 0) |
267 | mei_io_cb_free(cb); | 269 | mei_io_cb_free(cb); |
268 | 270 | ||
269 | return rets; | 271 | return rets; |
270 | } | 272 | } |
271 | 273 | ||
272 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | 274 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) |
273 | { | 275 | { |
274 | struct mei_device *dev; | 276 | struct mei_device *dev; |
275 | struct mei_cl_cb *cb; | 277 | struct mei_cl_cb *cb; |
276 | size_t r_length; | 278 | size_t r_length; |
277 | int err; | 279 | int err; |
278 | 280 | ||
279 | if (WARN_ON(!cl || !cl->dev)) | 281 | if (WARN_ON(!cl || !cl->dev)) |
280 | return -ENODEV; | 282 | return -ENODEV; |
281 | 283 | ||
282 | dev = cl->dev; | 284 | dev = cl->dev; |
283 | 285 | ||
284 | mutex_lock(&dev->device_lock); | 286 | mutex_lock(&dev->device_lock); |
285 | 287 | ||
286 | if (!cl->read_cb) { | 288 | if (!cl->read_cb) { |
287 | err = mei_cl_read_start(cl); | 289 | err = mei_cl_read_start(cl); |
288 | if (err < 0) { | 290 | if (err < 0) { |
289 | mutex_unlock(&dev->device_lock); | 291 | mutex_unlock(&dev->device_lock); |
290 | return err; | 292 | return err; |
291 | } | 293 | } |
292 | } | 294 | } |
293 | 295 | ||
294 | if (cl->reading_state != MEI_READ_COMPLETE && | 296 | if (cl->reading_state != MEI_READ_COMPLETE && |
295 | !waitqueue_active(&cl->rx_wait)) { | 297 | !waitqueue_active(&cl->rx_wait)) { |
296 | mutex_unlock(&dev->device_lock); | 298 | mutex_unlock(&dev->device_lock); |
297 | 299 | ||
298 | if (wait_event_interruptible(cl->rx_wait, | 300 | if (wait_event_interruptible(cl->rx_wait, |
299 | (MEI_READ_COMPLETE == cl->reading_state))) { | 301 | (MEI_READ_COMPLETE == cl->reading_state))) { |
300 | if (signal_pending(current)) | 302 | if (signal_pending(current)) |
301 | return -EINTR; | 303 | return -EINTR; |
302 | return -ERESTARTSYS; | 304 | return -ERESTARTSYS; |
303 | } | 305 | } |
304 | 306 | ||
305 | mutex_lock(&dev->device_lock); | 307 | mutex_lock(&dev->device_lock); |
306 | } | 308 | } |
307 | 309 | ||
308 | cb = cl->read_cb; | 310 | cb = cl->read_cb; |
309 | 311 | ||
310 | if (cl->reading_state != MEI_READ_COMPLETE) { | 312 | if (cl->reading_state != MEI_READ_COMPLETE) { |
311 | r_length = 0; | 313 | r_length = 0; |
312 | goto out; | 314 | goto out; |
313 | } | 315 | } |
314 | 316 | ||
315 | r_length = min_t(size_t, length, cb->buf_idx); | 317 | r_length = min_t(size_t, length, cb->buf_idx); |
316 | 318 | ||
317 | memcpy(buf, cb->response_buffer.data, r_length); | 319 | memcpy(buf, cb->response_buffer.data, r_length); |
318 | 320 | ||
319 | mei_io_cb_free(cb); | 321 | mei_io_cb_free(cb); |
320 | cl->reading_state = MEI_IDLE; | 322 | cl->reading_state = MEI_IDLE; |
321 | cl->read_cb = NULL; | 323 | cl->read_cb = NULL; |
322 | 324 | ||
323 | out: | 325 | out: |
324 | mutex_unlock(&dev->device_lock); | 326 | mutex_unlock(&dev->device_lock); |
325 | 327 | ||
326 | return r_length; | 328 | return r_length; |
327 | } | 329 | } |
328 | 330 | ||
329 | inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) | 331 | inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) |
330 | { | 332 | { |
331 | return ___mei_cl_send(cl, buf, length, 0); | 333 | return ___mei_cl_send(cl, buf, length, 0); |
332 | } | 334 | } |
333 | 335 | ||
334 | inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) | 336 | inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) |
335 | { | 337 | { |
336 | return ___mei_cl_send(cl, buf, length, 1); | 338 | return ___mei_cl_send(cl, buf, length, 1); |
337 | } | 339 | } |
338 | 340 | ||
339 | int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) | 341 | int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) |
340 | { | 342 | { |
341 | struct mei_cl *cl = device->cl; | 343 | struct mei_cl *cl = device->cl; |
342 | 344 | ||
343 | if (cl == NULL) | 345 | if (cl == NULL) |
344 | return -ENODEV; | 346 | return -ENODEV; |
345 | 347 | ||
346 | if (device->ops && device->ops->send) | 348 | if (device->ops && device->ops->send) |
347 | return device->ops->send(device, buf, length); | 349 | return device->ops->send(device, buf, length); |
348 | 350 | ||
349 | return __mei_cl_send(cl, buf, length); | 351 | return __mei_cl_send(cl, buf, length); |
350 | } | 352 | } |
351 | EXPORT_SYMBOL_GPL(mei_cl_send); | 353 | EXPORT_SYMBOL_GPL(mei_cl_send); |
352 | 354 | ||
353 | int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) | 355 | int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) |
354 | { | 356 | { |
355 | struct mei_cl *cl = device->cl; | 357 | struct mei_cl *cl = device->cl; |
356 | 358 | ||
357 | if (cl == NULL) | 359 | if (cl == NULL) |
358 | return -ENODEV; | 360 | return -ENODEV; |
359 | 361 | ||
360 | if (device->ops && device->ops->recv) | 362 | if (device->ops && device->ops->recv) |
361 | return device->ops->recv(device, buf, length); | 363 | return device->ops->recv(device, buf, length); |
362 | 364 | ||
363 | return __mei_cl_recv(cl, buf, length); | 365 | return __mei_cl_recv(cl, buf, length); |
364 | } | 366 | } |
365 | EXPORT_SYMBOL_GPL(mei_cl_recv); | 367 | EXPORT_SYMBOL_GPL(mei_cl_recv); |
366 | 368 | ||
367 | static void mei_bus_event_work(struct work_struct *work) | 369 | static void mei_bus_event_work(struct work_struct *work) |
368 | { | 370 | { |
369 | struct mei_cl_device *device; | 371 | struct mei_cl_device *device; |
370 | 372 | ||
371 | device = container_of(work, struct mei_cl_device, event_work); | 373 | device = container_of(work, struct mei_cl_device, event_work); |
372 | 374 | ||
373 | if (device->event_cb) | 375 | if (device->event_cb) |
374 | device->event_cb(device, device->events, device->event_context); | 376 | device->event_cb(device, device->events, device->event_context); |
375 | 377 | ||
376 | device->events = 0; | 378 | device->events = 0; |
377 | 379 | ||
378 | /* Prepare for the next read */ | 380 | /* Prepare for the next read */ |
379 | mei_cl_read_start(device->cl); | 381 | mei_cl_read_start(device->cl); |
380 | } | 382 | } |
381 | 383 | ||
382 | int mei_cl_register_event_cb(struct mei_cl_device *device, | 384 | int mei_cl_register_event_cb(struct mei_cl_device *device, |
383 | mei_cl_event_cb_t event_cb, void *context) | 385 | mei_cl_event_cb_t event_cb, void *context) |
384 | { | 386 | { |
385 | if (device->event_cb) | 387 | if (device->event_cb) |
386 | return -EALREADY; | 388 | return -EALREADY; |
387 | 389 | ||
388 | device->events = 0; | 390 | device->events = 0; |
389 | device->event_cb = event_cb; | 391 | device->event_cb = event_cb; |
390 | device->event_context = context; | 392 | device->event_context = context; |
391 | INIT_WORK(&device->event_work, mei_bus_event_work); | 393 | INIT_WORK(&device->event_work, mei_bus_event_work); |
392 | 394 | ||
393 | mei_cl_read_start(device->cl); | 395 | mei_cl_read_start(device->cl); |
394 | 396 | ||
395 | return 0; | 397 | return 0; |
396 | } | 398 | } |
397 | EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); | 399 | EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); |
398 | 400 | ||
399 | void *mei_cl_get_drvdata(const struct mei_cl_device *device) | 401 | void *mei_cl_get_drvdata(const struct mei_cl_device *device) |
400 | { | 402 | { |
401 | return dev_get_drvdata(&device->dev); | 403 | return dev_get_drvdata(&device->dev); |
402 | } | 404 | } |
403 | EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); | 405 | EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); |
404 | 406 | ||
405 | void mei_cl_set_drvdata(struct mei_cl_device *device, void *data) | 407 | void mei_cl_set_drvdata(struct mei_cl_device *device, void *data) |
406 | { | 408 | { |
407 | dev_set_drvdata(&device->dev, data); | 409 | dev_set_drvdata(&device->dev, data); |
408 | } | 410 | } |
409 | EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); | 411 | EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); |
412 | |||
413 | int mei_cl_enable_device(struct mei_cl_device *device) | ||
414 | { | ||
415 | int err; | ||
416 | struct mei_device *dev; | ||
417 | struct mei_cl *cl = device->cl; | ||
418 | |||
419 | if (cl == NULL) | ||
420 | return -ENODEV; | ||
421 | |||
422 | dev = cl->dev; | ||
423 | |||
424 | mutex_lock(&dev->device_lock); | ||
425 | |||
426 | cl->state = MEI_FILE_CONNECTING; | ||
427 | |||
428 | err = mei_cl_connect(cl, NULL); | ||
429 | if (err < 0) { | ||
430 | mutex_unlock(&dev->device_lock); | ||
431 | dev_err(&dev->pdev->dev, "Could not connect to the ME client"); | ||
432 | |||
433 | return err; | ||
434 | } | ||
435 | |||
436 | mutex_unlock(&dev->device_lock); | ||
437 | |||
438 | if (device->event_cb && !cl->read_cb) | ||
439 | mei_cl_read_start(device->cl); | ||
440 | |||
441 | if (!device->ops || !device->ops->enable) | ||
442 | return 0; | ||
443 | |||
444 | return device->ops->enable(device); | ||
445 | } | ||
446 | EXPORT_SYMBOL_GPL(mei_cl_enable_device); | ||
447 | |||
448 | int mei_cl_disable_device(struct mei_cl_device *device) | ||
449 | { | ||
450 | int err; | ||
451 | struct mei_device *dev; | ||
452 | struct mei_cl *cl = device->cl; | ||
453 | |||
454 | if (cl == NULL) | ||
455 | return -ENODEV; | ||
456 | |||
457 | dev = cl->dev; | ||
458 | |||
459 | mutex_lock(&dev->device_lock); | ||
460 | |||
461 | if (cl->state != MEI_FILE_CONNECTED) { | ||
462 | mutex_unlock(&dev->device_lock); | ||
463 | dev_err(&dev->pdev->dev, "Already disconnected"); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | cl->state = MEI_FILE_DISCONNECTING; | ||
469 | |||
470 | err = mei_cl_disconnect(cl); | ||
471 | if (err < 0) { | ||
472 | mutex_unlock(&dev->device_lock); | ||
473 | dev_err(&dev->pdev->dev, | ||
474 | "Could not disconnect from the ME client"); | ||
475 | |||
476 | return err; | ||
477 | } | ||
478 | |||
479 | /* Flush queues and remove any pending read */ | ||
480 | mei_cl_flush_queues(cl); | ||
481 | |||
482 | if (cl->read_cb) { | ||
483 | struct mei_cl_cb *cb = NULL; | ||
484 | |||
485 | cb = mei_cl_find_read_cb(cl); | ||
486 | /* Remove entry from read list */ | ||
487 | if (cb) | ||
488 | list_del(&cb->list); | ||
489 | |||
490 | cb = cl->read_cb; | ||
491 | cl->read_cb = NULL; | ||
492 | |||
493 | if (cb) { | ||
494 | mei_io_cb_free(cb); | ||
495 | cb = NULL; | ||
496 | } | ||
497 | } | ||
498 | |||
499 | mutex_unlock(&dev->device_lock); | ||
500 | |||
501 | if (!device->ops || !device->ops->disable) | ||
502 | return 0; | ||
503 | |||
504 | return device->ops->disable(device); | ||
505 | } | ||
506 | EXPORT_SYMBOL_GPL(mei_cl_disable_device); | ||
410 | 507 | ||
411 | void mei_cl_bus_rx_event(struct mei_cl *cl) | 508 | void mei_cl_bus_rx_event(struct mei_cl *cl) |
412 | { | 509 | { |
413 | struct mei_cl_device *device = cl->device; | 510 | struct mei_cl_device *device = cl->device; |
414 | 511 | ||
415 | if (!device || !device->event_cb) | 512 | if (!device || !device->event_cb) |
416 | return; | 513 | return; |
417 | 514 | ||
418 | set_bit(MEI_CL_EVENT_RX, &device->events); | 515 | set_bit(MEI_CL_EVENT_RX, &device->events); |
419 | 516 | ||
420 | schedule_work(&device->event_work); | 517 | schedule_work(&device->event_work); |
421 | } | 518 | } |
422 | 519 | ||
423 | int __init mei_cl_bus_init(void) | 520 | int __init mei_cl_bus_init(void) |
424 | { | 521 | { |
425 | return bus_register(&mei_cl_bus_type); | 522 | return bus_register(&mei_cl_bus_type); |
426 | } | 523 | } |
427 | 524 | ||
428 | void __exit mei_cl_bus_exit(void) | 525 | void __exit mei_cl_bus_exit(void) |
429 | { | 526 | { |
430 | bus_unregister(&mei_cl_bus_type); | 527 | bus_unregister(&mei_cl_bus_type); |
431 | } | 528 | } |
432 | 529 |
drivers/misc/mei/mei_dev.h
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | 3 | * Intel Management Engine Interface (Intel MEI) Linux driver |
4 | * Copyright (c) 2003-2012, Intel Corporation. | 4 | * Copyright (c) 2003-2012, Intel Corporation. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
8 | * version 2, as published by the Free Software Foundation. | 8 | * version 2, as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | 10 | * This program is distributed in the hope it will be useful, but WITHOUT |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
13 | * more details. | 13 | * more details. |
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #ifndef _MEI_DEV_H_ | 17 | #ifndef _MEI_DEV_H_ |
18 | #define _MEI_DEV_H_ | 18 | #define _MEI_DEV_H_ |
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <linux/poll.h> | 22 | #include <linux/poll.h> |
23 | #include <linux/mei.h> | 23 | #include <linux/mei.h> |
24 | #include <linux/mei_cl_bus.h> | 24 | #include <linux/mei_cl_bus.h> |
25 | 25 | ||
26 | #include "hw.h" | 26 | #include "hw.h" |
27 | #include "hw-me-regs.h" | 27 | #include "hw-me-regs.h" |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * watch dog definition | 30 | * watch dog definition |
31 | */ | 31 | */ |
32 | #define MEI_WD_HDR_SIZE 4 | 32 | #define MEI_WD_HDR_SIZE 4 |
33 | #define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE | 33 | #define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE |
34 | #define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16) | 34 | #define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16) |
35 | 35 | ||
36 | #define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */ | 36 | #define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */ |
37 | #define MEI_WD_MIN_TIMEOUT 120 /* seconds */ | 37 | #define MEI_WD_MIN_TIMEOUT 120 /* seconds */ |
38 | #define MEI_WD_MAX_TIMEOUT 65535 /* seconds */ | 38 | #define MEI_WD_MAX_TIMEOUT 65535 /* seconds */ |
39 | 39 | ||
40 | #define MEI_WD_STOP_TIMEOUT 10 /* msecs */ | 40 | #define MEI_WD_STOP_TIMEOUT 10 /* msecs */ |
41 | 41 | ||
42 | #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) | 42 | #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) |
43 | 43 | ||
44 | #define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) | 44 | #define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32)) |
45 | 45 | ||
46 | 46 | ||
47 | /* | 47 | /* |
48 | * AMTHI Client UUID | 48 | * AMTHI Client UUID |
49 | */ | 49 | */ |
50 | extern const uuid_le mei_amthif_guid; | 50 | extern const uuid_le mei_amthif_guid; |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * Watchdog Client UUID | 53 | * Watchdog Client UUID |
54 | */ | 54 | */ |
55 | extern const uuid_le mei_wd_guid; | 55 | extern const uuid_le mei_wd_guid; |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * Watchdog independence state message | 58 | * Watchdog independence state message |
59 | */ | 59 | */ |
60 | extern const u8 mei_wd_state_independence_msg[3][4]; | 60 | extern const u8 mei_wd_state_independence_msg[3][4]; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Number of Maximum MEI Clients | 63 | * Number of Maximum MEI Clients |
64 | */ | 64 | */ |
65 | #define MEI_CLIENTS_MAX 256 | 65 | #define MEI_CLIENTS_MAX 256 |
66 | 66 | ||
67 | /* | 67 | /* |
68 | * Number of File descriptors/handles | 68 | * Number of File descriptors/handles |
69 | * that can be opened to the driver. | 69 | * that can be opened to the driver. |
70 | * | 70 | * |
71 | * Limit to 255: 256 Total Clients | 71 | * Limit to 255: 256 Total Clients |
72 | * minus internal client for MEI Bus Messags | 72 | * minus internal client for MEI Bus Messags |
73 | */ | 73 | */ |
74 | #define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) | 74 | #define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) |
75 | 75 | ||
76 | /* | 76 | /* |
77 | * Internal Clients Number | 77 | * Internal Clients Number |
78 | */ | 78 | */ |
79 | #define MEI_HOST_CLIENT_ID_ANY (-1) | 79 | #define MEI_HOST_CLIENT_ID_ANY (-1) |
80 | #define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */ | 80 | #define MEI_HBM_HOST_CLIENT_ID 0 /* not used, just for documentation */ |
81 | #define MEI_WD_HOST_CLIENT_ID 1 | 81 | #define MEI_WD_HOST_CLIENT_ID 1 |
82 | #define MEI_IAMTHIF_HOST_CLIENT_ID 2 | 82 | #define MEI_IAMTHIF_HOST_CLIENT_ID 2 |
83 | 83 | ||
84 | 84 | ||
85 | /* File state */ | 85 | /* File state */ |
86 | enum file_state { | 86 | enum file_state { |
87 | MEI_FILE_INITIALIZING = 0, | 87 | MEI_FILE_INITIALIZING = 0, |
88 | MEI_FILE_CONNECTING, | 88 | MEI_FILE_CONNECTING, |
89 | MEI_FILE_CONNECTED, | 89 | MEI_FILE_CONNECTED, |
90 | MEI_FILE_DISCONNECTING, | 90 | MEI_FILE_DISCONNECTING, |
91 | MEI_FILE_DISCONNECTED | 91 | MEI_FILE_DISCONNECTED |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /* MEI device states */ | 94 | /* MEI device states */ |
95 | enum mei_dev_state { | 95 | enum mei_dev_state { |
96 | MEI_DEV_INITIALIZING = 0, | 96 | MEI_DEV_INITIALIZING = 0, |
97 | MEI_DEV_INIT_CLIENTS, | 97 | MEI_DEV_INIT_CLIENTS, |
98 | MEI_DEV_ENABLED, | 98 | MEI_DEV_ENABLED, |
99 | MEI_DEV_RESETING, | 99 | MEI_DEV_RESETING, |
100 | MEI_DEV_DISABLED, | 100 | MEI_DEV_DISABLED, |
101 | MEI_DEV_POWER_DOWN, | 101 | MEI_DEV_POWER_DOWN, |
102 | MEI_DEV_POWER_UP | 102 | MEI_DEV_POWER_UP |
103 | }; | 103 | }; |
104 | 104 | ||
105 | const char *mei_dev_state_str(int state); | 105 | const char *mei_dev_state_str(int state); |
106 | 106 | ||
107 | /* init clients states*/ | 107 | /* init clients states*/ |
108 | enum mei_init_clients_states { | 108 | enum mei_init_clients_states { |
109 | MEI_START_MESSAGE = 0, | 109 | MEI_START_MESSAGE = 0, |
110 | MEI_ENUM_CLIENTS_MESSAGE, | 110 | MEI_ENUM_CLIENTS_MESSAGE, |
111 | MEI_CLIENT_PROPERTIES_MESSAGE | 111 | MEI_CLIENT_PROPERTIES_MESSAGE |
112 | }; | 112 | }; |
113 | 113 | ||
114 | enum iamthif_states { | 114 | enum iamthif_states { |
115 | MEI_IAMTHIF_IDLE, | 115 | MEI_IAMTHIF_IDLE, |
116 | MEI_IAMTHIF_WRITING, | 116 | MEI_IAMTHIF_WRITING, |
117 | MEI_IAMTHIF_FLOW_CONTROL, | 117 | MEI_IAMTHIF_FLOW_CONTROL, |
118 | MEI_IAMTHIF_READING, | 118 | MEI_IAMTHIF_READING, |
119 | MEI_IAMTHIF_READ_COMPLETE | 119 | MEI_IAMTHIF_READ_COMPLETE |
120 | }; | 120 | }; |
121 | 121 | ||
122 | enum mei_file_transaction_states { | 122 | enum mei_file_transaction_states { |
123 | MEI_IDLE, | 123 | MEI_IDLE, |
124 | MEI_WRITING, | 124 | MEI_WRITING, |
125 | MEI_WRITE_COMPLETE, | 125 | MEI_WRITE_COMPLETE, |
126 | MEI_FLOW_CONTROL, | 126 | MEI_FLOW_CONTROL, |
127 | MEI_READING, | 127 | MEI_READING, |
128 | MEI_READ_COMPLETE | 128 | MEI_READ_COMPLETE |
129 | }; | 129 | }; |
130 | 130 | ||
131 | enum mei_wd_states { | 131 | enum mei_wd_states { |
132 | MEI_WD_IDLE, | 132 | MEI_WD_IDLE, |
133 | MEI_WD_RUNNING, | 133 | MEI_WD_RUNNING, |
134 | MEI_WD_STOPPING, | 134 | MEI_WD_STOPPING, |
135 | }; | 135 | }; |
136 | 136 | ||
137 | /** | 137 | /** |
138 | * enum mei_cb_file_ops - file operation associated with the callback | 138 | * enum mei_cb_file_ops - file operation associated with the callback |
139 | * @MEI_FOP_READ - read | 139 | * @MEI_FOP_READ - read |
140 | * @MEI_FOP_WRITE - write | 140 | * @MEI_FOP_WRITE - write |
141 | * @MEI_FOP_IOCTL - ioctl | 141 | * @MEI_FOP_IOCTL - ioctl |
142 | * @MEI_FOP_OPEN - open | 142 | * @MEI_FOP_OPEN - open |
143 | * @MEI_FOP_CLOSE - close | 143 | * @MEI_FOP_CLOSE - close |
144 | */ | 144 | */ |
145 | enum mei_cb_file_ops { | 145 | enum mei_cb_file_ops { |
146 | MEI_FOP_READ = 0, | 146 | MEI_FOP_READ = 0, |
147 | MEI_FOP_WRITE, | 147 | MEI_FOP_WRITE, |
148 | MEI_FOP_IOCTL, | 148 | MEI_FOP_IOCTL, |
149 | MEI_FOP_OPEN, | 149 | MEI_FOP_OPEN, |
150 | MEI_FOP_CLOSE | 150 | MEI_FOP_CLOSE |
151 | }; | 151 | }; |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * Intel MEI message data struct | 154 | * Intel MEI message data struct |
155 | */ | 155 | */ |
156 | struct mei_msg_data { | 156 | struct mei_msg_data { |
157 | u32 size; | 157 | u32 size; |
158 | unsigned char *data; | 158 | unsigned char *data; |
159 | }; | 159 | }; |
160 | 160 | ||
161 | /** | 161 | /** |
162 | * struct mei_me_client - representation of me (fw) client | 162 | * struct mei_me_client - representation of me (fw) client |
163 | * | 163 | * |
164 | * @props - client properties | 164 | * @props - client properties |
165 | * @client_id - me client id | 165 | * @client_id - me client id |
166 | * @mei_flow_ctrl_creds - flow control credits | 166 | * @mei_flow_ctrl_creds - flow control credits |
167 | */ | 167 | */ |
168 | struct mei_me_client { | 168 | struct mei_me_client { |
169 | struct mei_client_properties props; | 169 | struct mei_client_properties props; |
170 | u8 client_id; | 170 | u8 client_id; |
171 | u8 mei_flow_ctrl_creds; | 171 | u8 mei_flow_ctrl_creds; |
172 | }; | 172 | }; |
173 | 173 | ||
174 | 174 | ||
175 | struct mei_cl; | 175 | struct mei_cl; |
176 | 176 | ||
177 | /** | 177 | /** |
178 | * struct mei_cl_cb - file operation callback structure | 178 | * struct mei_cl_cb - file operation callback structure |
179 | * | 179 | * |
180 | * @cl - file client who is running this operation | 180 | * @cl - file client who is running this operation |
181 | * @fop_type - file operation type | 181 | * @fop_type - file operation type |
182 | */ | 182 | */ |
183 | struct mei_cl_cb { | 183 | struct mei_cl_cb { |
184 | struct list_head list; | 184 | struct list_head list; |
185 | struct mei_cl *cl; | 185 | struct mei_cl *cl; |
186 | enum mei_cb_file_ops fop_type; | 186 | enum mei_cb_file_ops fop_type; |
187 | struct mei_msg_data request_buffer; | 187 | struct mei_msg_data request_buffer; |
188 | struct mei_msg_data response_buffer; | 188 | struct mei_msg_data response_buffer; |
189 | unsigned long buf_idx; | 189 | unsigned long buf_idx; |
190 | unsigned long read_time; | 190 | unsigned long read_time; |
191 | struct file *file_object; | 191 | struct file *file_object; |
192 | }; | 192 | }; |
193 | 193 | ||
194 | /* MEI client instance carried as file->pirvate_data*/ | 194 | /* MEI client instance carried as file->pirvate_data*/ |
195 | struct mei_cl { | 195 | struct mei_cl { |
196 | struct list_head link; | 196 | struct list_head link; |
197 | struct mei_device *dev; | 197 | struct mei_device *dev; |
198 | enum file_state state; | 198 | enum file_state state; |
199 | wait_queue_head_t tx_wait; | 199 | wait_queue_head_t tx_wait; |
200 | wait_queue_head_t rx_wait; | 200 | wait_queue_head_t rx_wait; |
201 | wait_queue_head_t wait; | 201 | wait_queue_head_t wait; |
202 | int status; | 202 | int status; |
203 | /* ID of client connected */ | 203 | /* ID of client connected */ |
204 | u8 host_client_id; | 204 | u8 host_client_id; |
205 | u8 me_client_id; | 205 | u8 me_client_id; |
206 | u8 mei_flow_ctrl_creds; | 206 | u8 mei_flow_ctrl_creds; |
207 | u8 timer_count; | 207 | u8 timer_count; |
208 | enum mei_file_transaction_states reading_state; | 208 | enum mei_file_transaction_states reading_state; |
209 | enum mei_file_transaction_states writing_state; | 209 | enum mei_file_transaction_states writing_state; |
210 | int sm_state; | 210 | int sm_state; |
211 | struct mei_cl_cb *read_cb; | 211 | struct mei_cl_cb *read_cb; |
212 | 212 | ||
213 | /* MEI CL bus data */ | 213 | /* MEI CL bus data */ |
214 | struct mei_cl_device *device; | 214 | struct mei_cl_device *device; |
215 | struct list_head device_link; | 215 | struct list_head device_link; |
216 | uuid_le device_uuid; | 216 | uuid_le device_uuid; |
217 | }; | 217 | }; |
218 | 218 | ||
219 | /** struct mei_hw_ops | 219 | /** struct mei_hw_ops |
220 | * | 220 | * |
221 | * @host_is_ready - query for host readiness | 221 | * @host_is_ready - query for host readiness |
222 | 222 | ||
223 | * @hw_is_ready - query if hw is ready | 223 | * @hw_is_ready - query if hw is ready |
224 | * @hw_reset - reset hw | 224 | * @hw_reset - reset hw |
225 | * @hw_start - start hw after reset | 225 | * @hw_start - start hw after reset |
226 | * @hw_config - configure hw | 226 | * @hw_config - configure hw |
227 | 227 | ||
228 | * @intr_clear - clear pending interrupts | 228 | * @intr_clear - clear pending interrupts |
229 | * @intr_enable - enable interrupts | 229 | * @intr_enable - enable interrupts |
230 | * @intr_disable - disable interrupts | 230 | * @intr_disable - disable interrupts |
231 | 231 | ||
232 | * @hbuf_free_slots - query for write buffer empty slots | 232 | * @hbuf_free_slots - query for write buffer empty slots |
233 | * @hbuf_is_ready - query if write buffer is empty | 233 | * @hbuf_is_ready - query if write buffer is empty |
234 | * @hbuf_max_len - query for write buffer max len | 234 | * @hbuf_max_len - query for write buffer max len |
235 | 235 | ||
236 | * @write - write a message to FW | 236 | * @write - write a message to FW |
237 | 237 | ||
238 | * @rdbuf_full_slots - query how many slots are filled | 238 | * @rdbuf_full_slots - query how many slots are filled |
239 | 239 | ||
240 | * @read_hdr - get first 4 bytes (header) | 240 | * @read_hdr - get first 4 bytes (header) |
241 | * @read - read a buffer from the FW | 241 | * @read - read a buffer from the FW |
242 | */ | 242 | */ |
243 | struct mei_hw_ops { | 243 | struct mei_hw_ops { |
244 | 244 | ||
245 | bool (*host_is_ready) (struct mei_device *dev); | 245 | bool (*host_is_ready) (struct mei_device *dev); |
246 | 246 | ||
247 | bool (*hw_is_ready) (struct mei_device *dev); | 247 | bool (*hw_is_ready) (struct mei_device *dev); |
248 | void (*hw_reset) (struct mei_device *dev, bool enable); | 248 | void (*hw_reset) (struct mei_device *dev, bool enable); |
249 | int (*hw_start) (struct mei_device *dev); | 249 | int (*hw_start) (struct mei_device *dev); |
250 | void (*hw_config) (struct mei_device *dev); | 250 | void (*hw_config) (struct mei_device *dev); |
251 | 251 | ||
252 | void (*intr_clear) (struct mei_device *dev); | 252 | void (*intr_clear) (struct mei_device *dev); |
253 | void (*intr_enable) (struct mei_device *dev); | 253 | void (*intr_enable) (struct mei_device *dev); |
254 | void (*intr_disable) (struct mei_device *dev); | 254 | void (*intr_disable) (struct mei_device *dev); |
255 | 255 | ||
256 | int (*hbuf_free_slots) (struct mei_device *dev); | 256 | int (*hbuf_free_slots) (struct mei_device *dev); |
257 | bool (*hbuf_is_ready) (struct mei_device *dev); | 257 | bool (*hbuf_is_ready) (struct mei_device *dev); |
258 | size_t (*hbuf_max_len) (const struct mei_device *dev); | 258 | size_t (*hbuf_max_len) (const struct mei_device *dev); |
259 | 259 | ||
260 | int (*write)(struct mei_device *dev, | 260 | int (*write)(struct mei_device *dev, |
261 | struct mei_msg_hdr *hdr, | 261 | struct mei_msg_hdr *hdr, |
262 | unsigned char *buf); | 262 | unsigned char *buf); |
263 | 263 | ||
264 | int (*rdbuf_full_slots)(struct mei_device *dev); | 264 | int (*rdbuf_full_slots)(struct mei_device *dev); |
265 | 265 | ||
266 | u32 (*read_hdr)(const struct mei_device *dev); | 266 | u32 (*read_hdr)(const struct mei_device *dev); |
267 | int (*read) (struct mei_device *dev, | 267 | int (*read) (struct mei_device *dev, |
268 | unsigned char *buf, unsigned long len); | 268 | unsigned char *buf, unsigned long len); |
269 | }; | 269 | }; |
270 | 270 | ||
271 | /* MEI bus API*/ | 271 | /* MEI bus API*/ |
272 | struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, | ||
273 | uuid_le uuid, char *name); | ||
274 | void mei_cl_remove_device(struct mei_cl_device *device); | ||
275 | 272 | ||
276 | int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); | ||
277 | int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); | ||
278 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); | ||
279 | |||
280 | /** | 273 | /** |
281 | * struct mei_cl_transport_ops - MEI CL device transport ops | 274 | * struct mei_cl_ops - MEI CL device ops |
282 | * This structure allows ME host clients to implement technology | 275 | * This structure allows ME host clients to implement technology |
283 | * specific transport layers. | 276 | * specific operations. |
284 | * | 277 | * |
278 | * @enable: Enable an MEI CL device. Some devices require specific | ||
279 | * HECI commands to initialize completely. | ||
280 | * @disable: Disable an MEI CL device. | ||
285 | * @send: Tx hook for the device. This allows ME host clients to trap | 281 | * @send: Tx hook for the device. This allows ME host clients to trap |
286 | * the device driver buffers before actually physically | 282 | * the device driver buffers before actually physically |
287 | * pushing it to the ME. | 283 | * pushing it to the ME. |
288 | * @recv: Rx hook for the device. This allows ME host clients to trap the | 284 | * @recv: Rx hook for the device. This allows ME host clients to trap the |
289 | * ME buffers before forwarding them to the device driver. | 285 | * ME buffers before forwarding them to the device driver. |
290 | */ | 286 | */ |
291 | struct mei_cl_transport_ops { | 287 | struct mei_cl_ops { |
288 | int (*enable)(struct mei_cl_device *device); | ||
289 | int (*disable)(struct mei_cl_device *device); | ||
292 | int (*send)(struct mei_cl_device *device, u8 *buf, size_t length); | 290 | int (*send)(struct mei_cl_device *device, u8 *buf, size_t length); |
293 | int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length); | 291 | int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length); |
294 | }; | 292 | }; |
295 | 293 | ||
294 | struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, | ||
295 | uuid_le uuid, char *name, | ||
296 | struct mei_cl_ops *ops); | ||
297 | void mei_cl_remove_device(struct mei_cl_device *device); | ||
298 | |||
299 | int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); | ||
300 | int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); | ||
301 | int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); | ||
296 | void mei_cl_bus_rx_event(struct mei_cl *cl); | 302 | void mei_cl_bus_rx_event(struct mei_cl *cl); |
297 | int mei_cl_bus_init(void); | 303 | int mei_cl_bus_init(void); |
298 | void mei_cl_bus_exit(void); | 304 | void mei_cl_bus_exit(void); |
299 | 305 | ||
300 | 306 | ||
301 | /** | 307 | /** |
302 | * struct mei_cl_device - MEI device handle | 308 | * struct mei_cl_device - MEI device handle |
303 | * An mei_cl_device pointer is returned from mei_add_device() | 309 | * An mei_cl_device pointer is returned from mei_add_device() |
304 | * and links MEI bus clients to their actual ME host client pointer. | 310 | * and links MEI bus clients to their actual ME host client pointer. |
305 | * Drivers for MEI devices will get an mei_cl_device pointer | 311 | * Drivers for MEI devices will get an mei_cl_device pointer |
306 | * when being probed and shall use it for doing ME bus I/O. | 312 | * when being probed and shall use it for doing ME bus I/O. |
307 | * | 313 | * |
308 | * @dev: linux driver model device pointer | 314 | * @dev: linux driver model device pointer |
309 | * @uuid: me client uuid | 315 | * @uuid: me client uuid |
310 | * @cl: mei client | 316 | * @cl: mei client |
311 | * @ops: ME transport ops | 317 | * @ops: ME transport ops |
312 | * @event_cb: Drivers register this callback to get asynchronous ME | 318 | * @event_cb: Drivers register this callback to get asynchronous ME |
313 | * events (e.g. Rx buffer pending) notifications. | 319 | * events (e.g. Rx buffer pending) notifications. |
314 | * @events: Events bitmask sent to the driver. | 320 | * @events: Events bitmask sent to the driver. |
315 | * @priv_data: client private data | 321 | * @priv_data: client private data |
316 | */ | 322 | */ |
317 | struct mei_cl_device { | 323 | struct mei_cl_device { |
318 | struct device dev; | 324 | struct device dev; |
319 | 325 | ||
320 | struct mei_cl *cl; | 326 | struct mei_cl *cl; |
321 | 327 | ||
322 | const struct mei_cl_transport_ops *ops; | 328 | const struct mei_cl_ops *ops; |
323 | 329 | ||
324 | struct work_struct event_work; | 330 | struct work_struct event_work; |
325 | mei_cl_event_cb_t event_cb; | 331 | mei_cl_event_cb_t event_cb; |
326 | void *event_context; | 332 | void *event_context; |
327 | unsigned long events; | 333 | unsigned long events; |
328 | 334 | ||
329 | void *priv_data; | 335 | void *priv_data; |
330 | }; | 336 | }; |
331 | 337 | ||
332 | /** | 338 | /** |
333 | * struct mei_device - MEI private device struct | 339 | * struct mei_device - MEI private device struct |
334 | 340 | ||
335 | * @mem_addr - mem mapped base register address | 341 | * @mem_addr - mem mapped base register address |
336 | 342 | ||
337 | * @hbuf_depth - depth of hardware host/write buffer is slots | 343 | * @hbuf_depth - depth of hardware host/write buffer is slots |
338 | * @hbuf_is_ready - query if the host host/write buffer is ready | 344 | * @hbuf_is_ready - query if the host host/write buffer is ready |
339 | * @wr_msg - the buffer for hbm control messages | 345 | * @wr_msg - the buffer for hbm control messages |
340 | * @wr_ext_msg - the buffer for hbm control responses (set in read cycle) | 346 | * @wr_ext_msg - the buffer for hbm control responses (set in read cycle) |
341 | */ | 347 | */ |
342 | struct mei_device { | 348 | struct mei_device { |
343 | struct pci_dev *pdev; /* pointer to pci device struct */ | 349 | struct pci_dev *pdev; /* pointer to pci device struct */ |
344 | /* | 350 | /* |
345 | * lists of queues | 351 | * lists of queues |
346 | */ | 352 | */ |
347 | /* array of pointers to aio lists */ | 353 | /* array of pointers to aio lists */ |
348 | struct mei_cl_cb read_list; /* driver read queue */ | 354 | struct mei_cl_cb read_list; /* driver read queue */ |
349 | struct mei_cl_cb write_list; /* driver write queue */ | 355 | struct mei_cl_cb write_list; /* driver write queue */ |
350 | struct mei_cl_cb write_waiting_list; /* write waiting queue */ | 356 | struct mei_cl_cb write_waiting_list; /* write waiting queue */ |
351 | struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ | 357 | struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ |
352 | struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ | 358 | struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ |
353 | 359 | ||
354 | /* | 360 | /* |
355 | * list of files | 361 | * list of files |
356 | */ | 362 | */ |
357 | struct list_head file_list; | 363 | struct list_head file_list; |
358 | long open_handle_count; | 364 | long open_handle_count; |
359 | 365 | ||
360 | /* | 366 | /* |
361 | * lock for the device | 367 | * lock for the device |
362 | */ | 368 | */ |
363 | struct mutex device_lock; /* device lock */ | 369 | struct mutex device_lock; /* device lock */ |
364 | struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */ | 370 | struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */ |
365 | 371 | ||
366 | bool recvd_hw_ready; | 372 | bool recvd_hw_ready; |
367 | bool recvd_msg; | 373 | bool recvd_msg; |
368 | 374 | ||
369 | /* | 375 | /* |
370 | * waiting queue for receive message from FW | 376 | * waiting queue for receive message from FW |
371 | */ | 377 | */ |
372 | wait_queue_head_t wait_hw_ready; | 378 | wait_queue_head_t wait_hw_ready; |
373 | wait_queue_head_t wait_recvd_msg; | 379 | wait_queue_head_t wait_recvd_msg; |
374 | wait_queue_head_t wait_stop_wd; | 380 | wait_queue_head_t wait_stop_wd; |
375 | 381 | ||
376 | /* | 382 | /* |
377 | * mei device states | 383 | * mei device states |
378 | */ | 384 | */ |
379 | enum mei_dev_state dev_state; | 385 | enum mei_dev_state dev_state; |
380 | enum mei_init_clients_states init_clients_state; | 386 | enum mei_init_clients_states init_clients_state; |
381 | u16 init_clients_timer; | 387 | u16 init_clients_timer; |
382 | 388 | ||
383 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ | 389 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ |
384 | u32 rd_msg_hdr; | 390 | u32 rd_msg_hdr; |
385 | 391 | ||
386 | /* write buffer */ | 392 | /* write buffer */ |
387 | u8 hbuf_depth; | 393 | u8 hbuf_depth; |
388 | bool hbuf_is_ready; | 394 | bool hbuf_is_ready; |
389 | 395 | ||
390 | /* used for control messages */ | 396 | /* used for control messages */ |
391 | struct { | 397 | struct { |
392 | struct mei_msg_hdr hdr; | 398 | struct mei_msg_hdr hdr; |
393 | unsigned char data[128]; | 399 | unsigned char data[128]; |
394 | } wr_msg; | 400 | } wr_msg; |
395 | 401 | ||
396 | struct { | 402 | struct { |
397 | struct mei_msg_hdr hdr; | 403 | struct mei_msg_hdr hdr; |
398 | unsigned char data[4]; /* All HBM messages are 4 bytes */ | 404 | unsigned char data[4]; /* All HBM messages are 4 bytes */ |
399 | } wr_ext_msg; /* for control responses */ | 405 | } wr_ext_msg; /* for control responses */ |
400 | 406 | ||
401 | struct hbm_version version; | 407 | struct hbm_version version; |
402 | 408 | ||
403 | struct mei_me_client *me_clients; /* Note: memory has to be allocated */ | 409 | struct mei_me_client *me_clients; /* Note: memory has to be allocated */ |
404 | DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); | 410 | DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); |
405 | DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX); | 411 | DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX); |
406 | u8 me_clients_num; | 412 | u8 me_clients_num; |
407 | u8 me_client_presentation_num; | 413 | u8 me_client_presentation_num; |
408 | u8 me_client_index; | 414 | u8 me_client_index; |
409 | 415 | ||
410 | struct mei_cl wd_cl; | 416 | struct mei_cl wd_cl; |
411 | enum mei_wd_states wd_state; | 417 | enum mei_wd_states wd_state; |
412 | bool wd_pending; | 418 | bool wd_pending; |
413 | u16 wd_timeout; | 419 | u16 wd_timeout; |
414 | unsigned char wd_data[MEI_WD_START_MSG_SIZE]; | 420 | unsigned char wd_data[MEI_WD_START_MSG_SIZE]; |
415 | 421 | ||
416 | 422 | ||
417 | /* amthif list for cmd waiting */ | 423 | /* amthif list for cmd waiting */ |
418 | struct mei_cl_cb amthif_cmd_list; | 424 | struct mei_cl_cb amthif_cmd_list; |
419 | /* driver managed amthif list for reading completed amthif cmd data */ | 425 | /* driver managed amthif list for reading completed amthif cmd data */ |
420 | struct mei_cl_cb amthif_rd_complete_list; | 426 | struct mei_cl_cb amthif_rd_complete_list; |
421 | struct file *iamthif_file_object; | 427 | struct file *iamthif_file_object; |
422 | struct mei_cl iamthif_cl; | 428 | struct mei_cl iamthif_cl; |
423 | struct mei_cl_cb *iamthif_current_cb; | 429 | struct mei_cl_cb *iamthif_current_cb; |
424 | int iamthif_mtu; | 430 | int iamthif_mtu; |
425 | unsigned long iamthif_timer; | 431 | unsigned long iamthif_timer; |
426 | u32 iamthif_stall_timer; | 432 | u32 iamthif_stall_timer; |
427 | unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */ | 433 | unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */ |
428 | u32 iamthif_msg_buf_size; | 434 | u32 iamthif_msg_buf_size; |
429 | u32 iamthif_msg_buf_index; | 435 | u32 iamthif_msg_buf_index; |
430 | enum iamthif_states iamthif_state; | 436 | enum iamthif_states iamthif_state; |
431 | bool iamthif_flow_control_pending; | 437 | bool iamthif_flow_control_pending; |
432 | bool iamthif_ioctl; | 438 | bool iamthif_ioctl; |
433 | bool iamthif_canceled; | 439 | bool iamthif_canceled; |
434 | 440 | ||
435 | struct work_struct init_work; | 441 | struct work_struct init_work; |
436 | 442 | ||
437 | /* List of bus devices */ | 443 | /* List of bus devices */ |
438 | struct list_head device_list; | 444 | struct list_head device_list; |
439 | 445 | ||
440 | #if IS_ENABLED(CONFIG_DEBUG_FS) | 446 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
441 | struct dentry *dbgfs_dir; | 447 | struct dentry *dbgfs_dir; |
442 | #endif /* CONFIG_DEBUG_FS */ | 448 | #endif /* CONFIG_DEBUG_FS */ |
443 | 449 | ||
444 | 450 | ||
445 | const struct mei_hw_ops *ops; | 451 | const struct mei_hw_ops *ops; |
446 | char hw[0] __aligned(sizeof(void *)); | 452 | char hw[0] __aligned(sizeof(void *)); |
447 | }; | 453 | }; |
448 | 454 | ||
449 | static inline unsigned long mei_secs_to_jiffies(unsigned long sec) | 455 | static inline unsigned long mei_secs_to_jiffies(unsigned long sec) |
450 | { | 456 | { |
451 | return msecs_to_jiffies(sec * MSEC_PER_SEC); | 457 | return msecs_to_jiffies(sec * MSEC_PER_SEC); |
452 | } | 458 | } |
453 | 459 | ||
454 | /** | 460 | /** |
455 | * mei_data2slots - get slots - number of (dwords) from a message length | 461 | * mei_data2slots - get slots - number of (dwords) from a message length |
456 | * + size of the mei header | 462 | * + size of the mei header |
457 | * @length - size of the messages in bytes | 463 | * @length - size of the messages in bytes |
458 | * returns - number of slots | 464 | * returns - number of slots |
459 | */ | 465 | */ |
460 | static inline u32 mei_data2slots(size_t length) | 466 | static inline u32 mei_data2slots(size_t length) |
461 | { | 467 | { |
462 | return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4); | 468 | return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4); |
463 | } | 469 | } |
464 | 470 | ||
465 | /* | 471 | /* |
466 | * mei init function prototypes | 472 | * mei init function prototypes |
467 | */ | 473 | */ |
468 | void mei_device_init(struct mei_device *dev); | 474 | void mei_device_init(struct mei_device *dev); |
469 | void mei_reset(struct mei_device *dev, int interrupts); | 475 | void mei_reset(struct mei_device *dev, int interrupts); |
470 | int mei_start(struct mei_device *dev); | 476 | int mei_start(struct mei_device *dev); |
471 | void mei_stop(struct mei_device *dev); | 477 | void mei_stop(struct mei_device *dev); |
472 | 478 | ||
473 | /* | 479 | /* |
474 | * MEI interrupt functions prototype | 480 | * MEI interrupt functions prototype |
475 | */ | 481 | */ |
476 | 482 | ||
477 | void mei_timer(struct work_struct *work); | 483 | void mei_timer(struct work_struct *work); |
478 | int mei_irq_read_handler(struct mei_device *dev, | 484 | int mei_irq_read_handler(struct mei_device *dev, |
479 | struct mei_cl_cb *cmpl_list, s32 *slots); | 485 | struct mei_cl_cb *cmpl_list, s32 *slots); |
480 | 486 | ||
481 | int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); | 487 | int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); |
482 | void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); | 488 | void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); |
483 | 489 | ||
484 | /* | 490 | /* |
485 | * AMTHIF - AMT Host Interface Functions | 491 | * AMTHIF - AMT Host Interface Functions |
486 | */ | 492 | */ |
487 | void mei_amthif_reset_params(struct mei_device *dev); | 493 | void mei_amthif_reset_params(struct mei_device *dev); |
488 | 494 | ||
489 | int mei_amthif_host_init(struct mei_device *dev); | 495 | int mei_amthif_host_init(struct mei_device *dev); |
490 | 496 | ||
491 | int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); | 497 | int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); |
492 | 498 | ||
493 | int mei_amthif_read(struct mei_device *dev, struct file *file, | 499 | int mei_amthif_read(struct mei_device *dev, struct file *file, |
494 | char __user *ubuf, size_t length, loff_t *offset); | 500 | char __user *ubuf, size_t length, loff_t *offset); |
495 | 501 | ||
496 | unsigned int mei_amthif_poll(struct mei_device *dev, | 502 | unsigned int mei_amthif_poll(struct mei_device *dev, |
497 | struct file *file, poll_table *wait); | 503 | struct file *file, poll_table *wait); |
498 | 504 | ||
499 | int mei_amthif_release(struct mei_device *dev, struct file *file); | 505 | int mei_amthif_release(struct mei_device *dev, struct file *file); |
500 | 506 | ||
501 | struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, | 507 | struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, |
502 | struct file *file); | 508 | struct file *file); |
503 | 509 | ||
504 | void mei_amthif_run_next_cmd(struct mei_device *dev); | 510 | void mei_amthif_run_next_cmd(struct mei_device *dev); |
505 | 511 | ||
506 | 512 | ||
507 | int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, | 513 | int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, |
508 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); | 514 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); |
509 | 515 | ||
510 | void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); | 516 | void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); |
511 | int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, | 517 | int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, |
512 | struct mei_device *dev, struct mei_msg_hdr *mei_hdr); | 518 | struct mei_device *dev, struct mei_msg_hdr *mei_hdr); |
513 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); | 519 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); |
514 | 520 | ||
515 | 521 | ||
516 | int mei_wd_send(struct mei_device *dev); | 522 | int mei_wd_send(struct mei_device *dev); |
517 | int mei_wd_stop(struct mei_device *dev); | 523 | int mei_wd_stop(struct mei_device *dev); |
518 | int mei_wd_host_init(struct mei_device *dev); | 524 | int mei_wd_host_init(struct mei_device *dev); |
519 | /* | 525 | /* |
520 | * mei_watchdog_register - Registering watchdog interface | 526 | * mei_watchdog_register - Registering watchdog interface |
521 | * once we got connection to the WD Client | 527 | * once we got connection to the WD Client |
522 | * @dev - mei device | 528 | * @dev - mei device |
523 | */ | 529 | */ |
524 | void mei_watchdog_register(struct mei_device *dev); | 530 | void mei_watchdog_register(struct mei_device *dev); |
525 | /* | 531 | /* |
526 | * mei_watchdog_unregister - Unregistering watchdog interface | 532 | * mei_watchdog_unregister - Unregistering watchdog interface |
527 | * @dev - mei device | 533 | * @dev - mei device |
528 | */ | 534 | */ |
529 | void mei_watchdog_unregister(struct mei_device *dev); | 535 | void mei_watchdog_unregister(struct mei_device *dev); |
530 | 536 | ||
531 | /* | 537 | /* |
532 | * Register Access Function | 538 | * Register Access Function |
533 | */ | 539 | */ |
534 | 540 | ||
535 | static inline void mei_hw_config(struct mei_device *dev) | 541 | static inline void mei_hw_config(struct mei_device *dev) |
536 | { | 542 | { |
537 | dev->ops->hw_config(dev); | 543 | dev->ops->hw_config(dev); |
538 | } | 544 | } |
539 | static inline void mei_hw_reset(struct mei_device *dev, bool enable) | 545 | static inline void mei_hw_reset(struct mei_device *dev, bool enable) |
540 | { | 546 | { |
541 | dev->ops->hw_reset(dev, enable); | 547 | dev->ops->hw_reset(dev, enable); |
542 | } | 548 | } |
543 | 549 | ||
544 | static inline void mei_hw_start(struct mei_device *dev) | 550 | static inline void mei_hw_start(struct mei_device *dev) |
545 | { | 551 | { |
546 | dev->ops->hw_start(dev); | 552 | dev->ops->hw_start(dev); |
547 | } | 553 | } |
548 | 554 | ||
549 | static inline void mei_clear_interrupts(struct mei_device *dev) | 555 | static inline void mei_clear_interrupts(struct mei_device *dev) |
550 | { | 556 | { |
551 | dev->ops->intr_clear(dev); | 557 | dev->ops->intr_clear(dev); |
552 | } | 558 | } |
553 | 559 | ||
554 | static inline void mei_enable_interrupts(struct mei_device *dev) | 560 | static inline void mei_enable_interrupts(struct mei_device *dev) |
555 | { | 561 | { |
556 | dev->ops->intr_enable(dev); | 562 | dev->ops->intr_enable(dev); |
557 | } | 563 | } |
558 | 564 | ||
559 | static inline void mei_disable_interrupts(struct mei_device *dev) | 565 | static inline void mei_disable_interrupts(struct mei_device *dev) |
560 | { | 566 | { |
561 | dev->ops->intr_disable(dev); | 567 | dev->ops->intr_disable(dev); |
562 | } | 568 | } |
563 | 569 | ||
564 | static inline bool mei_host_is_ready(struct mei_device *dev) | 570 | static inline bool mei_host_is_ready(struct mei_device *dev) |
565 | { | 571 | { |
566 | return dev->ops->host_is_ready(dev); | 572 | return dev->ops->host_is_ready(dev); |
567 | } | 573 | } |
568 | static inline bool mei_hw_is_ready(struct mei_device *dev) | 574 | static inline bool mei_hw_is_ready(struct mei_device *dev) |
569 | { | 575 | { |
570 | return dev->ops->hw_is_ready(dev); | 576 | return dev->ops->hw_is_ready(dev); |
571 | } | 577 | } |
572 | 578 | ||
573 | static inline bool mei_hbuf_is_ready(struct mei_device *dev) | 579 | static inline bool mei_hbuf_is_ready(struct mei_device *dev) |
574 | { | 580 | { |
575 | return dev->ops->hbuf_is_ready(dev); | 581 | return dev->ops->hbuf_is_ready(dev); |
576 | } | 582 | } |
577 | 583 | ||
578 | static inline int mei_hbuf_empty_slots(struct mei_device *dev) | 584 | static inline int mei_hbuf_empty_slots(struct mei_device *dev) |
579 | { | 585 | { |
580 | return dev->ops->hbuf_free_slots(dev); | 586 | return dev->ops->hbuf_free_slots(dev); |
581 | } | 587 | } |
582 | 588 | ||
583 | static inline size_t mei_hbuf_max_len(const struct mei_device *dev) | 589 | static inline size_t mei_hbuf_max_len(const struct mei_device *dev) |
584 | { | 590 | { |
585 | return dev->ops->hbuf_max_len(dev); | 591 | return dev->ops->hbuf_max_len(dev); |
586 | } | 592 | } |
587 | 593 | ||
588 | static inline int mei_write_message(struct mei_device *dev, | 594 | static inline int mei_write_message(struct mei_device *dev, |
589 | struct mei_msg_hdr *hdr, | 595 | struct mei_msg_hdr *hdr, |
590 | unsigned char *buf) | 596 | unsigned char *buf) |
591 | { | 597 | { |
592 | return dev->ops->write(dev, hdr, buf); | 598 | return dev->ops->write(dev, hdr, buf); |
593 | } | 599 | } |
594 | 600 | ||
595 | static inline u32 mei_read_hdr(const struct mei_device *dev) | 601 | static inline u32 mei_read_hdr(const struct mei_device *dev) |
596 | { | 602 | { |
597 | return dev->ops->read_hdr(dev); | 603 | return dev->ops->read_hdr(dev); |
598 | } | 604 | } |
599 | 605 | ||
600 | static inline void mei_read_slots(struct mei_device *dev, | 606 | static inline void mei_read_slots(struct mei_device *dev, |
601 | unsigned char *buf, unsigned long len) | 607 | unsigned char *buf, unsigned long len) |
602 | { | 608 | { |
603 | dev->ops->read(dev, buf, len); | 609 | dev->ops->read(dev, buf, len); |
604 | } | 610 | } |
605 | 611 | ||
606 | static inline int mei_count_full_read_slots(struct mei_device *dev) | 612 | static inline int mei_count_full_read_slots(struct mei_device *dev) |
607 | { | 613 | { |
608 | return dev->ops->rdbuf_full_slots(dev); | 614 | return dev->ops->rdbuf_full_slots(dev); |
609 | } | 615 | } |
610 | 616 | ||
611 | #if IS_ENABLED(CONFIG_DEBUG_FS) | 617 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
612 | int mei_dbgfs_register(struct mei_device *dev, const char *name); | 618 | int mei_dbgfs_register(struct mei_device *dev, const char *name); |
613 | void mei_dbgfs_deregister(struct mei_device *dev); | 619 | void mei_dbgfs_deregister(struct mei_device *dev); |
614 | #else | 620 | #else |
615 | static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) | 621 | static inline int mei_dbgfs_register(struct mei_device *dev, const char *name) |
616 | { | 622 | { |
617 | return 0; | 623 | return 0; |
618 | } | 624 | } |
619 | static inline void mei_dbgfs_deregister(struct mei_device *dev) {} | 625 | static inline void mei_dbgfs_deregister(struct mei_device *dev) {} |
620 | #endif /* CONFIG_DEBUG_FS */ | 626 | #endif /* CONFIG_DEBUG_FS */ |
621 | 627 | ||
622 | int mei_register(struct mei_device *dev); | 628 | int mei_register(struct mei_device *dev); |
623 | void mei_deregister(struct mei_device *dev); | 629 | void mei_deregister(struct mei_device *dev); |
624 | 630 |
include/linux/mei_cl_bus.h
1 | #ifndef _LINUX_MEI_CL_BUS_H | 1 | #ifndef _LINUX_MEI_CL_BUS_H |
2 | #define _LINUX_MEI_CL_BUS_H | 2 | #define _LINUX_MEI_CL_BUS_H |
3 | 3 | ||
4 | #include <linux/device.h> | 4 | #include <linux/device.h> |
5 | #include <linux/uuid.h> | 5 | #include <linux/uuid.h> |
6 | 6 | ||
7 | struct mei_cl_device; | 7 | struct mei_cl_device; |
8 | 8 | ||
9 | struct mei_cl_driver { | 9 | struct mei_cl_driver { |
10 | struct device_driver driver; | 10 | struct device_driver driver; |
11 | const char *name; | 11 | const char *name; |
12 | 12 | ||
13 | const struct mei_cl_device_id *id_table; | 13 | const struct mei_cl_device_id *id_table; |
14 | 14 | ||
15 | int (*probe)(struct mei_cl_device *dev, | 15 | int (*probe)(struct mei_cl_device *dev, |
16 | const struct mei_cl_device_id *id); | 16 | const struct mei_cl_device_id *id); |
17 | int (*remove)(struct mei_cl_device *dev); | 17 | int (*remove)(struct mei_cl_device *dev); |
18 | }; | 18 | }; |
19 | 19 | ||
20 | int __mei_cl_driver_register(struct mei_cl_driver *driver, | 20 | int __mei_cl_driver_register(struct mei_cl_driver *driver, |
21 | struct module *owner); | 21 | struct module *owner); |
22 | #define mei_cl_driver_register(driver) \ | 22 | #define mei_cl_driver_register(driver) \ |
23 | __mei_cl_driver_register(driver, THIS_MODULE) | 23 | __mei_cl_driver_register(driver, THIS_MODULE) |
24 | 24 | ||
25 | void mei_cl_driver_unregister(struct mei_cl_driver *driver); | 25 | void mei_cl_driver_unregister(struct mei_cl_driver *driver); |
26 | 26 | ||
27 | int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length); | 27 | int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length); |
28 | int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length); | 28 | int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length); |
29 | 29 | ||
30 | typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, | 30 | typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, |
31 | u32 events, void *context); | 31 | u32 events, void *context); |
32 | int mei_cl_register_event_cb(struct mei_cl_device *device, | 32 | int mei_cl_register_event_cb(struct mei_cl_device *device, |
33 | mei_cl_event_cb_t read_cb, void *context); | 33 | mei_cl_event_cb_t read_cb, void *context); |
34 | 34 | ||
35 | #define MEI_CL_EVENT_RX 0 | 35 | #define MEI_CL_EVENT_RX 0 |
36 | #define MEI_CL_EVENT_TX 1 | 36 | #define MEI_CL_EVENT_TX 1 |
37 | 37 | ||
38 | void *mei_cl_get_drvdata(const struct mei_cl_device *device); | 38 | void *mei_cl_get_drvdata(const struct mei_cl_device *device); |
39 | void mei_cl_set_drvdata(struct mei_cl_device *device, void *data); | 39 | void mei_cl_set_drvdata(struct mei_cl_device *device, void *data); |
40 | 40 | ||
41 | int mei_cl_enable_device(struct mei_cl_device *device); | ||
42 | int mei_cl_disable_device(struct mei_cl_device *device); | ||
43 | |||
41 | #endif /* _LINUX_MEI_CL_BUS_H */ | 44 | #endif /* _LINUX_MEI_CL_BUS_H */ |
42 | 45 |