bus.c 13.2 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

#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)

33 34 35 36 37 38 39 40 41 42 43 44
/**
 * __mei_cl_send - internal client send (write)
 *
 * @cl: host client
 * @buf: buffer to send
 * @length: buffer length
 * @blocking: wait for write completion
 *
 * Return: written size bytes or < 0 on error
 */
ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
			bool blocking)
45
{
46 47 48
	struct mei_device *bus;
	struct mei_cl_cb *cb = NULL;
	ssize_t rets;
49

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

53
	bus = cl->dev;
54

55 56 57 58 59
	mutex_lock(&bus->device_lock);
	if (!mei_cl_is_connected(cl)) {
		rets = -ENODEV;
		goto out;
	}
60

61 62 63 64 65
	/* Check if we have an ME client device */
	if (!mei_me_cl_is_active(cl->me_cl)) {
		rets = -ENOTTY;
		goto out;
	}
66

67 68 69 70
	if (length > mei_cl_mtu(cl)) {
		rets = -EFBIG;
		goto out;
	}
71

72 73 74 75
	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
	if (!cb) {
		rets = -ENOMEM;
		goto out;
76 77
	}

78 79 80 81 82 83 84 85 86 87
	memcpy(cb->buf.data, buf, length);

	rets = mei_cl_write(cl, cb, blocking);

out:
	mutex_unlock(&bus->device_lock);
	if (rets < 0)
		mei_io_cb_free(cb);

	return rets;
88 89
}

90 91 92 93 94 95 96 97 98 99
/**
 * __mei_cl_recv - internal client receive (read)
 *
 * @cl: host client
 * @buf: buffer to send
 * @length: buffer length
 *
 * Return: read size in bytes of < 0 on error
 */
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
100
{
101 102 103 104
	struct mei_device *bus;
	struct mei_cl_cb *cb;
	size_t r_length;
	ssize_t rets;
105

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

109
	bus = cl->dev;
110

111
	mutex_lock(&bus->device_lock);
112

113 114 115
	cb = mei_cl_read_cb(cl, NULL);
	if (cb)
		goto copy;
116

117 118 119
	rets = mei_cl_read_start(cl, length, NULL);
	if (rets && rets != -EBUSY)
		goto out;
120

121 122
	/* wait on event only if there is no other waiter */
	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
123

124
		mutex_unlock(&bus->device_lock);
125

126 127 128
		if (wait_event_interruptible(cl->rx_wait,
				(!list_empty(&cl->rd_completed)) ||
				(!mei_cl_is_connected(cl)))) {
129

130 131 132 133 134 135 136 137 138 139 140
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&bus->device_lock);

		if (!mei_cl_is_connected(cl)) {
			rets = -EBUSY;
			goto out;
		}
141 142
	}

143 144 145 146 147
	cb = mei_cl_read_cb(cl, NULL);
	if (!cb) {
		rets = 0;
		goto out;
	}
148

149 150 151 152 153
copy:
	if (cb->status) {
		rets = cb->status;
		goto free;
	}
154

155 156 157
	r_length = min_t(size_t, length, cb->buf_idx);
	memcpy(buf, cb->buf.data, r_length);
	rets = r_length;
158

159 160 161 162 163 164
free:
	mei_io_cb_free(cb);
out:
	mutex_unlock(&bus->device_lock);

	return rets;
165 166
}

167 168 169 170 171 172 173 174 175 176
/**
 * mei_cl_send - me device send  (write)
 *
 * @cldev: me client device
 * @buf: buffer to send
 * @length: buffer length
 *
 * Return: written size in bytes or < 0 on error
 */
ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
177
{
178
	struct mei_cl *cl = cldev->cl;
179

180 181
	if (cl == NULL)
		return -ENODEV;
182

183
	return __mei_cl_send(cl, buf, length, 1);
184
}
185
EXPORT_SYMBOL_GPL(mei_cl_send);
186

187 188 189 190 191 192 193 194 195 196
/**
 * mei_cl_recv - client receive (read)
 *
 * @cldev: me client device
 * @buf: buffer to send
 * @length: buffer length
 *
 * Return: read size in bytes of < 0 on error
 */
ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
197
{
198
	struct mei_cl *cl = cldev->cl;
199

200 201
	if (cl == NULL)
		return -ENODEV;
202

203
	return __mei_cl_recv(cl, buf, length);
204
}
205
EXPORT_SYMBOL_GPL(mei_cl_recv);
206

207 208 209 210 211 212 213
/**
 * mei_bus_event_work  - dispatch rx event for a bus device
 *    and schedule new work
 *
 * @work: work
 */
static void mei_bus_event_work(struct work_struct *work)
214
{
215
	struct mei_cl_device *cldev;
216

217
	cldev = container_of(work, struct mei_cl_device, event_work);
218

219 220
	if (cldev->event_cb)
		cldev->event_cb(cldev, cldev->events, cldev->event_context);
221

222
	cldev->events = 0;
223

224 225
	/* Prepare for the next read */
	mei_cl_read_start(cldev->cl, 0, NULL);
226 227
}

228 229 230 231 232 233
/**
 * mei_cl_bus_rx_event  - schedule rx evenet
 *
 * @cl: host client
 */
void mei_cl_bus_rx_event(struct mei_cl *cl)
234
{
235
	struct mei_cl_device *cldev = cl->cldev;
236

237
	if (!cldev || !cldev->event_cb)
238 239
		return;

240
	set_bit(MEI_CL_EVENT_RX, &cldev->events);
241

242
	schedule_work(&cldev->event_work);
243
}
244

245 246 247 248 249 250 251 252 253 254 255 256 257
/**
 * mei_cl_register_event_cb - register event callback
 *
 * @cldev: me client devices
 * @event_cb: callback function
 * @context: driver context data
 *
 * Return: 0 on success
 *         -EALREADY if an callback is already registered
 *         <0 on other errors
 */
int mei_cl_register_event_cb(struct mei_cl_device *cldev,
			  mei_cl_event_cb_t event_cb, void *context)
258
{
259 260
	if (cldev->event_cb)
		return -EALREADY;
261

262 263 264 265
	cldev->events = 0;
	cldev->event_cb = event_cb;
	cldev->event_context = context;
	INIT_WORK(&cldev->event_work, mei_bus_event_work);
266

267
	mei_cl_read_start(cldev->cl, 0, NULL);
268

269 270 271
	return 0;
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
272

273 274 275 276 277 278 279 280 281 282
/**
 * mei_cl_get_drvdata - driver data getter
 *
 * @cldev: mei client device
 *
 * Return: driver private data
 */
void *mei_cl_get_drvdata(const struct mei_cl_device *cldev)
{
	return dev_get_drvdata(&cldev->dev);
283
}
284
EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
285

286 287 288 289 290 291 292
/**
 * mei_cl_set_drvdata - driver data setter
 *
 * @cldev: mei client device
 * @data: data to store
 */
void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data)
293
{
294
	dev_set_drvdata(&cldev->dev, data);
295
}
296
EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
297

298 299 300 301 302 303 304 305 306
/**
 * mei_cl_enable_device - enable me client device
 *     create connection with me client
 *
 * @cldev: me client device
 *
 * Return: 0 on success and < 0 on error
 */
int mei_cl_enable_device(struct mei_cl_device *cldev)
307 308
{
	int err;
309 310
	struct mei_device *bus;
	struct mei_cl *cl = cldev->cl;
311

312 313
	if (cl == NULL)
		return -ENODEV;
314

315
	bus = cl->dev;
316

317
	mutex_lock(&bus->device_lock);
318

319 320 321 322 323
	if (mei_cl_is_connected(cl)) {
		mutex_unlock(&bus->device_lock);
		dev_warn(bus->dev, "Already connected");
		return -EBUSY;
	}
324

325 326 327 328
	err = mei_cl_connect(cl, cldev->me_cl, NULL);
	if (err < 0) {
		mutex_unlock(&bus->device_lock);
		dev_err(bus->dev, "Could not connect to the ME client");
329

330 331 332 333 334 335 336 337 338
		return err;
	}

	mutex_unlock(&bus->device_lock);

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

	return 0;
339
}
340
EXPORT_SYMBOL_GPL(mei_cl_enable_device);
341

342 343 344 345 346 347 348 349 350
/**
 * mei_cl_disable_device - disable me client device
 *     disconnect form the me client
 *
 * @cldev: me client device
 *
 * Return: 0 on success and < 0 on error
 */
int mei_cl_disable_device(struct mei_cl_device *cldev)
351
{
352
	int err;
353
	struct mei_device *bus;
354
	struct mei_cl *cl = cldev->cl;
355

356
	if (cl == NULL)
357 358
		return -ENODEV;

359
	bus = cl->dev;
T
Tomas Winkler 已提交
360

361
	cldev->event_cb = NULL;
362

363
	mutex_lock(&bus->device_lock);
T
Tomas Winkler 已提交
364

365 366 367
	if (!mei_cl_is_connected(cl)) {
		dev_err(bus->dev, "Already disconnected");
		err = 0;
368 369
		goto out;
	}
T
Tomas Winkler 已提交
370

371 372 373
	err = mei_cl_disconnect(cl);
	if (err < 0) {
		dev_err(bus->dev, "Could not disconnect from the ME client");
374 375
		goto out;
	}
376

377 378
	/* Flush queues and remove any pending read */
	mei_cl_flush_queues(cl, NULL);
379

380
out:
381
	mutex_unlock(&bus->device_lock);
382
	return err;
383 384

}
385
EXPORT_SYMBOL_GPL(mei_cl_disable_device);
386

387
static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
388
{
389 390 391 392 393
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
	const struct mei_cl_device_id *id;
	const uuid_le *uuid;
	const char *name;
394

395 396
	if (!cldev)
		return 0;
397

398 399
	uuid = mei_me_cl_uuid(cldev->me_cl);
	name = cldev->name;
400

401 402
	if (!cldrv || !cldrv->id_table)
		return 0;
403

404
	id = cldrv->id_table;
T
Tomas Winkler 已提交
405

406
	while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) {
407

408 409 410 411 412 413 414 415
		if (!uuid_le_cmp(*uuid, id->uuid)) {
			if (id->name[0]) {
				if (!strncmp(name, id->name, sizeof(id->name)))
					return 1;
			} else {
				return 1;
			}
		}
416

417 418
		id++;
	}
419

420 421
	return 0;
}
422

423 424 425 426 427
static int mei_cl_device_probe(struct device *dev)
{
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv;
	struct mei_cl_device_id id;
428

429 430
	if (!cldev)
		return 0;
431

432 433 434 435 436 437 438 439 440 441
	cldrv = to_mei_cl_driver(dev->driver);
	if (!cldrv || !cldrv->probe)
		return -ENODEV;

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

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

	return cldrv->probe(cldev, &id);
}
442

443 444 445 446
static int mei_cl_device_remove(struct device *dev)
{
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	struct mei_cl_driver *cldrv;
447

448 449 450 451 452 453
	if (!cldev || !dev->driver)
		return 0;

	if (cldev->event_cb) {
		cldev->event_cb = NULL;
		cancel_work_sync(&cldev->event_work);
454 455
	}

456 457 458
	cldrv = to_mei_cl_driver(dev->driver);
	if (!cldrv->remove) {
		dev->driver = NULL;
459

460 461
		return 0;
	}
462

463
	return cldrv->remove(cldev);
464 465
}

466 467
static ssize_t name_show(struct device *dev, struct device_attribute *a,
			     char *buf)
468
{
469 470
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	size_t len;
471

472
	len = snprintf(buf, PAGE_SIZE, "%s", cldev->name);
473

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

478 479
static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
			     char *buf)
480
{
481 482 483
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
	size_t len;
484

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

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

491 492
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
			     char *buf)
493
{
494 495 496
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
	size_t len;
497

498 499
	len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":",
		cldev->name, MEI_CL_UUID_ARGS(uuid->b));
500

501
	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
502
}
503
static DEVICE_ATTR_RO(modalias);
504

505 506 507 508 509 510 511 512 513
static struct attribute *mei_cl_dev_attrs[] = {
	&dev_attr_name.attr,
	&dev_attr_uuid.attr,
	&dev_attr_modalias.attr,
	NULL,
};
ATTRIBUTE_GROUPS(mei_cl_dev);

static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
514
{
515 516
	struct mei_cl_device *cldev = to_mei_cl_device(dev);
	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
517

518 519
	if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid))
		return -ENOMEM;
520

521 522 523 524 525 526
	if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name))
		return -ENOMEM;

	if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":",
		cldev->name, MEI_CL_UUID_ARGS(uuid->b)))
		return -ENOMEM;
527 528 529

	return 0;
}
530

531 532 533 534 535 536 537 538 539 540
static struct bus_type mei_cl_bus_type = {
	.name		= "mei",
	.dev_groups	= mei_cl_dev_groups,
	.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)
541
{
542 543 544 545 546 547 548
	struct mei_cl_device *cldev = to_mei_cl_device(dev);

	if (!cldev)
		return;

	mei_me_cl_put(cldev->me_cl);
	kfree(cldev);
549 550
}

551 552 553 554 555 556
static struct device_type mei_cl_device_type = {
	.release	= mei_cl_dev_release,
};

struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus,
					 uuid_le uuid)
557
{
558 559 560 561 562 563 564 565 566
	struct mei_cl *cl;

	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)))
			return cl;
	}

	return NULL;
567 568
}

569 570 571 572
struct mei_cl_device *mei_cl_add_device(struct mei_device *bus,
					struct mei_me_client *me_cl,
					struct mei_cl *cl,
					char *name)
573
{
574 575
	struct mei_cl_device *cldev;
	int status;
576

577 578 579
	cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
	if (!cldev)
		return NULL;
580

581 582 583 584 585
	cldev->me_cl = mei_me_cl_get(me_cl);
	if (!cldev->me_cl) {
		kfree(cldev);
		return NULL;
	}
586

587 588 589 590
	cldev->cl = cl;
	cldev->dev.parent = bus->dev;
	cldev->dev.bus = &mei_cl_bus_type;
	cldev->dev.type = &mei_cl_device_type;
591

592
	strlcpy(cldev->name, name, sizeof(cldev->name));
T
Tomas Winkler 已提交
593

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

596 597 598 599 600 601
	status = device_register(&cldev->dev);
	if (status) {
		dev_err(bus->dev, "Failed to register MEI device\n");
		mei_me_cl_put(cldev->me_cl);
		kfree(cldev);
		return NULL;
602 603
	}

604
	cl->cldev = cldev;
605

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

608
	return cldev;
609
}
610
EXPORT_SYMBOL_GPL(mei_cl_add_device);
611

612
void mei_cl_remove_device(struct mei_cl_device *cldev)
613
{
614 615 616
	device_unregister(&cldev->dev);
}
EXPORT_SYMBOL_GPL(mei_cl_remove_device);
617

618 619 620
int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner)
{
	int err;
621

622 623 624
	cldrv->driver.name = cldrv->name;
	cldrv->driver.owner = owner;
	cldrv->driver.bus = &mei_cl_bus_type;
625

626 627 628
	err = driver_register(&cldrv->driver);
	if (err)
		return err;
629

630
	pr_debug("mei: driver [%s] registered\n", cldrv->driver.name);
631

632
	return 0;
633
}
634
EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
635

636
void mei_cl_driver_unregister(struct mei_cl_driver *cldrv)
637
{
638
	driver_unregister(&cldrv->driver);
639

640
	pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name);
641
}
642
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
643 644 645 646 647 648 649 650 651 652

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);
}