You need to sign in or sign up before continuing.
bus.c 10.8 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
	mutex_lock(&dev->device_lock);
241
	if (!mei_cl_is_connected(cl)) {
242 243 244
		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_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
259 260 261 262
	if (!cb) {
		rets = -ENOMEM;
		goto out;
	}
263

264
	memcpy(cb->buf.data, buf, length);
265

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

268 269
out:
	mei_me_cl_put(me_cl);
270
	mutex_unlock(&dev->device_lock);
T
Tomas Winkler 已提交
271 272
	if (rets < 0)
		mei_io_cb_free(cb);
273

T
Tomas Winkler 已提交
274
	return rets;
275 276
}

277
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
278 279 280 281
{
	struct mei_device *dev;
	struct mei_cl_cb *cb;
	size_t r_length;
282
	ssize_t rets;
283 284 285 286 287 288 289 290

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

	dev = cl->dev;

	mutex_lock(&dev->device_lock);

T
Tomas Winkler 已提交
291 292 293 294 295 296 297
	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;
298

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

301 302 303
		mutex_unlock(&dev->device_lock);

		if (wait_event_interruptible(cl->rx_wait,
T
Tomas Winkler 已提交
304
				(!list_empty(&cl->rd_completed)) ||
305
				(!mei_cl_is_connected(cl)))) {
306

307 308 309 310 311 312 313
			if (signal_pending(current))
				return -EINTR;
			return -ERESTARTSYS;
		}

		mutex_lock(&dev->device_lock);

314
		if (!mei_cl_is_connected(cl)) {
T
Tomas Winkler 已提交
315 316 317 318
			rets = -EBUSY;
			goto out;
		}
	}
319

T
Tomas Winkler 已提交
320 321
	cb = mei_cl_read_cb(cl, NULL);
	if (!cb) {
322
		rets = 0;
323 324 325
		goto out;
	}

T
Tomas Winkler 已提交
326
copy:
327 328 329 330 331
	if (cb->status) {
		rets = cb->status;
		goto free;
	}

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

336
free:
337 338 339 340
	mei_io_cb_free(cb);
out:
	mutex_unlock(&dev->device_lock);

341
	return rets;
342 343
}

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

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

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

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

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

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

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

	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 */
394
	mei_cl_read_start(device->cl, 0, NULL);
395 396 397 398 399 400 401 402 403 404 405 406 407
}

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

408
	mei_cl_read_start(device->cl, 0, NULL);
409 410 411 412

	return 0;
}
EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
413

414 415 416 417 418 419 420 421 422 423 424 425
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);

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
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);
442
		dev_err(dev->dev, "Could not connect to the ME client");
443 444 445 446 447 448

		return err;
	}

	mutex_unlock(&dev->device_lock);

T
Tomas Winkler 已提交
449
	if (device->event_cb)
450
		mei_cl_read_start(device->cl, 0, NULL);
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469

	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;

470 471 472 473 474
	if (device->ops && device->ops->disable)
		device->ops->disable(device);

	device->event_cb = NULL;

475 476
	mutex_lock(&dev->device_lock);

477
	if (!mei_cl_is_connected(cl)) {
478
		dev_err(dev->dev, "Already disconnected");
479 480
		err = 0;
		goto out;
481 482 483 484 485 486
	}

	cl->state = MEI_FILE_DISCONNECTING;

	err = mei_cl_disconnect(cl);
	if (err < 0) {
487 488
		dev_err(dev->dev, "Could not disconnect from the ME client");
		goto out;
489 490 491
	}

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

494
out:
495
	mutex_unlock(&dev->device_lock);
496
	return err;
497 498 499 500

}
EXPORT_SYMBOL_GPL(mei_cl_disable_device);

501 502 503 504 505 506 507 508 509 510 511 512
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);
}

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
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);
}

529 530 531 532 533 534 535 536 537
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);
}