2 * Intel Management Engine Interface (Intel MEI) Linux driver
3 * Copyright (c) 2012-2013, Intel Corporation.
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,
7 * version 2, as published by the Free Software Foundation.
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
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 #include <linux/module.h>
17 #include <linux/device.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/init.h>
21 #include <linux/errno.h>
22 #include <linux/slab.h>
23 #include <linux/mutex.h>
24 #include <linux/interrupt.h>
25 #include <linux/mei_cl_bus.h>
30 #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
31 #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
33 static int mei_cl_device_match(struct device
*dev
, struct device_driver
*drv
)
35 struct mei_cl_device
*device
= to_mei_cl_device(dev
);
36 struct mei_cl_driver
*driver
= to_mei_cl_driver(drv
);
37 const struct mei_cl_device_id
*id
;
42 if (!driver
|| !driver
->id_table
)
45 id
= driver
->id_table
;
48 if (!strncmp(dev_name(dev
), id
->name
, sizeof(id
->name
)))
57 static int mei_cl_device_probe(struct device
*dev
)
59 struct mei_cl_device
*device
= to_mei_cl_device(dev
);
60 struct mei_cl_driver
*driver
;
61 struct mei_cl_device_id id
;
66 driver
= to_mei_cl_driver(dev
->driver
);
67 if (!driver
|| !driver
->probe
)
70 dev_dbg(dev
, "Device probe\n");
72 strlcpy(id
.name
, dev_name(dev
), sizeof(id
.name
));
74 return driver
->probe(device
, &id
);
77 static int mei_cl_device_remove(struct device
*dev
)
79 struct mei_cl_device
*device
= to_mei_cl_device(dev
);
80 struct mei_cl_driver
*driver
;
82 if (!device
|| !dev
->driver
)
85 if (device
->event_cb
) {
86 device
->event_cb
= NULL
;
87 cancel_work_sync(&device
->event_work
);
90 driver
= to_mei_cl_driver(dev
->driver
);
91 if (!driver
->remove
) {
97 return driver
->remove(device
);
100 static ssize_t
modalias_show(struct device
*dev
, struct device_attribute
*a
,
105 len
= snprintf(buf
, PAGE_SIZE
, "mei:%s\n", dev_name(dev
));
107 return (len
>= PAGE_SIZE
) ? (PAGE_SIZE
- 1) : len
;
109 static DEVICE_ATTR_RO(modalias
);
111 static struct attribute
*mei_cl_dev_attrs
[] = {
112 &dev_attr_modalias
.attr
,
115 ATTRIBUTE_GROUPS(mei_cl_dev
);
117 static int mei_cl_uevent(struct device
*dev
, struct kobj_uevent_env
*env
)
119 if (add_uevent_var(env
, "MODALIAS=mei:%s", dev_name(dev
)))
125 static struct bus_type mei_cl_bus_type
= {
127 .dev_groups
= mei_cl_dev_groups
,
128 .match
= mei_cl_device_match
,
129 .probe
= mei_cl_device_probe
,
130 .remove
= mei_cl_device_remove
,
131 .uevent
= mei_cl_uevent
,
134 static void mei_cl_dev_release(struct device
*dev
)
136 kfree(to_mei_cl_device(dev
));
139 static struct device_type mei_cl_device_type
= {
140 .release
= mei_cl_dev_release
,
143 struct mei_cl
*mei_cl_bus_find_cl_by_uuid(struct mei_device
*dev
,
148 list_for_each_entry(cl
, &dev
->device_list
, device_link
) {
149 if (!uuid_le_cmp(uuid
, cl
->cl_uuid
))
155 struct mei_cl_device
*mei_cl_add_device(struct mei_device
*dev
,
156 uuid_le uuid
, char *name
,
157 struct mei_cl_ops
*ops
)
159 struct mei_cl_device
*device
;
163 cl
= mei_cl_bus_find_cl_by_uuid(dev
, uuid
);
167 device
= kzalloc(sizeof(struct mei_cl_device
), GFP_KERNEL
);
174 device
->dev
.parent
= dev
->dev
;
175 device
->dev
.bus
= &mei_cl_bus_type
;
176 device
->dev
.type
= &mei_cl_device_type
;
178 dev_set_name(&device
->dev
, "%s", name
);
180 status
= device_register(&device
->dev
);
182 dev_err(dev
->dev
, "Failed to register MEI device\n");
189 dev_dbg(&device
->dev
, "client %s registered\n", name
);
193 EXPORT_SYMBOL_GPL(mei_cl_add_device
);
195 void mei_cl_remove_device(struct mei_cl_device
*device
)
197 device_unregister(&device
->dev
);
199 EXPORT_SYMBOL_GPL(mei_cl_remove_device
);
201 int __mei_cl_driver_register(struct mei_cl_driver
*driver
, struct module
*owner
)
205 driver
->driver
.name
= driver
->name
;
206 driver
->driver
.owner
= owner
;
207 driver
->driver
.bus
= &mei_cl_bus_type
;
209 err
= driver_register(&driver
->driver
);
213 pr_debug("mei: driver [%s] registered\n", driver
->driver
.name
);
217 EXPORT_SYMBOL_GPL(__mei_cl_driver_register
);
219 void mei_cl_driver_unregister(struct mei_cl_driver
*driver
)
221 driver_unregister(&driver
->driver
);
223 pr_debug("mei: driver [%s] unregistered\n", driver
->driver
.name
);
225 EXPORT_SYMBOL_GPL(mei_cl_driver_unregister
);
227 static ssize_t
___mei_cl_send(struct mei_cl
*cl
, u8
*buf
, size_t length
,
230 struct mei_device
*dev
;
231 struct mei_me_client
*me_cl
= NULL
;
232 struct mei_cl_cb
*cb
= NULL
;
235 if (WARN_ON(!cl
|| !cl
->dev
))
240 mutex_lock(&dev
->device_lock
);
241 if (cl
->state
!= MEI_FILE_CONNECTED
) {
246 /* Check if we have an ME client device */
247 me_cl
= mei_me_cl_by_uuid_id(dev
, &cl
->cl_uuid
, cl
->me_client_id
);
253 if (length
> me_cl
->props
.max_msg_length
) {
258 cb
= mei_io_cb_init(cl
, NULL
);
264 rets
= mei_io_cb_alloc_req_buf(cb
, length
);
268 memcpy(cb
->request_buffer
.data
, buf
, length
);
270 rets
= mei_cl_write(cl
, cb
, blocking
);
273 mei_me_cl_put(me_cl
);
274 mutex_unlock(&dev
->device_lock
);
281 ssize_t
__mei_cl_recv(struct mei_cl
*cl
, u8
*buf
, size_t length
)
283 struct mei_device
*dev
;
284 struct mei_cl_cb
*cb
;
288 if (WARN_ON(!cl
|| !cl
->dev
))
293 mutex_lock(&dev
->device_lock
);
296 rets
= mei_cl_read_start(cl
, length
);
301 if (cl
->reading_state
!= MEI_READ_COMPLETE
&&
302 !waitqueue_active(&cl
->rx_wait
)) {
304 mutex_unlock(&dev
->device_lock
);
306 if (wait_event_interruptible(cl
->rx_wait
,
307 cl
->reading_state
== MEI_READ_COMPLETE
||
308 mei_cl_is_transitioning(cl
))) {
310 if (signal_pending(current
))
315 mutex_lock(&dev
->device_lock
);
320 if (cl
->reading_state
!= MEI_READ_COMPLETE
) {
330 r_length
= min_t(size_t, length
, cb
->buf_idx
);
331 memcpy(buf
, cb
->response_buffer
.data
, r_length
);
336 cl
->reading_state
= MEI_IDLE
;
340 mutex_unlock(&dev
->device_lock
);
345 inline ssize_t
__mei_cl_async_send(struct mei_cl
*cl
, u8
*buf
, size_t length
)
347 return ___mei_cl_send(cl
, buf
, length
, 0);
350 inline ssize_t
__mei_cl_send(struct mei_cl
*cl
, u8
*buf
, size_t length
)
352 return ___mei_cl_send(cl
, buf
, length
, 1);
355 ssize_t
mei_cl_send(struct mei_cl_device
*device
, u8
*buf
, size_t length
)
357 struct mei_cl
*cl
= device
->cl
;
362 if (device
->ops
&& device
->ops
->send
)
363 return device
->ops
->send(device
, buf
, length
);
365 return __mei_cl_send(cl
, buf
, length
);
367 EXPORT_SYMBOL_GPL(mei_cl_send
);
369 ssize_t
mei_cl_recv(struct mei_cl_device
*device
, u8
*buf
, size_t length
)
371 struct mei_cl
*cl
= device
->cl
;
376 if (device
->ops
&& device
->ops
->recv
)
377 return device
->ops
->recv(device
, buf
, length
);
379 return __mei_cl_recv(cl
, buf
, length
);
381 EXPORT_SYMBOL_GPL(mei_cl_recv
);
383 static void mei_bus_event_work(struct work_struct
*work
)
385 struct mei_cl_device
*device
;
387 device
= container_of(work
, struct mei_cl_device
, event_work
);
389 if (device
->event_cb
)
390 device
->event_cb(device
, device
->events
, device
->event_context
);
394 /* Prepare for the next read */
395 mei_cl_read_start(device
->cl
, 0);
398 int mei_cl_register_event_cb(struct mei_cl_device
*device
,
399 mei_cl_event_cb_t event_cb
, void *context
)
401 if (device
->event_cb
)
405 device
->event_cb
= event_cb
;
406 device
->event_context
= context
;
407 INIT_WORK(&device
->event_work
, mei_bus_event_work
);
409 mei_cl_read_start(device
->cl
, 0);
413 EXPORT_SYMBOL_GPL(mei_cl_register_event_cb
);
415 void *mei_cl_get_drvdata(const struct mei_cl_device
*device
)
417 return dev_get_drvdata(&device
->dev
);
419 EXPORT_SYMBOL_GPL(mei_cl_get_drvdata
);
421 void mei_cl_set_drvdata(struct mei_cl_device
*device
, void *data
)
423 dev_set_drvdata(&device
->dev
, data
);
425 EXPORT_SYMBOL_GPL(mei_cl_set_drvdata
);
427 int mei_cl_enable_device(struct mei_cl_device
*device
)
430 struct mei_device
*dev
;
431 struct mei_cl
*cl
= device
->cl
;
438 mutex_lock(&dev
->device_lock
);
440 err
= mei_cl_connect(cl
, NULL
);
442 mutex_unlock(&dev
->device_lock
);
443 dev_err(dev
->dev
, "Could not connect to the ME client");
448 mutex_unlock(&dev
->device_lock
);
450 if (device
->event_cb
&& !cl
->read_cb
)
451 mei_cl_read_start(device
->cl
, 0);
453 if (!device
->ops
|| !device
->ops
->enable
)
456 return device
->ops
->enable(device
);
458 EXPORT_SYMBOL_GPL(mei_cl_enable_device
);
460 int mei_cl_disable_device(struct mei_cl_device
*device
)
463 struct mei_device
*dev
;
464 struct mei_cl
*cl
= device
->cl
;
471 mutex_lock(&dev
->device_lock
);
473 if (cl
->state
!= MEI_FILE_CONNECTED
) {
474 mutex_unlock(&dev
->device_lock
);
475 dev_err(dev
->dev
, "Already disconnected");
480 cl
->state
= MEI_FILE_DISCONNECTING
;
482 err
= mei_cl_disconnect(cl
);
484 mutex_unlock(&dev
->device_lock
);
486 "Could not disconnect from the ME client");
491 /* Flush queues and remove any pending read */
492 mei_cl_flush_queues(cl
);
495 struct mei_cl_cb
*cb
= NULL
;
497 cb
= mei_cl_find_read_cb(cl
);
498 /* Remove entry from read list */
511 device
->event_cb
= NULL
;
513 mutex_unlock(&dev
->device_lock
);
515 if (!device
->ops
|| !device
->ops
->disable
)
518 return device
->ops
->disable(device
);
520 EXPORT_SYMBOL_GPL(mei_cl_disable_device
);
522 void mei_cl_bus_rx_event(struct mei_cl
*cl
)
524 struct mei_cl_device
*device
= cl
->device
;
526 if (!device
|| !device
->event_cb
)
529 set_bit(MEI_CL_EVENT_RX
, &device
->events
);
531 schedule_work(&device
->event_work
);
534 void mei_cl_bus_remove_devices(struct mei_device
*dev
)
536 struct mei_cl
*cl
, *next
;
538 mutex_lock(&dev
->device_lock
);
539 list_for_each_entry_safe(cl
, next
, &dev
->device_list
, device_link
) {
541 mei_cl_remove_device(cl
->device
);
543 list_del(&cl
->device_link
);
547 mutex_unlock(&dev
->device_lock
);
550 int __init
mei_cl_bus_init(void)
552 return bus_register(&mei_cl_bus_type
);
555 void __exit
mei_cl_bus_exit(void)
557 bus_unregister(&mei_cl_bus_type
);