blob: 8dbcb1516dc63df0983340a10e3ff1a52df91838 [file] [log] [blame]
Samuel Ortize5354102013-03-27 17:29:53 +02001/*
2 * Intel Management Engine Interface (Intel MEI) Linux driver
3 * Copyright (c) 2012-2013, Intel Corporation.
4 *
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.
8 *
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
12 * more details.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/device.h>
18#include <linux/kernel.h>
Samuel Ortiz3e833292013-03-27 17:29:55 +020019#include <linux/sched.h>
Samuel Ortize5354102013-03-27 17:29:53 +020020#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/pci.h>
26#include <linux/mei_cl_bus.h>
27
28#include "mei_dev.h"
Samuel Ortiz3e833292013-03-27 17:29:55 +020029#include "hw-me.h"
30#include "client.h"
Samuel Ortize5354102013-03-27 17:29:53 +020031
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)
34
35static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
36{
37 struct mei_cl_device *device = to_mei_cl_device(dev);
38 struct mei_cl_driver *driver = to_mei_cl_driver(drv);
39 const struct mei_cl_device_id *id;
40
41 if (!device)
42 return 0;
43
44 if (!driver || !driver->id_table)
45 return 0;
46
47 id = driver->id_table;
48
49 while (id->name[0]) {
50 if (!strcmp(dev_name(dev), id->name))
51 return 1;
52
53 id++;
54 }
55
56 return 0;
57}
58
59static int mei_cl_device_probe(struct device *dev)
60{
61 struct mei_cl_device *device = to_mei_cl_device(dev);
62 struct mei_cl_driver *driver;
63 struct mei_cl_device_id id;
64
65 if (!device)
66 return 0;
67
68 driver = to_mei_cl_driver(dev->driver);
69 if (!driver || !driver->probe)
70 return -ENODEV;
71
72 dev_dbg(dev, "Device probe\n");
73
74 strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
75
76 return driver->probe(device, &id);
77}
78
79static int mei_cl_device_remove(struct device *dev)
80{
81 struct mei_cl_device *device = to_mei_cl_device(dev);
82 struct mei_cl_driver *driver;
83
84 if (!device || !dev->driver)
85 return 0;
86
Samuel Ortiz3e833292013-03-27 17:29:55 +020087 if (device->event_cb) {
88 device->event_cb = NULL;
89 cancel_work_sync(&device->event_work);
90 }
91
Samuel Ortize5354102013-03-27 17:29:53 +020092 driver = to_mei_cl_driver(dev->driver);
93 if (!driver->remove) {
94 dev->driver = NULL;
95
96 return 0;
97 }
98
99 return driver->remove(device);
100}
101
102static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
103 char *buf)
104{
105 int len;
106
107 len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));
108
109 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
110}
111
112static struct device_attribute mei_cl_dev_attrs[] = {
113 __ATTR_RO(modalias),
114 __ATTR_NULL,
115};
116
117static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
118{
119 if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
120 return -ENOMEM;
121
122 return 0;
123}
124
125static struct bus_type mei_cl_bus_type = {
126 .name = "mei",
127 .dev_attrs = mei_cl_dev_attrs,
128 .match = mei_cl_device_match,
129 .probe = mei_cl_device_probe,
130 .remove = mei_cl_device_remove,
131 .uevent = mei_cl_uevent,
132};
133
134static void mei_cl_dev_release(struct device *dev)
135{
136 kfree(to_mei_cl_device(dev));
137}
138
139static struct device_type mei_cl_device_type = {
140 .release = mei_cl_dev_release,
141};
142
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200143static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
144 uuid_le uuid)
145{
146 struct mei_cl *cl, *next;
147
148 list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
149 if (!uuid_le_cmp(uuid, cl->device_uuid))
150 return cl;
151 }
152
153 return NULL;
154}
155struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
Samuel Ortize5354102013-03-27 17:29:53 +0200156 uuid_le uuid, char *name)
157{
158 struct mei_cl_device *device;
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200159 struct mei_cl *cl;
Samuel Ortize5354102013-03-27 17:29:53 +0200160 int status;
161
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200162 cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
163 if (cl == NULL)
164 return NULL;
165
Samuel Ortize5354102013-03-27 17:29:53 +0200166 device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
167 if (!device)
168 return NULL;
169
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200170 device->cl = cl;
171
172 device->dev.parent = &dev->pdev->dev;
Samuel Ortize5354102013-03-27 17:29:53 +0200173 device->dev.bus = &mei_cl_bus_type;
174 device->dev.type = &mei_cl_device_type;
175
176 dev_set_name(&device->dev, "%s", name);
177
178 status = device_register(&device->dev);
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200179 if (status) {
180 dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
181 kfree(device);
182 return NULL;
183 }
184
185 cl->device = device;
Samuel Ortize5354102013-03-27 17:29:53 +0200186
187 dev_dbg(&device->dev, "client %s registered\n", name);
188
189 return device;
Samuel Ortize5354102013-03-27 17:29:53 +0200190}
191EXPORT_SYMBOL_GPL(mei_cl_add_device);
192
193void mei_cl_remove_device(struct mei_cl_device *device)
194{
195 device_unregister(&device->dev);
196}
197EXPORT_SYMBOL_GPL(mei_cl_remove_device);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200198
199int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
200{
201 int err;
202
203 driver->driver.name = driver->name;
204 driver->driver.owner = owner;
205 driver->driver.bus = &mei_cl_bus_type;
206
207 err = driver_register(&driver->driver);
208 if (err)
209 return err;
210
211 pr_debug("mei: driver [%s] registered\n", driver->driver.name);
212
213 return 0;
214}
215EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
216
217void mei_cl_driver_unregister(struct mei_cl_driver *driver)
218{
219 driver_unregister(&driver->driver);
220
221 pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
222}
223EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200224
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200225static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
226 bool blocking)
Samuel Ortiz3e833292013-03-27 17:29:55 +0200227{
228 struct mei_device *dev;
229 struct mei_msg_hdr mei_hdr;
230 struct mei_cl_cb *cb;
231 int me_cl_id, err;
232
233 if (WARN_ON(!cl || !cl->dev))
234 return -ENODEV;
235
236 if (cl->state != MEI_FILE_CONNECTED)
237 return -ENODEV;
238
239 cb = mei_io_cb_init(cl, NULL);
240 if (!cb)
241 return -ENOMEM;
242
243 err = mei_io_cb_alloc_req_buf(cb, length);
244 if (err < 0) {
245 mei_io_cb_free(cb);
246 return err;
247 }
248
249 memcpy(cb->request_buffer.data, buf, length);
250 cb->fop_type = MEI_FOP_WRITE;
251
252 dev = cl->dev;
253
254 mutex_lock(&dev->device_lock);
255
256 /* Check if we have an ME client device */
257 me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id);
258 if (me_cl_id == dev->me_clients_num) {
259 err = -ENODEV;
260 goto out_err;
261 }
262
263 if (length > dev->me_clients[me_cl_id].props.max_msg_length) {
264 err = -EINVAL;
265 goto out_err;
266 }
267
268 err = mei_cl_flow_ctrl_creds(cl);
269 if (err < 0)
270 goto out_err;
271
272 /* Host buffer is not ready, we queue the request */
273 if (err == 0 || !dev->hbuf_is_ready) {
274 cb->buf_idx = 0;
275 mei_hdr.msg_complete = 0;
276 cl->writing_state = MEI_WRITING;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200277
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200278 goto out;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200279 }
280
281 dev->hbuf_is_ready = false;
282
283 /* Check for a maximum length */
284 if (length > mei_hbuf_max_len(dev)) {
285 mei_hdr.length = mei_hbuf_max_len(dev);
286 mei_hdr.msg_complete = 0;
287 } else {
288 mei_hdr.length = length;
289 mei_hdr.msg_complete = 1;
290 }
291
292 mei_hdr.host_addr = cl->host_client_id;
293 mei_hdr.me_addr = cl->me_client_id;
294 mei_hdr.reserved = 0;
295
296 if (mei_write_message(dev, &mei_hdr, buf)) {
297 err = -EIO;
298 goto out_err;
299 }
300
301 cl->writing_state = MEI_WRITING;
302 cb->buf_idx = mei_hdr.length;
303
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200304out:
305 if (mei_hdr.msg_complete) {
Samuel Ortiz3e833292013-03-27 17:29:55 +0200306 if (mei_cl_flow_ctrl_reduce(cl)) {
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200307 err = -ENODEV;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200308 goto out_err;
309 }
Samuel Ortiz3e833292013-03-27 17:29:55 +0200310 list_add_tail(&cb->list, &dev->write_waiting_list.list);
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200311 } else {
312 list_add_tail(&cb->list, &dev->write_list.list);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200313 }
314
315 mutex_unlock(&dev->device_lock);
316
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200317 if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
318 if (wait_event_interruptible(cl->tx_wait,
319 cl->writing_state == MEI_WRITE_COMPLETE)) {
320 if (signal_pending(current))
321 err = -EINTR;
322 err = -ERESTARTSYS;
323 mutex_lock(&dev->device_lock);
324 goto out_err;
325 }
326 }
327
Samuel Ortiz3e833292013-03-27 17:29:55 +0200328 return mei_hdr.length;
329
330out_err:
331 mutex_unlock(&dev->device_lock);
332 mei_io_cb_free(cb);
333
334 return err;
335}
336
337int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
338{
339 struct mei_device *dev;
340 struct mei_cl_cb *cb;
341 size_t r_length;
342 int err;
343
344 if (WARN_ON(!cl || !cl->dev))
345 return -ENODEV;
346
347 dev = cl->dev;
348
349 mutex_lock(&dev->device_lock);
350
351 if (!cl->read_cb) {
352 err = mei_cl_read_start(cl);
353 if (err < 0) {
354 mutex_unlock(&dev->device_lock);
355 return err;
356 }
357 }
358
359 if (cl->reading_state != MEI_READ_COMPLETE &&
360 !waitqueue_active(&cl->rx_wait)) {
361 mutex_unlock(&dev->device_lock);
362
363 if (wait_event_interruptible(cl->rx_wait,
364 (MEI_READ_COMPLETE == cl->reading_state))) {
365 if (signal_pending(current))
366 return -EINTR;
367 return -ERESTARTSYS;
368 }
369
370 mutex_lock(&dev->device_lock);
371 }
372
373 cb = cl->read_cb;
374
375 if (cl->reading_state != MEI_READ_COMPLETE) {
376 r_length = 0;
377 goto out;
378 }
379
380 r_length = min_t(size_t, length, cb->buf_idx);
381
382 memcpy(buf, cb->response_buffer.data, r_length);
383
384 mei_io_cb_free(cb);
385 cl->reading_state = MEI_IDLE;
386 cl->read_cb = NULL;
387
388out:
389 mutex_unlock(&dev->device_lock);
390
391 return r_length;
392}
393
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200394inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
395{
396 return ___mei_cl_send(cl, buf, length, 0);
397}
398
399inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
400{
401 return ___mei_cl_send(cl, buf, length, 1);
402}
403
Samuel Ortiz3e833292013-03-27 17:29:55 +0200404int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
405{
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200406 struct mei_cl *cl = device->cl;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200407
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200408 if (cl == NULL)
409 return -ENODEV;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200410
411 if (device->ops && device->ops->send)
412 return device->ops->send(device, buf, length);
413
414 return __mei_cl_send(cl, buf, length);
415}
416EXPORT_SYMBOL_GPL(mei_cl_send);
417
418int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
419{
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200420 struct mei_cl *cl = device->cl;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200421
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200422 if (cl == NULL)
423 return -ENODEV;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200424
425 if (device->ops && device->ops->recv)
426 return device->ops->recv(device, buf, length);
427
428 return __mei_cl_recv(cl, buf, length);
429}
430EXPORT_SYMBOL_GPL(mei_cl_recv);
431
432static void mei_bus_event_work(struct work_struct *work)
433{
434 struct mei_cl_device *device;
435
436 device = container_of(work, struct mei_cl_device, event_work);
437
438 if (device->event_cb)
439 device->event_cb(device, device->events, device->event_context);
440
441 device->events = 0;
442
443 /* Prepare for the next read */
444 mei_cl_read_start(device->cl);
445}
446
447int mei_cl_register_event_cb(struct mei_cl_device *device,
448 mei_cl_event_cb_t event_cb, void *context)
449{
450 if (device->event_cb)
451 return -EALREADY;
452
453 device->events = 0;
454 device->event_cb = event_cb;
455 device->event_context = context;
456 INIT_WORK(&device->event_work, mei_bus_event_work);
457
458 mei_cl_read_start(device->cl);
459
460 return 0;
461}
462EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
Samuel Ortizcf3baef2013-03-27 17:29:57 +0200463
Samuel Ortizaa6aef22013-03-27 17:29:59 +0200464void *mei_cl_get_drvdata(const struct mei_cl_device *device)
465{
466 return dev_get_drvdata(&device->dev);
467}
468EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
469
470void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
471{
472 dev_set_drvdata(&device->dev, data);
473}
474EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
475
Samuel Ortizcf3baef2013-03-27 17:29:57 +0200476void mei_cl_bus_rx_event(struct mei_cl *cl)
477{
478 struct mei_cl_device *device = cl->device;
479
480 if (!device || !device->event_cb)
481 return;
482
483 set_bit(MEI_CL_EVENT_RX, &device->events);
484
485 schedule_work(&device->event_work);
486}
487
488int __init mei_cl_bus_init(void)
489{
490 return bus_register(&mei_cl_bus_type);
491}
492
493void __exit mei_cl_bus_exit(void)
494{
495 bus_unregister(&mei_cl_bus_type);
496}