bus.c 11.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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

#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)
{
	struct mei_cl_device *device = to_mei_cl_device(dev);
	struct mei_cl_driver *driver = to_mei_cl_driver(drv);
	const struct mei_cl_device_id *id;

	if (!device)
		return 0;

	if (!driver || !driver->id_table)
		return 0;

	id = driver->id_table;

	while (id->name[0]) {
48
		if (!strncmp(dev_name(dev), id->name, sizeof(id->name)))
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
			return 1;

		id++;
	}

	return 0;
}

static int mei_cl_device_probe(struct device *dev)
{
	struct mei_cl_device *device = to_mei_cl_device(dev);
	struct mei_cl_driver *driver;
	struct mei_cl_device_id id;

	if (!device)
		return 0;

	driver = to_mei_cl_driver(dev->driver);
	if (!driver || !driver->probe)
		return -ENODEV;

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

72
	strlcpy(id.name, dev_name(dev), sizeof(id.name));
73 74 75 76 77 78 79 80 81 82 83 84

	return driver->probe(device, &id);
}

static int mei_cl_device_remove(struct device *dev)
{
	struct mei_cl_device *device = to_mei_cl_device(dev);
	struct mei_cl_driver *driver;

	if (!device || !dev->driver)
		return 0;

85 86 87 88 89
	if (device->event_cb) {
		device->event_cb = NULL;
		cancel_work_sync(&device->event_work);
	}

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
	driver = to_mei_cl_driver(dev->driver);
	if (!driver->remove) {
		dev->driver = NULL;

		return 0;
	}

	return driver->remove(device);
}

static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
			     char *buf)
{
	int len;

	len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));

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

111 112 113
static struct attribute *mei_cl_dev_attrs[] = {
	&dev_attr_modalias.attr,
	NULL,
114
};
115
ATTRIBUTE_GROUPS(mei_cl_dev);
116 117 118 119 120 121 122 123 124 125 126

static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
		return -ENOMEM;

	return 0;
}

static struct bus_type mei_cl_bus_type = {
	.name		= "mei",
127
	.dev_groups	= mei_cl_dev_groups,
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	.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)
{
	kfree(to_mei_cl_device(dev));
}

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

143
struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev,
144 145
						uuid_le uuid)
{
146
	struct mei_cl *cl;
147

148
	list_for_each_entry(cl, &dev->device_list, device_link) {
149
		if (!uuid_le_cmp(uuid, cl->cl_uuid))
150 151 152 153 154 155
			return cl;
	}

	return NULL;
}
struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
156 157
					uuid_le uuid, char *name,
					struct mei_cl_ops *ops)
158 159
{
	struct mei_cl_device *device;
160
	struct mei_cl *cl;
161 162
	int status;

163
	cl = mei_cl_bus_find_cl_by_uuid(dev, uuid);
164 165 166
	if (cl == NULL)
		return NULL;

167 168 169 170
	device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
	if (!device)
		return NULL;

171
	device->cl = cl;
172
	device->ops = ops;
173

174
	device->dev.parent = dev->dev;
175 176 177 178 179 180
	device->dev.bus = &mei_cl_bus_type;
	device->dev.type = &mei_cl_device_type;

	dev_set_name(&device->dev, "%s", name);

	status = device_register(&device->dev);
181
	if (status) {
182
		dev_err(dev->dev, "Failed to register MEI device\n");
183 184 185 186 187
		kfree(device);
		return NULL;
	}

	cl->device = device;
188 189 190 191 192 193 194 195 196 197 198 199

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

	return device;
}
EXPORT_SYMBOL_GPL(mei_cl_add_device);

void mei_cl_remove_device(struct mei_cl_device *device)
{
	device_unregister(&device->dev);
}
EXPORT_SYMBOL_GPL(mei_cl_remove_device);
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225

int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
{
	int err;

	driver->driver.name = driver->name;
	driver->driver.owner = owner;
	driver->driver.bus = &mei_cl_bus_type;

	err = driver_register(&driver->driver);
	if (err)
		return err;

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

	return 0;
}
EXPORT_SYMBOL_GPL(__mei_cl_driver_register);

void mei_cl_driver_unregister(struct mei_cl_driver *driver)
{
	driver_unregister(&driver->driver);

	pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
}
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
226

227
static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
228
			bool blocking)
229 230
{
	struct mei_device *dev;
231 232
	struct mei_me_client *me_cl = NULL;
	struct mei_cl_cb *cb = NULL;
233
	ssize_t rets;
234 235 236 237

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

T
Tomas Winkler 已提交
238 239
	dev = cl->dev;

240 241 242 243 244
	mutex_lock(&dev->device_lock);
	if (cl->state != MEI_FILE_CONNECTED) {
		rets = -ENODEV;
		goto out;
	}
245

T
Tomas Winkler 已提交
246
	/* Check if we have an ME client device */
247
	me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
248 249 250 251
	if (!me_cl) {
		rets = -ENOTTY;
		goto out;
	}
T
Tomas Winkler 已提交
252

253 254 255 256
	if (length > me_cl->props.max_msg_length) {
		rets = -EFBIG;
		goto out;
	}
T
Tomas Winkler 已提交
257

258
	cb = mei_io_cb_init(cl, NULL);
259 260 261 262
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}
263

264
	rets = mei_io_cb_alloc_buf(cb, length);
265 266
	if (rets < 0)
		goto out;
267

268
	memcpy(cb->buf.data, buf, length);
269

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

272 273
out:
	mei_me_cl_put(me_cl);
274
	mutex_unlock(&dev->device_lock);
T
Tomas Winkler 已提交
275 276
	if (rets < 0)
		mei_io_cb_free(cb);
277

T
Tomas Winkler 已提交
278
	return rets;
279 280
}

281
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
282 283 284 285
{
	struct mei_device *dev;
	struct mei_cl_cb *cb;
	size_t r_length;
286
	ssize_t rets;
287 288 289 290 291 292 293 294 295

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

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

	if (!cl->read_cb) {
296 297 298
		rets = mei_cl_read_start(cl, length);
		if (rets < 0)
			goto out;
299 300 301 302
	}

	if (cl->reading_state != MEI_READ_COMPLETE &&
	    !waitqueue_active(&cl->rx_wait)) {
303

304 305 306
		mutex_unlock(&dev->device_lock);

		if (wait_event_interruptible(cl->rx_wait,
307 308 309
				cl->reading_state == MEI_READ_COMPLETE  ||
				mei_cl_is_transitioning(cl))) {

310 311 312 313 314 315 316 317 318 319 320
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&dev->device_lock);
	}

	cb = cl->read_cb;

	if (cl->reading_state != MEI_READ_COMPLETE) {
321
		rets = 0;
322 323 324
		goto out;
	}

325 326 327 328 329
	if (cb->status) {
		rets = cb->status;
		goto free;
	}

330
	r_length = min_t(size_t, length, cb->buf_idx);
331
	memcpy(buf, cb->buf.data, r_length);
332
	rets = r_length;
333

334
free:
335 336 337 338 339 340 341
	mei_io_cb_free(cb);
	cl->reading_state = MEI_IDLE;
	cl->read_cb = NULL;

out:
	mutex_unlock(&dev->device_lock);

342
	return rets;
343 344
}

345
inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
346 347 348 349
{
	return ___mei_cl_send(cl, buf, length, 0);
}

350
inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
351 352 353 354
{
	return ___mei_cl_send(cl, buf, length, 1);
}

355
ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
356
{
357
	struct mei_cl *cl = device->cl;
358

359 360
	if (cl == NULL)
		return -ENODEV;
361 362 363 364 365 366 367 368

	if (device->ops && device->ops->send)
		return device->ops->send(device, buf, length);

	return __mei_cl_send(cl, buf, length);
}
EXPORT_SYMBOL_GPL(mei_cl_send);

369
ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
370
{
371
	struct mei_cl *cl =  device->cl;
372

373 374
	if (cl == NULL)
		return -ENODEV;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

	if (device->ops && device->ops->recv)
		return device->ops->recv(device, buf, length);

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

static void mei_bus_event_work(struct work_struct *work)
{
	struct mei_cl_device *device;

	device = container_of(work, struct mei_cl_device, event_work);

	if (device->event_cb)
		device->event_cb(device, device->events, device->event_context);

	device->events = 0;

	/* Prepare for the next read */
T
Tomas Winkler 已提交
395
	mei_cl_read_start(device->cl, 0);
396 397 398 399 400 401 402 403 404 405 406 407 408
}

int mei_cl_register_event_cb(struct mei_cl_device *device,
			  mei_cl_event_cb_t event_cb, void *context)
{
	if (device->event_cb)
		return -EALREADY;

	device->events = 0;
	device->event_cb = event_cb;
	device->event_context = context;
	INIT_WORK(&device->event_work, mei_bus_event_work);

T
Tomas Winkler 已提交
409
	mei_cl_read_start(device->cl, 0);
410 411 412 413

	return 0;
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
414

415 416 417 418 419 420 421 422 423 424 425 426
void *mei_cl_get_drvdata(const struct mei_cl_device *device)
{
	return dev_get_drvdata(&device->dev);
}
EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);

void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
{
	dev_set_drvdata(&device->dev, data);
}
EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
int mei_cl_enable_device(struct mei_cl_device *device)
{
	int err;
	struct mei_device *dev;
	struct mei_cl *cl = device->cl;

	if (cl == NULL)
		return -ENODEV;

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

	err = mei_cl_connect(cl, NULL);
	if (err < 0) {
		mutex_unlock(&dev->device_lock);
443
		dev_err(dev->dev, "Could not connect to the ME client");
444 445 446 447 448 449 450

		return err;
	}

	mutex_unlock(&dev->device_lock);

	if (device->event_cb && !cl->read_cb)
T
Tomas Winkler 已提交
451
		mei_cl_read_start(device->cl, 0);
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474

	if (!device->ops || !device->ops->enable)
		return 0;

	return device->ops->enable(device);
}
EXPORT_SYMBOL_GPL(mei_cl_enable_device);

int mei_cl_disable_device(struct mei_cl_device *device)
{
	int err;
	struct mei_device *dev;
	struct mei_cl *cl = device->cl;

	if (cl == NULL)
		return -ENODEV;

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

	if (cl->state != MEI_FILE_CONNECTED) {
		mutex_unlock(&dev->device_lock);
475
		dev_err(dev->dev, "Already disconnected");
476 477 478 479 480 481 482 483 484

		return 0;
	}

	cl->state = MEI_FILE_DISCONNECTING;

	err = mei_cl_disconnect(cl);
	if (err < 0) {
		mutex_unlock(&dev->device_lock);
485
		dev_err(dev->dev,
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
			"Could not disconnect from the ME client");

		return err;
	}

	/* Flush queues and remove any pending read */
	mei_cl_flush_queues(cl);

	if (cl->read_cb) {
		struct mei_cl_cb *cb = NULL;

		cb = mei_cl_find_read_cb(cl);
		/* Remove entry from read list */
		if (cb)
			list_del(&cb->list);

		cb = cl->read_cb;
		cl->read_cb = NULL;

		if (cb) {
			mei_io_cb_free(cb);
			cb = NULL;
		}
	}

511 512
	device->event_cb = NULL;

513 514 515 516 517 518 519 520 521
	mutex_unlock(&dev->device_lock);

	if (!device->ops || !device->ops->disable)
		return 0;

	return device->ops->disable(device);
}
EXPORT_SYMBOL_GPL(mei_cl_disable_device);

522 523 524 525 526 527 528 529 530 531 532 533
void mei_cl_bus_rx_event(struct mei_cl *cl)
{
	struct mei_cl_device *device = cl->device;

	if (!device || !device->event_cb)
		return;

	set_bit(MEI_CL_EVENT_RX, &device->events);

	schedule_work(&device->event_work);
}

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
void mei_cl_bus_remove_devices(struct mei_device *dev)
{
	struct mei_cl *cl, *next;

	mutex_lock(&dev->device_lock);
	list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
		if (cl->device)
			mei_cl_remove_device(cl->device);

		list_del(&cl->device_link);
		mei_cl_unlink(cl);
		kfree(cl);
	}
	mutex_unlock(&dev->device_lock);
}

550 551 552 553 554 555 556 557 558
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);
}