| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0  | 
|---|
| 1 | 2 |  /* | 
|---|
| 2 |  | - *  | 
|---|
 | 3 | + * Copyright (c) 2003-2020, Intel Corporation. All rights reserved.  | 
|---|
| 3 | 4 |   * Intel Management Engine Interface (Intel MEI) Linux driver | 
|---|
| 4 |  | - * Copyright (c) 2003-2012, Intel Corporation.  | 
|---|
| 5 |  | - *  | 
|---|
| 6 |  | - * This program is free software; you can redistribute it and/or modify it  | 
|---|
| 7 |  | - * under the terms and conditions of the GNU General Public License,  | 
|---|
| 8 |  | - * version 2, as published by the Free Software Foundation.  | 
|---|
| 9 |  | - *  | 
|---|
| 10 |  | - * This program is distributed in the hope it will be useful, but WITHOUT  | 
|---|
| 11 |  | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or  | 
|---|
| 12 |  | - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for  | 
|---|
| 13 |  | - * more details.  | 
|---|
| 14 |  | - *  | 
|---|
| 15 | 5 |   */ | 
|---|
| 16 | 6 |   | 
|---|
| 17 | 7 |  #include <linux/sched/signal.h> | 
|---|
| .. | .. | 
|---|
| 320 | 310 |  } | 
|---|
| 321 | 311 |   | 
|---|
| 322 | 312 |  /** | 
|---|
| 323 |  | - * mei_cl_cmp_id - tells if the clients are the same  | 
|---|
| 324 |  | - *  | 
|---|
| 325 |  | - * @cl1: host client 1  | 
|---|
| 326 |  | - * @cl2: host client 2  | 
|---|
| 327 |  | - *  | 
|---|
| 328 |  | - * Return: true  - if the clients has same host and me ids  | 
|---|
| 329 |  | - *         false - otherwise  | 
|---|
| 330 |  | - */  | 
|---|
| 331 |  | -static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,  | 
|---|
| 332 |  | -				const struct mei_cl *cl2)  | 
|---|
| 333 |  | -{  | 
|---|
| 334 |  | -	return cl1 && cl2 &&  | 
|---|
| 335 |  | -		(cl1->host_client_id == cl2->host_client_id) &&  | 
|---|
| 336 |  | -		(mei_cl_me_id(cl1) == mei_cl_me_id(cl2));  | 
|---|
| 337 |  | -}  | 
|---|
| 338 |  | -  | 
|---|
| 339 |  | -/**  | 
|---|
| 340 | 313 |   * mei_io_cb_free - free mei_cb_private related memory | 
|---|
| 341 | 314 |   * | 
|---|
| 342 | 315 |   * @cb: mei callback struct | 
|---|
| .. | .. | 
|---|
| 382 | 355 |  } | 
|---|
| 383 | 356 |   | 
|---|
| 384 | 357 |  /** | 
|---|
 | 358 | + * mei_cl_set_read_by_fp - set pending_read flag to vtag struct for given fp  | 
|---|
 | 359 | + *  | 
|---|
 | 360 | + * Locking: called under "dev->device_lock" lock  | 
|---|
 | 361 | + *  | 
|---|
 | 362 | + * @cl: mei client  | 
|---|
 | 363 | + * @fp: pointer to file structure  | 
|---|
 | 364 | + */  | 
|---|
 | 365 | +static void mei_cl_set_read_by_fp(const struct mei_cl *cl,  | 
|---|
 | 366 | +				  const struct file *fp)  | 
|---|
 | 367 | +{  | 
|---|
 | 368 | +	struct mei_cl_vtag *cl_vtag;  | 
|---|
 | 369 | +  | 
|---|
 | 370 | +	list_for_each_entry(cl_vtag, &cl->vtag_map, list) {  | 
|---|
 | 371 | +		if (cl_vtag->fp == fp) {  | 
|---|
 | 372 | +			cl_vtag->pending_read = true;  | 
|---|
 | 373 | +			return;  | 
|---|
 | 374 | +		}  | 
|---|
 | 375 | +	}  | 
|---|
 | 376 | +}  | 
|---|
 | 377 | +  | 
|---|
 | 378 | +/**  | 
|---|
| 385 | 379 |   * mei_io_cb_init - allocate and initialize io callback | 
|---|
| 386 | 380 |   * | 
|---|
| 387 | 381 |   * @cl: mei client | 
|---|
| .. | .. | 
|---|
| 396 | 390 |  { | 
|---|
| 397 | 391 |  	struct mei_cl_cb *cb; | 
|---|
| 398 | 392 |   | 
|---|
| 399 |  | -	cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);  | 
|---|
 | 393 | +	cb = kzalloc(sizeof(*cb), GFP_KERNEL);  | 
|---|
| 400 | 394 |  	if (!cb) | 
|---|
| 401 | 395 |  		return NULL; | 
|---|
| 402 | 396 |   | 
|---|
| .. | .. | 
|---|
| 405 | 399 |  	cb->cl = cl; | 
|---|
| 406 | 400 |  	cb->buf_idx = 0; | 
|---|
| 407 | 401 |  	cb->fop_type = type; | 
|---|
 | 402 | +	cb->vtag = 0;  | 
|---|
 | 403 | +  | 
|---|
| 408 | 404 |  	return cb; | 
|---|
| 409 | 405 |  } | 
|---|
| 410 | 406 |   | 
|---|
| .. | .. | 
|---|
| 420 | 416 |  	struct mei_cl_cb *cb, *next; | 
|---|
| 421 | 417 |   | 
|---|
| 422 | 418 |  	list_for_each_entry_safe(cb, next, head, list) { | 
|---|
| 423 |  | -		if (mei_cl_cmp_id(cl, cb->cl))  | 
|---|
 | 419 | +		if (cl == cb->cl) {  | 
|---|
| 424 | 420 |  			list_del_init(&cb->list); | 
|---|
 | 421 | +			if (cb->fop_type == MEI_FOP_READ)  | 
|---|
 | 422 | +				mei_io_cb_free(cb);  | 
|---|
 | 423 | +		}  | 
|---|
| 425 | 424 |  	} | 
|---|
| 426 | 425 |  } | 
|---|
| 427 | 426 |   | 
|---|
| .. | .. | 
|---|
| 430 | 429 |   * | 
|---|
| 431 | 430 |   * @head: An instance of our list structure | 
|---|
| 432 | 431 |   * @cl: host client | 
|---|
 | 432 | + * @fp: file pointer (matching cb file object), may be NULL  | 
|---|
| 433 | 433 |   */ | 
|---|
| 434 | 434 |  static void mei_io_tx_list_free_cl(struct list_head *head, | 
|---|
| 435 |  | -				   const struct mei_cl *cl)  | 
|---|
 | 435 | +				   const struct mei_cl *cl,  | 
|---|
 | 436 | +				   const struct file *fp)  | 
|---|
| 436 | 437 |  { | 
|---|
| 437 | 438 |  	struct mei_cl_cb *cb, *next; | 
|---|
| 438 | 439 |   | 
|---|
| 439 | 440 |  	list_for_each_entry_safe(cb, next, head, list) { | 
|---|
| 440 |  | -		if (mei_cl_cmp_id(cl, cb->cl))  | 
|---|
 | 441 | +		if (cl == cb->cl && (!fp || fp == cb->fp))  | 
|---|
| 441 | 442 |  			mei_tx_cb_dequeue(cb); | 
|---|
| 442 | 443 |  	} | 
|---|
| 443 | 444 |  } | 
|---|
| .. | .. | 
|---|
| 455 | 456 |  	list_for_each_entry_safe(cb, next, head, list) | 
|---|
| 456 | 457 |  		if (!fp || fp == cb->fp) | 
|---|
| 457 | 458 |  			mei_io_cb_free(cb); | 
|---|
 | 459 | +}  | 
|---|
 | 460 | +  | 
|---|
 | 461 | +/**  | 
|---|
 | 462 | + * mei_cl_free_pending - free pending cb  | 
|---|
 | 463 | + *  | 
|---|
 | 464 | + * @cl: host client  | 
|---|
 | 465 | + */  | 
|---|
 | 466 | +static void mei_cl_free_pending(struct mei_cl *cl)  | 
|---|
 | 467 | +{  | 
|---|
 | 468 | +	struct mei_cl_cb *cb;  | 
|---|
 | 469 | +  | 
|---|
 | 470 | +	cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);  | 
|---|
 | 471 | +	mei_io_cb_free(cb);  | 
|---|
| 458 | 472 |  } | 
|---|
| 459 | 473 |   | 
|---|
| 460 | 474 |  /** | 
|---|
| .. | .. | 
|---|
| 480 | 494 |  	if (length == 0) | 
|---|
| 481 | 495 |  		return cb; | 
|---|
| 482 | 496 |   | 
|---|
| 483 |  | -	cb->buf.data = kmalloc(length, GFP_KERNEL);  | 
|---|
 | 497 | +	cb->buf.data = kmalloc(roundup(length, MEI_SLOT_SIZE), GFP_KERNEL);  | 
|---|
| 484 | 498 |  	if (!cb->buf.data) { | 
|---|
| 485 | 499 |  		mei_io_cb_free(cb); | 
|---|
| 486 | 500 |  		return NULL; | 
|---|
| .. | .. | 
|---|
| 529 | 543 |   * | 
|---|
| 530 | 544 |   * Return: cb on success, NULL if cb is not found | 
|---|
| 531 | 545 |   */ | 
|---|
| 532 |  | -struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)  | 
|---|
 | 546 | +struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp)  | 
|---|
| 533 | 547 |  { | 
|---|
| 534 | 548 |  	struct mei_cl_cb *cb; | 
|---|
 | 549 | +	struct mei_cl_cb *ret_cb = NULL;  | 
|---|
| 535 | 550 |   | 
|---|
 | 551 | +	spin_lock(&cl->rd_completed_lock);  | 
|---|
| 536 | 552 |  	list_for_each_entry(cb, &cl->rd_completed, list) | 
|---|
| 537 |  | -		if (!fp || fp == cb->fp)  | 
|---|
| 538 |  | -			return cb;  | 
|---|
| 539 |  | -  | 
|---|
| 540 |  | -	return NULL;  | 
|---|
 | 553 | +		if (!fp || fp == cb->fp) {  | 
|---|
 | 554 | +			ret_cb = cb;  | 
|---|
 | 555 | +			break;  | 
|---|
 | 556 | +		}  | 
|---|
 | 557 | +	spin_unlock(&cl->rd_completed_lock);  | 
|---|
 | 558 | +	return ret_cb;  | 
|---|
| 541 | 559 |  } | 
|---|
| 542 | 560 |   | 
|---|
| 543 | 561 |  /** | 
|---|
| .. | .. | 
|---|
| 558 | 576 |  	dev = cl->dev; | 
|---|
| 559 | 577 |   | 
|---|
| 560 | 578 |  	cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | 
|---|
| 561 |  | -	mei_io_tx_list_free_cl(&cl->dev->write_list, cl);  | 
|---|
| 562 |  | -	mei_io_tx_list_free_cl(&cl->dev->write_waiting_list, cl);  | 
|---|
| 563 |  | -	mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl);  | 
|---|
| 564 |  | -	mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl);  | 
|---|
| 565 |  | -	mei_io_list_free_fp(&cl->rd_pending, fp);  | 
|---|
 | 579 | +	mei_io_tx_list_free_cl(&cl->dev->write_list, cl, fp);  | 
|---|
 | 580 | +	mei_io_tx_list_free_cl(&cl->dev->write_waiting_list, cl, fp);  | 
|---|
 | 581 | +	/* free pending and control cb only in final flush */  | 
|---|
 | 582 | +	if (!fp) {  | 
|---|
 | 583 | +		mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl);  | 
|---|
 | 584 | +		mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl);  | 
|---|
 | 585 | +		mei_cl_free_pending(cl);  | 
|---|
 | 586 | +	}  | 
|---|
 | 587 | +	spin_lock(&cl->rd_completed_lock);  | 
|---|
| 566 | 588 |  	mei_io_list_free_fp(&cl->rd_completed, fp); | 
|---|
 | 589 | +	spin_unlock(&cl->rd_completed_lock);  | 
|---|
| 567 | 590 |   | 
|---|
| 568 | 591 |  	return 0; | 
|---|
| 569 | 592 |  } | 
|---|
| .. | .. | 
|---|
| 576 | 599 |   */ | 
|---|
| 577 | 600 |  static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) | 
|---|
| 578 | 601 |  { | 
|---|
| 579 |  | -	memset(cl, 0, sizeof(struct mei_cl));  | 
|---|
 | 602 | +	memset(cl, 0, sizeof(*cl));  | 
|---|
| 580 | 603 |  	init_waitqueue_head(&cl->wait); | 
|---|
| 581 | 604 |  	init_waitqueue_head(&cl->rx_wait); | 
|---|
| 582 | 605 |  	init_waitqueue_head(&cl->tx_wait); | 
|---|
| 583 | 606 |  	init_waitqueue_head(&cl->ev_wait); | 
|---|
 | 607 | +	INIT_LIST_HEAD(&cl->vtag_map);  | 
|---|
 | 608 | +	spin_lock_init(&cl->rd_completed_lock);  | 
|---|
| 584 | 609 |  	INIT_LIST_HEAD(&cl->rd_completed); | 
|---|
| 585 | 610 |  	INIT_LIST_HEAD(&cl->rd_pending); | 
|---|
| 586 | 611 |  	INIT_LIST_HEAD(&cl->link); | 
|---|
| .. | .. | 
|---|
| 599 | 624 |  { | 
|---|
| 600 | 625 |  	struct mei_cl *cl; | 
|---|
| 601 | 626 |   | 
|---|
| 602 |  | -	cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);  | 
|---|
 | 627 | +	cl = kmalloc(sizeof(*cl), GFP_KERNEL);  | 
|---|
| 603 | 628 |  	if (!cl) | 
|---|
| 604 | 629 |  		return NULL; | 
|---|
| 605 | 630 |   | 
|---|
| .. | .. | 
|---|
| 695 | 720 |   | 
|---|
| 696 | 721 |  void mei_host_client_init(struct mei_device *dev) | 
|---|
| 697 | 722 |  { | 
|---|
| 698 |  | -	dev->dev_state = MEI_DEV_ENABLED;  | 
|---|
 | 723 | +	mei_set_devstate(dev, MEI_DEV_ENABLED);  | 
|---|
| 699 | 724 |  	dev->reset_count = 0; | 
|---|
| 700 | 725 |   | 
|---|
| 701 | 726 |  	schedule_work(&dev->bus_rescan_work); | 
|---|
| .. | .. | 
|---|
| 776 | 801 |  		return; | 
|---|
| 777 | 802 |   | 
|---|
| 778 | 803 |  	cl->state = MEI_FILE_DISCONNECTED; | 
|---|
| 779 |  | -	mei_io_tx_list_free_cl(&dev->write_list, cl);  | 
|---|
| 780 |  | -	mei_io_tx_list_free_cl(&dev->write_waiting_list, cl);  | 
|---|
 | 804 | +	mei_io_tx_list_free_cl(&dev->write_list, cl, NULL);  | 
|---|
 | 805 | +	mei_io_tx_list_free_cl(&dev->write_waiting_list, cl, NULL);  | 
|---|
| 781 | 806 |  	mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); | 
|---|
| 782 | 807 |  	mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); | 
|---|
| 783 | 808 |  	mei_cl_wake_all(cl); | 
|---|
| .. | .. | 
|---|
| 1253 | 1278 |  } | 
|---|
| 1254 | 1279 |   | 
|---|
| 1255 | 1280 |  /** | 
|---|
 | 1281 | + * mei_cl_vtag_alloc - allocate and fill the vtag structure  | 
|---|
 | 1282 | + *  | 
|---|
 | 1283 | + * @fp: pointer to file structure  | 
|---|
 | 1284 | + * @vtag: vm tag  | 
|---|
 | 1285 | + *  | 
|---|
 | 1286 | + * Return:  | 
|---|
 | 1287 | + * * Pointer to allocated struct - on success  | 
|---|
 | 1288 | + * * ERR_PTR(-ENOMEM) on memory allocation failure  | 
|---|
 | 1289 | + */  | 
|---|
 | 1290 | +struct mei_cl_vtag *mei_cl_vtag_alloc(struct file *fp, u8 vtag)  | 
|---|
 | 1291 | +{  | 
|---|
 | 1292 | +	struct mei_cl_vtag *cl_vtag;  | 
|---|
 | 1293 | +  | 
|---|
 | 1294 | +	cl_vtag = kzalloc(sizeof(*cl_vtag), GFP_KERNEL);  | 
|---|
 | 1295 | +	if (!cl_vtag)  | 
|---|
 | 1296 | +		return ERR_PTR(-ENOMEM);  | 
|---|
 | 1297 | +  | 
|---|
 | 1298 | +	INIT_LIST_HEAD(&cl_vtag->list);  | 
|---|
 | 1299 | +	cl_vtag->vtag = vtag;  | 
|---|
 | 1300 | +	cl_vtag->fp = fp;  | 
|---|
 | 1301 | +  | 
|---|
 | 1302 | +	return cl_vtag;  | 
|---|
 | 1303 | +}  | 
|---|
 | 1304 | +  | 
|---|
 | 1305 | +/**  | 
|---|
 | 1306 | + * mei_cl_fp_by_vtag - obtain the file pointer by vtag  | 
|---|
 | 1307 | + *  | 
|---|
 | 1308 | + * @cl: host client  | 
|---|
 | 1309 | + * @vtag: vm tag  | 
|---|
 | 1310 | + *  | 
|---|
 | 1311 | + * Return:  | 
|---|
 | 1312 | + * * A file pointer - on success  | 
|---|
 | 1313 | + * * ERR_PTR(-ENOENT) if vtag is not found in the client vtag list  | 
|---|
 | 1314 | + */  | 
|---|
 | 1315 | +const struct file *mei_cl_fp_by_vtag(const struct mei_cl *cl, u8 vtag)  | 
|---|
 | 1316 | +{  | 
|---|
 | 1317 | +	struct mei_cl_vtag *vtag_l;  | 
|---|
 | 1318 | +  | 
|---|
 | 1319 | +	list_for_each_entry(vtag_l, &cl->vtag_map, list)  | 
|---|
 | 1320 | +		if (vtag_l->vtag == vtag)  | 
|---|
 | 1321 | +			return vtag_l->fp;  | 
|---|
 | 1322 | +  | 
|---|
 | 1323 | +	return ERR_PTR(-ENOENT);  | 
|---|
 | 1324 | +}  | 
|---|
 | 1325 | +  | 
|---|
 | 1326 | +/**  | 
|---|
 | 1327 | + * mei_cl_reset_read_by_vtag - reset pending_read flag by given vtag  | 
|---|
 | 1328 | + *  | 
|---|
 | 1329 | + * @cl: host client  | 
|---|
 | 1330 | + * @vtag: vm tag  | 
|---|
 | 1331 | + */  | 
|---|
 | 1332 | +static void mei_cl_reset_read_by_vtag(const struct mei_cl *cl, u8 vtag)  | 
|---|
 | 1333 | +{  | 
|---|
 | 1334 | +	struct mei_cl_vtag *vtag_l;  | 
|---|
 | 1335 | +  | 
|---|
 | 1336 | +	list_for_each_entry(vtag_l, &cl->vtag_map, list) {  | 
|---|
 | 1337 | +		if (vtag_l->vtag == vtag) {  | 
|---|
 | 1338 | +			vtag_l->pending_read = false;  | 
|---|
 | 1339 | +			break;  | 
|---|
 | 1340 | +		}  | 
|---|
 | 1341 | +	}  | 
|---|
 | 1342 | +}  | 
|---|
 | 1343 | +  | 
|---|
 | 1344 | +/**  | 
|---|
 | 1345 | + * mei_cl_read_vtag_add_fc - add flow control for next pending reader  | 
|---|
 | 1346 | + *                           in the vtag list  | 
|---|
 | 1347 | + *  | 
|---|
 | 1348 | + * @cl: host client  | 
|---|
 | 1349 | + */  | 
|---|
 | 1350 | +static void mei_cl_read_vtag_add_fc(struct mei_cl *cl)  | 
|---|
 | 1351 | +{  | 
|---|
 | 1352 | +	struct mei_cl_vtag *cl_vtag;  | 
|---|
 | 1353 | +  | 
|---|
 | 1354 | +	list_for_each_entry(cl_vtag, &cl->vtag_map, list) {  | 
|---|
 | 1355 | +		if (cl_vtag->pending_read) {  | 
|---|
 | 1356 | +			if (mei_cl_enqueue_ctrl_wr_cb(cl,  | 
|---|
 | 1357 | +						      mei_cl_mtu(cl),  | 
|---|
 | 1358 | +						      MEI_FOP_READ,  | 
|---|
 | 1359 | +						      cl_vtag->fp))  | 
|---|
 | 1360 | +				cl->rx_flow_ctrl_creds++;  | 
|---|
 | 1361 | +			break;  | 
|---|
 | 1362 | +		}  | 
|---|
 | 1363 | +	}  | 
|---|
 | 1364 | +}  | 
|---|
 | 1365 | +  | 
|---|
 | 1366 | +/**  | 
|---|
 | 1367 | + * mei_cl_vt_support_check - check if client support vtags  | 
|---|
 | 1368 | + *  | 
|---|
 | 1369 | + * @cl: host client  | 
|---|
 | 1370 | + *  | 
|---|
 | 1371 | + * Return:  | 
|---|
 | 1372 | + * * 0 - supported, or not connected at all  | 
|---|
 | 1373 | + * * -EOPNOTSUPP - vtags are not supported by client  | 
|---|
 | 1374 | + */  | 
|---|
 | 1375 | +int mei_cl_vt_support_check(const struct mei_cl *cl)  | 
|---|
 | 1376 | +{  | 
|---|
 | 1377 | +	struct mei_device *dev = cl->dev;  | 
|---|
 | 1378 | +  | 
|---|
 | 1379 | +	if (!dev->hbm_f_vt_supported)  | 
|---|
 | 1380 | +		return -EOPNOTSUPP;  | 
|---|
 | 1381 | +  | 
|---|
 | 1382 | +	if (!cl->me_cl)  | 
|---|
 | 1383 | +		return 0;  | 
|---|
 | 1384 | +  | 
|---|
 | 1385 | +	return cl->me_cl->props.vt_supported ? 0 : -EOPNOTSUPP;  | 
|---|
 | 1386 | +}  | 
|---|
 | 1387 | +  | 
|---|
 | 1388 | +/**  | 
|---|
 | 1389 | + * mei_cl_add_rd_completed - add read completed callback to list with lock  | 
|---|
 | 1390 | + *                           and vtag check  | 
|---|
 | 1391 | + *  | 
|---|
 | 1392 | + * @cl: host client  | 
|---|
 | 1393 | + * @cb: callback block  | 
|---|
 | 1394 | + *  | 
|---|
 | 1395 | + */  | 
|---|
 | 1396 | +void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)  | 
|---|
 | 1397 | +{  | 
|---|
 | 1398 | +	const struct file *fp;  | 
|---|
 | 1399 | +  | 
|---|
 | 1400 | +	if (!mei_cl_vt_support_check(cl)) {  | 
|---|
 | 1401 | +		fp = mei_cl_fp_by_vtag(cl, cb->vtag);  | 
|---|
 | 1402 | +		if (IS_ERR(fp)) {  | 
|---|
 | 1403 | +			/* client already disconnected, discarding */  | 
|---|
 | 1404 | +			mei_io_cb_free(cb);  | 
|---|
 | 1405 | +			return;  | 
|---|
 | 1406 | +		}  | 
|---|
 | 1407 | +		cb->fp = fp;  | 
|---|
 | 1408 | +		mei_cl_reset_read_by_vtag(cl, cb->vtag);  | 
|---|
 | 1409 | +		mei_cl_read_vtag_add_fc(cl);  | 
|---|
 | 1410 | +	}  | 
|---|
 | 1411 | +  | 
|---|
 | 1412 | +	spin_lock(&cl->rd_completed_lock);  | 
|---|
 | 1413 | +	list_add_tail(&cb->list, &cl->rd_completed);  | 
|---|
 | 1414 | +	spin_unlock(&cl->rd_completed_lock);  | 
|---|
 | 1415 | +}  | 
|---|
 | 1416 | +  | 
|---|
 | 1417 | +/**  | 
|---|
 | 1418 | + * mei_cl_del_rd_completed - free read completed callback with lock  | 
|---|
 | 1419 | + *  | 
|---|
 | 1420 | + * @cl: host client  | 
|---|
 | 1421 | + * @cb: callback block  | 
|---|
 | 1422 | + *  | 
|---|
 | 1423 | + */  | 
|---|
 | 1424 | +void mei_cl_del_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)  | 
|---|
 | 1425 | +{  | 
|---|
 | 1426 | +	spin_lock(&cl->rd_completed_lock);  | 
|---|
 | 1427 | +	mei_io_cb_free(cb);  | 
|---|
 | 1428 | +	spin_unlock(&cl->rd_completed_lock);  | 
|---|
 | 1429 | +}  | 
|---|
 | 1430 | +  | 
|---|
 | 1431 | +/**  | 
|---|
| 1256 | 1432 |   *  mei_cl_notify_fop2req - convert fop to proper request | 
|---|
| 1257 | 1433 |   * | 
|---|
| 1258 | 1434 |   * @fop: client notification start response command | 
|---|
| .. | .. | 
|---|
| 1376 | 1552 |   | 
|---|
| 1377 | 1553 |  	mutex_unlock(&dev->device_lock); | 
|---|
| 1378 | 1554 |  	wait_event_timeout(cl->wait, | 
|---|
| 1379 |  | -			   cl->notify_en == request || !mei_cl_is_connected(cl),  | 
|---|
 | 1555 | +			   cl->notify_en == request ||  | 
|---|
 | 1556 | +			   cl->status ||  | 
|---|
 | 1557 | +			   !mei_cl_is_connected(cl),  | 
|---|
| 1380 | 1558 |  			   mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); | 
|---|
| 1381 | 1559 |  	mutex_lock(&dev->device_lock); | 
|---|
| 1382 | 1560 |   | 
|---|
| .. | .. | 
|---|
| 1505 | 1683 |  		return 0; | 
|---|
| 1506 | 1684 |   | 
|---|
| 1507 | 1685 |  	/* HW currently supports only one pending read */ | 
|---|
| 1508 |  | -	if (cl->rx_flow_ctrl_creds)  | 
|---|
 | 1686 | +	if (cl->rx_flow_ctrl_creds) {  | 
|---|
 | 1687 | +		mei_cl_set_read_by_fp(cl, fp);  | 
|---|
| 1509 | 1688 |  		return -EBUSY; | 
|---|
 | 1689 | +	}  | 
|---|
| 1510 | 1690 |   | 
|---|
| 1511 | 1691 |  	cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp); | 
|---|
| 1512 | 1692 |  	if (!cb) | 
|---|
| 1513 | 1693 |  		return -ENOMEM; | 
|---|
 | 1694 | +  | 
|---|
 | 1695 | +	mei_cl_set_read_by_fp(cl, fp);  | 
|---|
| 1514 | 1696 |   | 
|---|
| 1515 | 1697 |  	rets = pm_runtime_get(dev->dev); | 
|---|
| 1516 | 1698 |  	if (rets < 0 && rets != -EINPROGRESS) { | 
|---|
| .. | .. | 
|---|
| 1540 | 1722 |  	return rets; | 
|---|
| 1541 | 1723 |  } | 
|---|
| 1542 | 1724 |   | 
|---|
| 1543 |  | -/**  | 
|---|
| 1544 |  | - * mei_msg_hdr_init - initialize mei message header  | 
|---|
| 1545 |  | - *  | 
|---|
| 1546 |  | - * @mei_hdr: mei message header  | 
|---|
| 1547 |  | - * @cb: message callback structure  | 
|---|
| 1548 |  | - */  | 
|---|
| 1549 |  | -static void mei_msg_hdr_init(struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *cb)  | 
|---|
 | 1725 | +static inline u8 mei_ext_hdr_set_vtag(struct mei_ext_hdr *ext, u8 vtag)  | 
|---|
| 1550 | 1726 |  { | 
|---|
 | 1727 | +	ext->type = MEI_EXT_HDR_VTAG;  | 
|---|
 | 1728 | +	ext->ext_payload[0] = vtag;  | 
|---|
 | 1729 | +	ext->length = mei_data2slots(sizeof(*ext));  | 
|---|
 | 1730 | +	return ext->length;  | 
|---|
 | 1731 | +}  | 
|---|
 | 1732 | +  | 
|---|
 | 1733 | +/**  | 
|---|
 | 1734 | + * mei_msg_hdr_init - allocate and initialize mei message header  | 
|---|
 | 1735 | + *  | 
|---|
 | 1736 | + * @cb: message callback structure  | 
|---|
 | 1737 | + *  | 
|---|
 | 1738 | + * Return: a pointer to initialized header  | 
|---|
 | 1739 | + */  | 
|---|
 | 1740 | +static struct mei_msg_hdr *mei_msg_hdr_init(const struct mei_cl_cb *cb)  | 
|---|
 | 1741 | +{  | 
|---|
 | 1742 | +	size_t hdr_len;  | 
|---|
 | 1743 | +	struct mei_ext_meta_hdr *meta;  | 
|---|
 | 1744 | +	struct mei_ext_hdr *ext;  | 
|---|
 | 1745 | +	struct mei_msg_hdr *mei_hdr;  | 
|---|
 | 1746 | +	bool is_ext, is_vtag;  | 
|---|
 | 1747 | +  | 
|---|
 | 1748 | +	if (!cb)  | 
|---|
 | 1749 | +		return ERR_PTR(-EINVAL);  | 
|---|
 | 1750 | +  | 
|---|
 | 1751 | +	/* Extended header for vtag is attached only on the first fragment */  | 
|---|
 | 1752 | +	is_vtag = (cb->vtag && cb->buf_idx == 0);  | 
|---|
 | 1753 | +	is_ext = is_vtag;  | 
|---|
 | 1754 | +  | 
|---|
 | 1755 | +	/* Compute extended header size */  | 
|---|
 | 1756 | +	hdr_len = sizeof(*mei_hdr);  | 
|---|
 | 1757 | +  | 
|---|
 | 1758 | +	if (!is_ext)  | 
|---|
 | 1759 | +		goto setup_hdr;  | 
|---|
 | 1760 | +  | 
|---|
 | 1761 | +	hdr_len += sizeof(*meta);  | 
|---|
 | 1762 | +	if (is_vtag)  | 
|---|
 | 1763 | +		hdr_len += sizeof(*ext);  | 
|---|
 | 1764 | +  | 
|---|
 | 1765 | +setup_hdr:  | 
|---|
 | 1766 | +	mei_hdr = kzalloc(hdr_len, GFP_KERNEL);  | 
|---|
 | 1767 | +	if (!mei_hdr)  | 
|---|
 | 1768 | +		return ERR_PTR(-ENOMEM);  | 
|---|
 | 1769 | +  | 
|---|
| 1551 | 1770 |  	mei_hdr->host_addr = mei_cl_host_addr(cb->cl); | 
|---|
| 1552 | 1771 |  	mei_hdr->me_addr = mei_cl_me_id(cb->cl); | 
|---|
| 1553 |  | -	mei_hdr->length = 0;  | 
|---|
| 1554 |  | -	mei_hdr->reserved = 0;  | 
|---|
| 1555 |  | -	mei_hdr->msg_complete = 0;  | 
|---|
| 1556 |  | -	mei_hdr->dma_ring = 0;  | 
|---|
| 1557 | 1772 |  	mei_hdr->internal = cb->internal; | 
|---|
 | 1773 | +	mei_hdr->extended = is_ext;  | 
|---|
 | 1774 | +  | 
|---|
 | 1775 | +	if (!is_ext)  | 
|---|
 | 1776 | +		goto out;  | 
|---|
 | 1777 | +  | 
|---|
 | 1778 | +	meta = (struct mei_ext_meta_hdr *)mei_hdr->extension;  | 
|---|
 | 1779 | +	if (is_vtag) {  | 
|---|
 | 1780 | +		meta->count++;  | 
|---|
 | 1781 | +		meta->size += mei_ext_hdr_set_vtag(meta->hdrs, cb->vtag);  | 
|---|
 | 1782 | +	}  | 
|---|
 | 1783 | +out:  | 
|---|
 | 1784 | +	mei_hdr->length = hdr_len - sizeof(*mei_hdr);  | 
|---|
 | 1785 | +	return mei_hdr;  | 
|---|
| 1558 | 1786 |  } | 
|---|
| 1559 | 1787 |   | 
|---|
| 1560 | 1788 |  /** | 
|---|
| .. | .. | 
|---|
| 1572 | 1800 |  { | 
|---|
| 1573 | 1801 |  	struct mei_device *dev; | 
|---|
| 1574 | 1802 |  	struct mei_msg_data *buf; | 
|---|
| 1575 |  | -	struct mei_msg_hdr mei_hdr;  | 
|---|
| 1576 |  | -	size_t hdr_len = sizeof(mei_hdr);  | 
|---|
| 1577 |  | -	size_t len;  | 
|---|
| 1578 |  | -	size_t hbuf_len;  | 
|---|
 | 1803 | +	struct mei_msg_hdr *mei_hdr = NULL;  | 
|---|
 | 1804 | +	size_t hdr_len;  | 
|---|
 | 1805 | +	size_t hbuf_len, dr_len;  | 
|---|
 | 1806 | +	size_t buf_len;  | 
|---|
 | 1807 | +	size_t data_len;  | 
|---|
| 1579 | 1808 |  	int hbuf_slots; | 
|---|
 | 1809 | +	u32 dr_slots;  | 
|---|
 | 1810 | +	u32 dma_len;  | 
|---|
| 1580 | 1811 |  	int rets; | 
|---|
| 1581 | 1812 |  	bool first_chunk; | 
|---|
 | 1813 | +	const void *data;  | 
|---|
| 1582 | 1814 |   | 
|---|
| 1583 | 1815 |  	if (WARN_ON(!cl || !cl->dev)) | 
|---|
| 1584 | 1816 |  		return -ENODEV; | 
|---|
| .. | .. | 
|---|
| 1598 | 1830 |  		return 0; | 
|---|
| 1599 | 1831 |  	} | 
|---|
| 1600 | 1832 |   | 
|---|
| 1601 |  | -	len = buf->size - cb->buf_idx;  | 
|---|
 | 1833 | +	buf_len = buf->size - cb->buf_idx;  | 
|---|
 | 1834 | +	data = buf->data + cb->buf_idx;  | 
|---|
| 1602 | 1835 |  	hbuf_slots = mei_hbuf_empty_slots(dev); | 
|---|
| 1603 | 1836 |  	if (hbuf_slots < 0) { | 
|---|
| 1604 | 1837 |  		rets = -EOVERFLOW; | 
|---|
| 1605 | 1838 |  		goto err; | 
|---|
| 1606 | 1839 |  	} | 
|---|
| 1607 | 1840 |   | 
|---|
| 1608 |  | -	hbuf_len = mei_slots2data(hbuf_slots);  | 
|---|
 | 1841 | +	hbuf_len = mei_slots2data(hbuf_slots) & MEI_MSG_MAX_LEN_MASK;  | 
|---|
 | 1842 | +	dr_slots = mei_dma_ring_empty_slots(dev);  | 
|---|
 | 1843 | +	dr_len = mei_slots2data(dr_slots);  | 
|---|
| 1609 | 1844 |   | 
|---|
| 1610 |  | -	mei_msg_hdr_init(&mei_hdr, cb);  | 
|---|
 | 1845 | +	mei_hdr = mei_msg_hdr_init(cb);  | 
|---|
 | 1846 | +	if (IS_ERR(mei_hdr)) {  | 
|---|
 | 1847 | +		rets = PTR_ERR(mei_hdr);  | 
|---|
 | 1848 | +		mei_hdr = NULL;  | 
|---|
 | 1849 | +		goto err;  | 
|---|
 | 1850 | +	}  | 
|---|
 | 1851 | +  | 
|---|
 | 1852 | +	cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",  | 
|---|
 | 1853 | +	       mei_hdr->extended, cb->vtag);  | 
|---|
 | 1854 | +  | 
|---|
 | 1855 | +	hdr_len = sizeof(*mei_hdr) + mei_hdr->length;  | 
|---|
| 1611 | 1856 |   | 
|---|
| 1612 | 1857 |  	/** | 
|---|
| 1613 | 1858 |  	 * Split the message only if we can write the whole host buffer | 
|---|
| 1614 | 1859 |  	 * otherwise wait for next time the host buffer is empty. | 
|---|
| 1615 | 1860 |  	 */ | 
|---|
| 1616 |  | -	if (len + hdr_len <= hbuf_len) {  | 
|---|
| 1617 |  | -		mei_hdr.length = len;  | 
|---|
| 1618 |  | -		mei_hdr.msg_complete = 1;  | 
|---|
 | 1861 | +	if (hdr_len + buf_len <= hbuf_len) {  | 
|---|
 | 1862 | +		data_len = buf_len;  | 
|---|
 | 1863 | +		mei_hdr->msg_complete = 1;  | 
|---|
 | 1864 | +	} else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) {  | 
|---|
 | 1865 | +		mei_hdr->dma_ring = 1;  | 
|---|
 | 1866 | +		if (buf_len > dr_len)  | 
|---|
 | 1867 | +			buf_len = dr_len;  | 
|---|
 | 1868 | +		else  | 
|---|
 | 1869 | +			mei_hdr->msg_complete = 1;  | 
|---|
 | 1870 | +  | 
|---|
 | 1871 | +		data_len = sizeof(dma_len);  | 
|---|
 | 1872 | +		dma_len = buf_len;  | 
|---|
 | 1873 | +		data = &dma_len;  | 
|---|
| 1619 | 1874 |  	} else if ((u32)hbuf_slots == mei_hbuf_depth(dev)) { | 
|---|
| 1620 |  | -		mei_hdr.length = hbuf_len - hdr_len;  | 
|---|
 | 1875 | +		buf_len = hbuf_len - hdr_len;  | 
|---|
 | 1876 | +		data_len = buf_len;  | 
|---|
| 1621 | 1877 |  	} else { | 
|---|
 | 1878 | +		kfree(mei_hdr);  | 
|---|
| 1622 | 1879 |  		return 0; | 
|---|
| 1623 | 1880 |  	} | 
|---|
 | 1881 | +	mei_hdr->length += data_len;  | 
|---|
| 1624 | 1882 |   | 
|---|
| 1625 |  | -	cl_dbg(dev, cl, "buf: size = %zu idx = %zu\n",  | 
|---|
| 1626 |  | -			cb->buf.size, cb->buf_idx);  | 
|---|
 | 1883 | +	if (mei_hdr->dma_ring)  | 
|---|
 | 1884 | +		mei_dma_ring_write(dev, buf->data + cb->buf_idx, buf_len);  | 
|---|
 | 1885 | +	rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);  | 
|---|
| 1627 | 1886 |   | 
|---|
| 1628 |  | -	rets = mei_write_message(dev, &mei_hdr, hdr_len,  | 
|---|
| 1629 |  | -				 buf->data + cb->buf_idx, mei_hdr.length);  | 
|---|
| 1630 | 1887 |  	if (rets) | 
|---|
| 1631 | 1888 |  		goto err; | 
|---|
| 1632 | 1889 |   | 
|---|
| 1633 | 1890 |  	cl->status = 0; | 
|---|
| 1634 | 1891 |  	cl->writing_state = MEI_WRITING; | 
|---|
| 1635 |  | -	cb->buf_idx += mei_hdr.length;  | 
|---|
 | 1892 | +	cb->buf_idx += buf_len;  | 
|---|
| 1636 | 1893 |   | 
|---|
| 1637 | 1894 |  	if (first_chunk) { | 
|---|
| 1638 | 1895 |  		if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { | 
|---|
| .. | .. | 
|---|
| 1641 | 1898 |  		} | 
|---|
| 1642 | 1899 |  	} | 
|---|
| 1643 | 1900 |   | 
|---|
| 1644 |  | -	if (mei_hdr.msg_complete)  | 
|---|
 | 1901 | +	if (mei_hdr->msg_complete)  | 
|---|
| 1645 | 1902 |  		list_move_tail(&cb->list, &dev->write_waiting_list); | 
|---|
| 1646 | 1903 |   | 
|---|
 | 1904 | +	kfree(mei_hdr);  | 
|---|
| 1647 | 1905 |  	return 0; | 
|---|
| 1648 | 1906 |   | 
|---|
| 1649 | 1907 |  err: | 
|---|
 | 1908 | +	kfree(mei_hdr);  | 
|---|
| 1650 | 1909 |  	cl->status = rets; | 
|---|
| 1651 | 1910 |  	list_move_tail(&cb->list, cmpl_list); | 
|---|
| 1652 | 1911 |  	return rets; | 
|---|
| .. | .. | 
|---|
| 1665 | 1924 |  { | 
|---|
| 1666 | 1925 |  	struct mei_device *dev; | 
|---|
| 1667 | 1926 |  	struct mei_msg_data *buf; | 
|---|
| 1668 |  | -	struct mei_msg_hdr mei_hdr;  | 
|---|
| 1669 |  | -	size_t hdr_len = sizeof(mei_hdr);  | 
|---|
| 1670 |  | -	size_t len;  | 
|---|
| 1671 |  | -	size_t hbuf_len;  | 
|---|
 | 1927 | +	struct mei_msg_hdr *mei_hdr = NULL;  | 
|---|
 | 1928 | +	size_t hdr_len;  | 
|---|
 | 1929 | +	size_t hbuf_len, dr_len;  | 
|---|
 | 1930 | +	size_t buf_len;  | 
|---|
 | 1931 | +	size_t data_len;  | 
|---|
| 1672 | 1932 |  	int hbuf_slots; | 
|---|
 | 1933 | +	u32 dr_slots;  | 
|---|
 | 1934 | +	u32 dma_len;  | 
|---|
| 1673 | 1935 |  	ssize_t rets; | 
|---|
| 1674 | 1936 |  	bool blocking; | 
|---|
 | 1937 | +	const void *data;  | 
|---|
| 1675 | 1938 |   | 
|---|
| 1676 | 1939 |  	if (WARN_ON(!cl || !cl->dev)) | 
|---|
| 1677 | 1940 |  		return -ENODEV; | 
|---|
| .. | .. | 
|---|
| 1682 | 1945 |  	dev = cl->dev; | 
|---|
| 1683 | 1946 |   | 
|---|
| 1684 | 1947 |  	buf = &cb->buf; | 
|---|
| 1685 |  | -	len = buf->size;  | 
|---|
| 1686 |  | -	blocking = cb->blocking;  | 
|---|
 | 1948 | +	buf_len = buf->size;  | 
|---|
| 1687 | 1949 |   | 
|---|
| 1688 |  | -	cl_dbg(dev, cl, "len=%zd\n", len);  | 
|---|
 | 1950 | +	cl_dbg(dev, cl, "buf_len=%zd\n", buf_len);  | 
|---|
 | 1951 | +  | 
|---|
 | 1952 | +	blocking = cb->blocking;  | 
|---|
 | 1953 | +	data = buf->data;  | 
|---|
| 1689 | 1954 |   | 
|---|
| 1690 | 1955 |  	rets = pm_runtime_get(dev->dev); | 
|---|
| 1691 | 1956 |  	if (rets < 0 && rets != -EINPROGRESS) { | 
|---|
| .. | .. | 
|---|
| 1702 | 1967 |  	if (rets < 0) | 
|---|
| 1703 | 1968 |  		goto err; | 
|---|
| 1704 | 1969 |   | 
|---|
| 1705 |  | -	mei_msg_hdr_init(&mei_hdr, cb);  | 
|---|
 | 1970 | +	mei_hdr = mei_msg_hdr_init(cb);  | 
|---|
 | 1971 | +	if (IS_ERR(mei_hdr)) {  | 
|---|
 | 1972 | +		rets = -PTR_ERR(mei_hdr);  | 
|---|
 | 1973 | +		mei_hdr = NULL;  | 
|---|
 | 1974 | +		goto err;  | 
|---|
 | 1975 | +	}  | 
|---|
 | 1976 | +  | 
|---|
 | 1977 | +	cl_dbg(dev, cl, "Extended Header %d vtag = %d\n",  | 
|---|
 | 1978 | +	       mei_hdr->extended, cb->vtag);  | 
|---|
 | 1979 | +  | 
|---|
 | 1980 | +	hdr_len = sizeof(*mei_hdr) + mei_hdr->length;  | 
|---|
| 1706 | 1981 |   | 
|---|
| 1707 | 1982 |  	if (rets == 0) { | 
|---|
| 1708 | 1983 |  		cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | 
|---|
| 1709 |  | -		rets = len;  | 
|---|
 | 1984 | +		rets = buf_len;  | 
|---|
| 1710 | 1985 |  		goto out; | 
|---|
| 1711 | 1986 |  	} | 
|---|
| 1712 | 1987 |   | 
|---|
| 1713 | 1988 |  	if (!mei_hbuf_acquire(dev)) { | 
|---|
| 1714 | 1989 |  		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); | 
|---|
| 1715 |  | -		rets = len;  | 
|---|
 | 1990 | +		rets = buf_len;  | 
|---|
| 1716 | 1991 |  		goto out; | 
|---|
| 1717 | 1992 |  	} | 
|---|
| 1718 | 1993 |   | 
|---|
| .. | .. | 
|---|
| 1722 | 1997 |  		goto out; | 
|---|
| 1723 | 1998 |  	} | 
|---|
| 1724 | 1999 |   | 
|---|
| 1725 |  | -	hbuf_len = mei_slots2data(hbuf_slots);  | 
|---|
 | 2000 | +	hbuf_len = mei_slots2data(hbuf_slots) & MEI_MSG_MAX_LEN_MASK;  | 
|---|
 | 2001 | +	dr_slots = mei_dma_ring_empty_slots(dev);  | 
|---|
 | 2002 | +	dr_len =  mei_slots2data(dr_slots);  | 
|---|
| 1726 | 2003 |   | 
|---|
| 1727 |  | -	if (len + hdr_len <= hbuf_len) {  | 
|---|
| 1728 |  | -		mei_hdr.length = len;  | 
|---|
| 1729 |  | -		mei_hdr.msg_complete = 1;  | 
|---|
 | 2004 | +	if (hdr_len + buf_len <= hbuf_len) {  | 
|---|
 | 2005 | +		data_len = buf_len;  | 
|---|
 | 2006 | +		mei_hdr->msg_complete = 1;  | 
|---|
 | 2007 | +	} else if (dr_slots && hbuf_len >= hdr_len + sizeof(dma_len)) {  | 
|---|
 | 2008 | +		mei_hdr->dma_ring = 1;  | 
|---|
 | 2009 | +		if (buf_len > dr_len)  | 
|---|
 | 2010 | +			buf_len = dr_len;  | 
|---|
 | 2011 | +		else  | 
|---|
 | 2012 | +			mei_hdr->msg_complete = 1;  | 
|---|
 | 2013 | +  | 
|---|
 | 2014 | +		data_len = sizeof(dma_len);  | 
|---|
 | 2015 | +		dma_len = buf_len;  | 
|---|
 | 2016 | +		data = &dma_len;  | 
|---|
| 1730 | 2017 |  	} else { | 
|---|
| 1731 |  | -		mei_hdr.length = hbuf_len - hdr_len;  | 
|---|
 | 2018 | +		buf_len = hbuf_len - hdr_len;  | 
|---|
 | 2019 | +		data_len = buf_len;  | 
|---|
| 1732 | 2020 |  	} | 
|---|
| 1733 | 2021 |   | 
|---|
| 1734 |  | -	rets = mei_write_message(dev, &mei_hdr, hdr_len,  | 
|---|
| 1735 |  | -				 buf->data, mei_hdr.length);  | 
|---|
 | 2022 | +	mei_hdr->length += data_len;  | 
|---|
 | 2023 | +  | 
|---|
 | 2024 | +	if (mei_hdr->dma_ring)  | 
|---|
 | 2025 | +		mei_dma_ring_write(dev, buf->data, buf_len);  | 
|---|
 | 2026 | +	rets = mei_write_message(dev, mei_hdr, hdr_len, data, data_len);  | 
|---|
 | 2027 | +  | 
|---|
| 1736 | 2028 |  	if (rets) | 
|---|
| 1737 | 2029 |  		goto err; | 
|---|
| 1738 | 2030 |   | 
|---|
| .. | .. | 
|---|
| 1741 | 2033 |  		goto err; | 
|---|
| 1742 | 2034 |   | 
|---|
| 1743 | 2035 |  	cl->writing_state = MEI_WRITING; | 
|---|
| 1744 |  | -	cb->buf_idx = mei_hdr.length;  | 
|---|
 | 2036 | +	cb->buf_idx = buf_len;  | 
|---|
 | 2037 | +	/* restore return value */  | 
|---|
 | 2038 | +	buf_len = buf->size;  | 
|---|
| 1745 | 2039 |   | 
|---|
| 1746 | 2040 |  out: | 
|---|
| 1747 |  | -	if (mei_hdr.msg_complete)  | 
|---|
 | 2041 | +	if (mei_hdr->msg_complete)  | 
|---|
| 1748 | 2042 |  		mei_tx_cb_enqueue(cb, &dev->write_waiting_list); | 
|---|
| 1749 | 2043 |  	else | 
|---|
| 1750 | 2044 |  		mei_tx_cb_enqueue(cb, &dev->write_list); | 
|---|
| .. | .. | 
|---|
| 1769 | 2063 |  		} | 
|---|
| 1770 | 2064 |  	} | 
|---|
| 1771 | 2065 |   | 
|---|
| 1772 |  | -	rets = len;  | 
|---|
 | 2066 | +	rets = buf_len;  | 
|---|
| 1773 | 2067 |  err: | 
|---|
| 1774 | 2068 |  	cl_dbg(dev, cl, "rpm: autosuspend\n"); | 
|---|
| 1775 | 2069 |  	pm_runtime_mark_last_busy(dev->dev); | 
|---|
| .. | .. | 
|---|
| 1777 | 2071 |  free: | 
|---|
| 1778 | 2072 |  	mei_io_cb_free(cb); | 
|---|
| 1779 | 2073 |   | 
|---|
 | 2074 | +	kfree(mei_hdr);  | 
|---|
 | 2075 | +  | 
|---|
| 1780 | 2076 |  	return rets; | 
|---|
| 1781 | 2077 |  } | 
|---|
| 1782 |  | -  | 
|---|
| 1783 | 2078 |   | 
|---|
| 1784 | 2079 |  /** | 
|---|
| 1785 | 2080 |   * mei_cl_complete - processes completed operation for a client | 
|---|
| .. | .. | 
|---|
| 1804 | 2099 |  		break; | 
|---|
| 1805 | 2100 |   | 
|---|
| 1806 | 2101 |  	case MEI_FOP_READ: | 
|---|
| 1807 |  | -		list_add_tail(&cb->list, &cl->rd_completed);  | 
|---|
 | 2102 | +		mei_cl_add_rd_completed(cl, cb);  | 
|---|
| 1808 | 2103 |  		if (!mei_cl_is_fixed_address(cl) && | 
|---|
| 1809 | 2104 |  		    !WARN_ON(!cl->rx_flow_ctrl_creds)) | 
|---|
| 1810 | 2105 |  			cl->rx_flow_ctrl_creds--; | 
|---|