blob: 16c7fff5054996c5d40608aa2820c3dd798da1d1 [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
143struct mei_cl_device *mei_cl_add_device(struct mei_device *mei_device,
144 uuid_le uuid, char *name)
145{
146 struct mei_cl_device *device;
147 int status;
148
149 device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
150 if (!device)
151 return NULL;
152
153 device->dev.parent = &mei_device->pdev->dev;
154 device->dev.bus = &mei_cl_bus_type;
155 device->dev.type = &mei_cl_device_type;
156
157 dev_set_name(&device->dev, "%s", name);
158
159 status = device_register(&device->dev);
160 if (status)
161 goto out_err;
162
163 dev_dbg(&device->dev, "client %s registered\n", name);
164
165 return device;
166
167out_err:
168 dev_err(device->dev.parent, "Failed to register MEI client\n");
169
170 kfree(device);
171
172 return NULL;
173}
174EXPORT_SYMBOL_GPL(mei_cl_add_device);
175
176void mei_cl_remove_device(struct mei_cl_device *device)
177{
178 device_unregister(&device->dev);
179}
180EXPORT_SYMBOL_GPL(mei_cl_remove_device);
Samuel Ortiz333e4ee2013-03-27 17:29:54 +0200181
182int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
183{
184 int err;
185
186 driver->driver.name = driver->name;
187 driver->driver.owner = owner;
188 driver->driver.bus = &mei_cl_bus_type;
189
190 err = driver_register(&driver->driver);
191 if (err)
192 return err;
193
194 pr_debug("mei: driver [%s] registered\n", driver->driver.name);
195
196 return 0;
197}
198EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
199
200void mei_cl_driver_unregister(struct mei_cl_driver *driver)
201{
202 driver_unregister(&driver->driver);
203
204 pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
205}
206EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
Samuel Ortiz3e833292013-03-27 17:29:55 +0200207
208int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
209{
210 struct mei_device *dev;
211 struct mei_msg_hdr mei_hdr;
212 struct mei_cl_cb *cb;
213 int me_cl_id, err;
214
215 if (WARN_ON(!cl || !cl->dev))
216 return -ENODEV;
217
218 if (cl->state != MEI_FILE_CONNECTED)
219 return -ENODEV;
220
221 cb = mei_io_cb_init(cl, NULL);
222 if (!cb)
223 return -ENOMEM;
224
225 err = mei_io_cb_alloc_req_buf(cb, length);
226 if (err < 0) {
227 mei_io_cb_free(cb);
228 return err;
229 }
230
231 memcpy(cb->request_buffer.data, buf, length);
232 cb->fop_type = MEI_FOP_WRITE;
233
234 dev = cl->dev;
235
236 mutex_lock(&dev->device_lock);
237
238 /* Check if we have an ME client device */
239 me_cl_id = mei_me_cl_by_id(dev, cl->me_client_id);
240 if (me_cl_id == dev->me_clients_num) {
241 err = -ENODEV;
242 goto out_err;
243 }
244
245 if (length > dev->me_clients[me_cl_id].props.max_msg_length) {
246 err = -EINVAL;
247 goto out_err;
248 }
249
250 err = mei_cl_flow_ctrl_creds(cl);
251 if (err < 0)
252 goto out_err;
253
254 /* Host buffer is not ready, we queue the request */
255 if (err == 0 || !dev->hbuf_is_ready) {
256 cb->buf_idx = 0;
257 mei_hdr.msg_complete = 0;
258 cl->writing_state = MEI_WRITING;
259 list_add_tail(&cb->list, &dev->write_list.list);
260
261 mutex_unlock(&dev->device_lock);
262
263 return length;
264 }
265
266 dev->hbuf_is_ready = false;
267
268 /* Check for a maximum length */
269 if (length > mei_hbuf_max_len(dev)) {
270 mei_hdr.length = mei_hbuf_max_len(dev);
271 mei_hdr.msg_complete = 0;
272 } else {
273 mei_hdr.length = length;
274 mei_hdr.msg_complete = 1;
275 }
276
277 mei_hdr.host_addr = cl->host_client_id;
278 mei_hdr.me_addr = cl->me_client_id;
279 mei_hdr.reserved = 0;
280
281 if (mei_write_message(dev, &mei_hdr, buf)) {
282 err = -EIO;
283 goto out_err;
284 }
285
286 cl->writing_state = MEI_WRITING;
287 cb->buf_idx = mei_hdr.length;
288
289 if (!mei_hdr.msg_complete) {
290 list_add_tail(&cb->list, &dev->write_list.list);
291 } else {
292 if (mei_cl_flow_ctrl_reduce(cl)) {
293 err = -EIO;
294 goto out_err;
295 }
296
297 list_add_tail(&cb->list, &dev->write_waiting_list.list);
298 }
299
300 mutex_unlock(&dev->device_lock);
301
302 return mei_hdr.length;
303
304out_err:
305 mutex_unlock(&dev->device_lock);
306 mei_io_cb_free(cb);
307
308 return err;
309}
310
311int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
312{
313 struct mei_device *dev;
314 struct mei_cl_cb *cb;
315 size_t r_length;
316 int err;
317
318 if (WARN_ON(!cl || !cl->dev))
319 return -ENODEV;
320
321 dev = cl->dev;
322
323 mutex_lock(&dev->device_lock);
324
325 if (!cl->read_cb) {
326 err = mei_cl_read_start(cl);
327 if (err < 0) {
328 mutex_unlock(&dev->device_lock);
329 return err;
330 }
331 }
332
333 if (cl->reading_state != MEI_READ_COMPLETE &&
334 !waitqueue_active(&cl->rx_wait)) {
335 mutex_unlock(&dev->device_lock);
336
337 if (wait_event_interruptible(cl->rx_wait,
338 (MEI_READ_COMPLETE == cl->reading_state))) {
339 if (signal_pending(current))
340 return -EINTR;
341 return -ERESTARTSYS;
342 }
343
344 mutex_lock(&dev->device_lock);
345 }
346
347 cb = cl->read_cb;
348
349 if (cl->reading_state != MEI_READ_COMPLETE) {
350 r_length = 0;
351 goto out;
352 }
353
354 r_length = min_t(size_t, length, cb->buf_idx);
355
356 memcpy(buf, cb->response_buffer.data, r_length);
357
358 mei_io_cb_free(cb);
359 cl->reading_state = MEI_IDLE;
360 cl->read_cb = NULL;
361
362out:
363 mutex_unlock(&dev->device_lock);
364
365 return r_length;
366}
367
368int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
369{
370 struct mei_cl *cl = NULL;
371
372 /* TODO: hook between mei_bus_client and mei_cl */
373
374 if (device->ops && device->ops->send)
375 return device->ops->send(device, buf, length);
376
377 return __mei_cl_send(cl, buf, length);
378}
379EXPORT_SYMBOL_GPL(mei_cl_send);
380
381int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
382{
383 struct mei_cl *cl = NULL;
384
385 /* TODO: hook between mei_bus_client and mei_cl */
386
387 if (device->ops && device->ops->recv)
388 return device->ops->recv(device, buf, length);
389
390 return __mei_cl_recv(cl, buf, length);
391}
392EXPORT_SYMBOL_GPL(mei_cl_recv);
393
394static void mei_bus_event_work(struct work_struct *work)
395{
396 struct mei_cl_device *device;
397
398 device = container_of(work, struct mei_cl_device, event_work);
399
400 if (device->event_cb)
401 device->event_cb(device, device->events, device->event_context);
402
403 device->events = 0;
404
405 /* Prepare for the next read */
406 mei_cl_read_start(device->cl);
407}
408
409int mei_cl_register_event_cb(struct mei_cl_device *device,
410 mei_cl_event_cb_t event_cb, void *context)
411{
412 if (device->event_cb)
413 return -EALREADY;
414
415 device->events = 0;
416 device->event_cb = event_cb;
417 device->event_context = context;
418 INIT_WORK(&device->event_work, mei_bus_event_work);
419
420 mei_cl_read_start(device->cl);
421
422 return 0;
423}
424EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);