blob: 6badfa1110e99ef9f87e76668563a047901b550b [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;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200229 struct mei_cl_cb *cb;
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300230 int id;
231 int rets;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200232
233 if (WARN_ON(!cl || !cl->dev))
234 return -ENODEV;
235
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300236 dev = cl->dev;
237
Samuel Ortiz3e833292013-03-27 17:29:55 +0200238 if (cl->state != MEI_FILE_CONNECTED)
239 return -ENODEV;
240
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300241 /* Check if we have an ME client device */
242 id = mei_me_cl_by_id(dev, cl->me_client_id);
243 if (id < 0)
244 return -ENODEV;
245
246 if (length > dev->me_clients[id].props.max_msg_length)
247 return -EINVAL;
248
Samuel Ortiz3e833292013-03-27 17:29:55 +0200249 cb = mei_io_cb_init(cl, NULL);
250 if (!cb)
251 return -ENOMEM;
252
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300253 rets = mei_io_cb_alloc_req_buf(cb, length);
254 if (rets < 0) {
Samuel Ortiz3e833292013-03-27 17:29:55 +0200255 mei_io_cb_free(cb);
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300256 return rets;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200257 }
258
259 memcpy(cb->request_buffer.data, buf, length);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200260
261 mutex_lock(&dev->device_lock);
262
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300263 rets = mei_cl_write(cl, cb, blocking);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200264
265 mutex_unlock(&dev->device_lock);
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300266 if (rets < 0)
267 mei_io_cb_free(cb);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200268
Tomas Winkler4234a6d2013-04-08 21:56:37 +0300269 return rets;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200270}
271
272int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
273{
274 struct mei_device *dev;
275 struct mei_cl_cb *cb;
276 size_t r_length;
277 int err;
278
279 if (WARN_ON(!cl || !cl->dev))
280 return -ENODEV;
281
282 dev = cl->dev;
283
284 mutex_lock(&dev->device_lock);
285
286 if (!cl->read_cb) {
287 err = mei_cl_read_start(cl);
288 if (err < 0) {
289 mutex_unlock(&dev->device_lock);
290 return err;
291 }
292 }
293
294 if (cl->reading_state != MEI_READ_COMPLETE &&
295 !waitqueue_active(&cl->rx_wait)) {
296 mutex_unlock(&dev->device_lock);
297
298 if (wait_event_interruptible(cl->rx_wait,
299 (MEI_READ_COMPLETE == cl->reading_state))) {
300 if (signal_pending(current))
301 return -EINTR;
302 return -ERESTARTSYS;
303 }
304
305 mutex_lock(&dev->device_lock);
306 }
307
308 cb = cl->read_cb;
309
310 if (cl->reading_state != MEI_READ_COMPLETE) {
311 r_length = 0;
312 goto out;
313 }
314
315 r_length = min_t(size_t, length, cb->buf_idx);
316
317 memcpy(buf, cb->response_buffer.data, r_length);
318
319 mei_io_cb_free(cb);
320 cl->reading_state = MEI_IDLE;
321 cl->read_cb = NULL;
322
323out:
324 mutex_unlock(&dev->device_lock);
325
326 return r_length;
327}
328
Samuel Ortiz44d88d92013-03-27 17:29:58 +0200329inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
330{
331 return ___mei_cl_send(cl, buf, length, 0);
332}
333
334inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
335{
336 return ___mei_cl_send(cl, buf, length, 1);
337}
338
Samuel Ortiz3e833292013-03-27 17:29:55 +0200339int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
340{
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200341 struct mei_cl *cl = device->cl;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200342
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200343 if (cl == NULL)
344 return -ENODEV;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200345
346 if (device->ops && device->ops->send)
347 return device->ops->send(device, buf, length);
348
349 return __mei_cl_send(cl, buf, length);
350}
351EXPORT_SYMBOL_GPL(mei_cl_send);
352
353int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
354{
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200355 struct mei_cl *cl = device->cl;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200356
Samuel Ortiza7b71bc2013-03-27 17:29:56 +0200357 if (cl == NULL)
358 return -ENODEV;
Samuel Ortiz3e833292013-03-27 17:29:55 +0200359
360 if (device->ops && device->ops->recv)
361 return device->ops->recv(device, buf, length);
362
363 return __mei_cl_recv(cl, buf, length);
364}
365EXPORT_SYMBOL_GPL(mei_cl_recv);
366
367static void mei_bus_event_work(struct work_struct *work)
368{
369 struct mei_cl_device *device;
370
371 device = container_of(work, struct mei_cl_device, event_work);
372
373 if (device->event_cb)
374 device->event_cb(device, device->events, device->event_context);
375
376 device->events = 0;
377
378 /* Prepare for the next read */
379 mei_cl_read_start(device->cl);
380}
381
382int mei_cl_register_event_cb(struct mei_cl_device *device,
383 mei_cl_event_cb_t event_cb, void *context)
384{
385 if (device->event_cb)
386 return -EALREADY;
387
388 device->events = 0;
389 device->event_cb = event_cb;
390 device->event_context = context;
391 INIT_WORK(&device->event_work, mei_bus_event_work);
392
393 mei_cl_read_start(device->cl);
394
395 return 0;
396}
397EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
Samuel Ortizcf3baef2013-03-27 17:29:57 +0200398
Samuel Ortizaa6aef22013-03-27 17:29:59 +0200399void *mei_cl_get_drvdata(const struct mei_cl_device *device)
400{
401 return dev_get_drvdata(&device->dev);
402}
403EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
404
405void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
406{
407 dev_set_drvdata(&device->dev, data);
408}
409EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
410
Samuel Ortizcf3baef2013-03-27 17:29:57 +0200411void mei_cl_bus_rx_event(struct mei_cl *cl)
412{
413 struct mei_cl_device *device = cl->device;
414
415 if (!device || !device->event_cb)
416 return;
417
418 set_bit(MEI_CL_EVENT_RX, &device->events);
419
420 schedule_work(&device->event_work);
421}
422
423int __init mei_cl_bus_init(void)
424{
425 return bus_register(&mei_cl_bus_type);
426}
427
428void __exit mei_cl_bus_exit(void)
429{
430 bus_unregister(&mei_cl_bus_type);
431}