bus.c 11.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Intel Management Engine Interface (Intel MEI) Linux driver
 * Copyright (c) 2012-2013, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 */

#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
19
#include <linux/sched.h>
20 21 22 23 24 25 26 27
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/mei_cl_bus.h>

#include "mei_dev.h"
28
#include "client.h"
29 30 31 32 33 34

#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)

static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
{
35 36
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
37
	const struct mei_cl_device_id *id;
38 39
	const uuid_le *uuid;
	const char *name;
40

41
	if (!cldev)
42 43
		return 0;

44 45
	uuid = mei_me_cl_uuid(cldev->me_cl);
	name = cldev->name;
46

47
	if (!cldrv || !cldrv->id_table)
48 49
		return 0;

50
	id = cldrv->id_table;
51

G
Greg Kroah-Hartman 已提交
52
	while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) {
53

G
Greg Kroah-Hartman 已提交
54
		if (!uuid_le_cmp(*uuid, id->uuid)) {
55 56 57 58 59 60 61
			if (id->name[0]) {
				if (!strncmp(name, id->name, sizeof(id->name)))
					return 1;
			} else {
				return 1;
			}
		}
62 63 64 65 66 67 68 69 70

		id++;
	}

	return 0;
}

static int mei_cl_device_probe(struct device *dev)
{
71 72
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv;
73 74
	struct mei_cl_device_id id;

75
	if (!cldev)
76 77
		return 0;

78 79
	cldrv = to_mei_cl_driver(dev->driver);
	if (!cldrv || !cldrv->probe)
80 81 82 83
		return -ENODEV;

	dev_dbg(dev, "Device probe\n");

84
	strlcpy(id.name, cldev->name, sizeof(id.name));
85

86
	return cldrv->probe(cldev, &id);
87 88 89 90
}

static int mei_cl_device_remove(struct device *dev)
{
91 92
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv;
93

94
	if (!cldev || !dev->driver)
95 96
		return 0;

97 98 99
	if (cldev->event_cb) {
		cldev->event_cb = NULL;
		cancel_work_sync(&cldev->event_work);
100 101
	}

102 103
	cldrv = to_mei_cl_driver(dev->driver);
	if (!cldrv->remove) {
104 105 106 107 108
		dev->driver = NULL;

		return 0;
	}

109
	return cldrv->remove(cldev);
110 111
}

112 113 114
static ssize_t name_show(struct device *dev, struct device_attribute *a,
			     char *buf)
{
115
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
116 117
	size_t len;

118
	len = snprintf(buf, PAGE_SIZE, "%s", cldev->name);
119 120 121 122 123 124 125 126

	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
static DEVICE_ATTR_RO(name);

static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
			     char *buf)
{
127 128
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
129 130 131 132 133 134 135 136
	size_t len;

	len = snprintf(buf, PAGE_SIZE, "%pUl", uuid);

	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
static DEVICE_ATTR_RO(uuid);

137 138 139
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
			     char *buf)
{
140 141
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
142
	size_t len;
143

144
	len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":",
145
		cldev->name, MEI_CL_UUID_ARGS(uuid->b));
146 147 148

	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
149
static DEVICE_ATTR_RO(modalias);
150

151
static struct attribute *mei_cl_dev_attrs[] = {
152 153
	&dev_attr_name.attr,
	&dev_attr_uuid.attr,
154 155
	&dev_attr_modalias.attr,
	NULL,
156
};
157
ATTRIBUTE_GROUPS(mei_cl_dev);
158 159 160

static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
{
161 162
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
163

164 165 166
	if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid))
		return -ENOMEM;

167
	if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name))
168 169
		return -ENOMEM;

170
	if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":",
171
		cldev->name, MEI_CL_UUID_ARGS(uuid->b)))
172 173 174 175 176 177 178
		return -ENOMEM;

	return 0;
}

static struct bus_type mei_cl_bus_type = {
	.name		= "mei",
179
	.dev_groups	= mei_cl_dev_groups,
180 181 182 183 184 185 186 187
	.match		= mei_cl_device_match,
	.probe		= mei_cl_device_probe,
	.remove		= mei_cl_device_remove,
	.uevent		= mei_cl_uevent,
};

static void mei_cl_dev_release(struct device *dev)
{
188
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
189

190
	if (!cldev)
191 192
		return;

193 194
	mei_me_cl_put(cldev->me_cl);
	kfree(cldev);
195 196 197 198 199 200
}

static struct device_type mei_cl_device_type = {
	.release	= mei_cl_dev_release,
};

201
struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus,
202
					 uuid_le uuid)
203
{
204
	struct mei_cl *cl;
205

206 207 208
	list_for_each_entry(cl, &bus->device_list, device_link) {
		if (cl->cldev && cl->cldev->me_cl &&
		    !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl)))
209 210 211 212 213
			return cl;
	}

	return NULL;
}
214

215
struct mei_cl_device *mei_cl_add_device(struct mei_device *bus,
216 217
					struct mei_me_client *me_cl,
					struct mei_cl *cl,
218
					char *name)
219
{
220
	struct mei_cl_device *cldev;
221 222
	int status;

223 224
	cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
	if (!cldev)
225 226
		return NULL;

227 228 229
	cldev->me_cl = mei_me_cl_get(me_cl);
	if (!cldev->me_cl) {
		kfree(cldev);
230 231
		return NULL;
	}
232

233 234 235 236
	cldev->cl = cl;
	cldev->dev.parent = bus->dev;
	cldev->dev.bus = &mei_cl_bus_type;
	cldev->dev.type = &mei_cl_device_type;
237

238
	strlcpy(cldev->name, name, sizeof(cldev->name));
239

240
	dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl));
241

242
	status = device_register(&cldev->dev);
243
	if (status) {
244 245 246
		dev_err(bus->dev, "Failed to register MEI device\n");
		mei_me_cl_put(cldev->me_cl);
		kfree(cldev);
247 248 249
		return NULL;
	}

250
	cl->cldev = cldev;
251

252
	dev_dbg(&cldev->dev, "client %s registered\n", name);
253

254
	return cldev;
255 256 257
}
EXPORT_SYMBOL_GPL(mei_cl_add_device);

258
void mei_cl_remove_device(struct mei_cl_device *cldev)
259
{
260
	device_unregister(&cldev->dev);
261 262
}
EXPORT_SYMBOL_GPL(mei_cl_remove_device);
263

264
int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner)
265 266 267
{
	int err;

268 269 270
	cldrv->driver.name = cldrv->name;
	cldrv->driver.owner = owner;
	cldrv->driver.bus = &mei_cl_bus_type;
271

272
	err = driver_register(&cldrv->driver);
273 274 275
	if (err)
		return err;

276
	pr_debug("mei: driver [%s] registered\n", cldrv->driver.name);
277 278 279 280 281

	return 0;
}
EXPORT_SYMBOL_GPL(__mei_cl_driver_register);

282
void mei_cl_driver_unregister(struct mei_cl_driver *cldrv)
283
{
284
	driver_unregister(&cldrv->driver);
285

286
	pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name);
287 288
}
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
289

290
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
291
			bool blocking)
292
{
293
	struct mei_device *bus;
294
	struct mei_cl_cb *cb = NULL;
295
	ssize_t rets;
296 297 298 299

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

300
	bus = cl->dev;
T
Tomas Winkler 已提交
301

302
	mutex_lock(&bus->device_lock);
303
	if (!mei_cl_is_connected(cl)) {
304 305 306
		rets = -ENODEV;
		goto out;
	}
307

T
Tomas Winkler 已提交
308
	/* Check if we have an ME client device */
309
	if (!mei_me_cl_is_active(cl->me_cl)) {
310 311 312
		rets = -ENOTTY;
		goto out;
	}
T
Tomas Winkler 已提交
313

314
	if (length > mei_cl_mtu(cl)) {
315 316 317
		rets = -EFBIG;
		goto out;
	}
T
Tomas Winkler 已提交
318

319
	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
320 321 322 323
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}
324

325
	memcpy(cb->buf.data, buf, length);
326

T
Tomas Winkler 已提交
327
	rets = mei_cl_write(cl, cb, blocking);
328

329
out:
330
	mutex_unlock(&bus->device_lock);
T
Tomas Winkler 已提交
331 332
	if (rets < 0)
		mei_io_cb_free(cb);
333

T
Tomas Winkler 已提交
334
	return rets;
335 336
}

337
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
338
{
339
	struct mei_device *bus;
340 341
	struct mei_cl_cb *cb;
	size_t r_length;
342
	ssize_t rets;
343 344 345 346

	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

347
	bus = cl->dev;
348

349
	mutex_lock(&bus->device_lock);
350

T
Tomas Winkler 已提交
351 352 353 354 355 356 357
	cb = mei_cl_read_cb(cl, NULL);
	if (cb)
		goto copy;

	rets = mei_cl_read_start(cl, length, NULL);
	if (rets && rets != -EBUSY)
		goto out;
358

T
Tomas Winkler 已提交
359
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
360

361
		mutex_unlock(&bus->device_lock);
362 363

		if (wait_event_interruptible(cl->rx_wait,
T
Tomas Winkler 已提交
364
				(!list_empty(&cl->rd_completed)) ||
365
				(!mei_cl_is_connected(cl)))) {
366

367 368 369 370 371
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

372
		mutex_lock(&bus->device_lock);
373

374
		if (!mei_cl_is_connected(cl)) {
T
Tomas Winkler 已提交
375 376 377 378
			rets = -EBUSY;
			goto out;
		}
	}
379

T
Tomas Winkler 已提交
380 381
	cb = mei_cl_read_cb(cl, NULL);
	if (!cb) {
382
		rets = 0;
383 384 385
		goto out;
	}

T
Tomas Winkler 已提交
386
copy:
387 388 389 390 391
	if (cb->status) {
		rets = cb->status;
		goto free;
	}

392
	r_length = min_t(size_t, length, cb->buf_idx);
393
	memcpy(buf, cb->buf.data, r_length);
394
	rets = r_length;
395

396
free:
397 398
	mei_io_cb_free(cb);
out:
399
	mutex_unlock(&bus->device_lock);
400

401
	return rets;
402 403
}

404
ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
405
{
406
	struct mei_cl *cl = cldev->cl;
407

408 409
	if (cl == NULL)
		return -ENODEV;
410

411
	return __mei_cl_send(cl, buf, length, 1);
412 413 414
}
EXPORT_SYMBOL_GPL(mei_cl_send);

415
ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
416
{
417
	struct mei_cl *cl = cldev->cl;
418

419 420
	if (cl == NULL)
		return -ENODEV;
421 422 423 424 425 426 427

	return __mei_cl_recv(cl, buf, length);
}
EXPORT_SYMBOL_GPL(mei_cl_recv);

static void mei_bus_event_work(struct work_struct *work)
{
428
	struct mei_cl_device *cldev;
429

430
	cldev = container_of(work, struct mei_cl_device, event_work);
431

432 433
	if (cldev->event_cb)
		cldev->event_cb(cldev, cldev->events, cldev->event_context);
434

435
	cldev->events = 0;
436 437

	/* Prepare for the next read */
438
	mei_cl_read_start(cldev->cl, 0, NULL);
439 440
}

441
int mei_cl_register_event_cb(struct mei_cl_device *cldev,
442 443
			  mei_cl_event_cb_t event_cb, void *context)
{
444
	if (cldev->event_cb)
445 446
		return -EALREADY;

447 448 449 450
	cldev->events = 0;
	cldev->event_cb = event_cb;
	cldev->event_context = context;
	INIT_WORK(&cldev->event_work, mei_bus_event_work);
451

452
	mei_cl_read_start(cldev->cl, 0, NULL);
453 454 455 456

	return 0;
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
457

458
void *mei_cl_get_drvdata(const struct mei_cl_device *cldev)
459
{
460
	return dev_get_drvdata(&cldev->dev);
461 462 463
}
EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);

464
void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data)
465
{
466
	dev_set_drvdata(&cldev->dev, data);
467 468 469
}
EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);

470
int mei_cl_enable_device(struct mei_cl_device *cldev)
471 472
{
	int err;
473 474
	struct mei_device *bus;
	struct mei_cl *cl = cldev->cl;
475 476 477 478

	if (cl == NULL)
		return -ENODEV;

479
	bus = cl->dev;
480

481
	mutex_lock(&bus->device_lock);
482

T
Tomas Winkler 已提交
483
	if (mei_cl_is_connected(cl)) {
484 485
		mutex_unlock(&bus->device_lock);
		dev_warn(bus->dev, "Already connected");
T
Tomas Winkler 已提交
486 487 488
		return -EBUSY;
	}

489
	err = mei_cl_connect(cl, cldev->me_cl, NULL);
490
	if (err < 0) {
491 492
		mutex_unlock(&bus->device_lock);
		dev_err(bus->dev, "Could not connect to the ME client");
493 494 495 496

		return err;
	}

497
	mutex_unlock(&bus->device_lock);
498

499 500
	if (cldev->event_cb)
		mei_cl_read_start(cldev->cl, 0, NULL);
501

502
	return 0;
503 504 505
}
EXPORT_SYMBOL_GPL(mei_cl_enable_device);

506
int mei_cl_disable_device(struct mei_cl_device *cldev)
507 508
{
	int err;
509 510
	struct mei_device *bus;
	struct mei_cl *cl = cldev->cl;
511 512 513 514

	if (cl == NULL)
		return -ENODEV;

515
	bus = cl->dev;
516

517
	cldev->event_cb = NULL;
518

519
	mutex_lock(&bus->device_lock);
520

521
	if (!mei_cl_is_connected(cl)) {
522
		dev_err(bus->dev, "Already disconnected");
523 524
		err = 0;
		goto out;
525 526 527 528
	}

	err = mei_cl_disconnect(cl);
	if (err < 0) {
529
		dev_err(bus->dev, "Could not disconnect from the ME client");
530
		goto out;
531 532 533
	}

	/* Flush queues and remove any pending read */
T
Tomas Winkler 已提交
534
	mei_cl_flush_queues(cl, NULL);
535

536
out:
537
	mutex_unlock(&bus->device_lock);
538
	return err;
539 540 541 542

}
EXPORT_SYMBOL_GPL(mei_cl_disable_device);

543 544
void mei_cl_bus_rx_event(struct mei_cl *cl)
{
545
	struct mei_cl_device *cldev = cl->cldev;
546

547
	if (!cldev || !cldev->event_cb)
548 549
		return;

550
	set_bit(MEI_CL_EVENT_RX, &cldev->events);
551

552
	schedule_work(&cldev->event_work);
553 554 555 556 557 558 559 560 561 562 563
}

int __init mei_cl_bus_init(void)
{
	return bus_register(&mei_cl_bus_type);
}

void __exit mei_cl_bus_exit(void)
{
	bus_unregister(&mei_cl_bus_type);
}