diff options
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r-- | drivers/misc/mei/client.c | 145 |
1 files changed, 77 insertions, 68 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index b0395601c6ae..68fe37b5bc52 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -377,19 +377,19 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, | |||
377 | } | 377 | } |
378 | 378 | ||
379 | /** | 379 | /** |
380 | * __mei_io_list_flush - removes and frees cbs belonging to cl. | 380 | * __mei_io_list_flush_cl - removes and frees cbs belonging to cl. |
381 | * | 381 | * |
382 | * @list: an instance of our list structure | 382 | * @head: an instance of our list structure |
383 | * @cl: host client, can be NULL for flushing the whole list | 383 | * @cl: host client, can be NULL for flushing the whole list |
384 | * @free: whether to free the cbs | 384 | * @free: whether to free the cbs |
385 | */ | 385 | */ |
386 | static void __mei_io_list_flush(struct mei_cl_cb *list, | 386 | static void __mei_io_list_flush_cl(struct list_head *head, |
387 | struct mei_cl *cl, bool free) | 387 | const struct mei_cl *cl, bool free) |
388 | { | 388 | { |
389 | struct mei_cl_cb *cb, *next; | 389 | struct mei_cl_cb *cb, *next; |
390 | 390 | ||
391 | /* enable removing everything if no cl is specified */ | 391 | /* enable removing everything if no cl is specified */ |
392 | list_for_each_entry_safe(cb, next, &list->list, list) { | 392 | list_for_each_entry_safe(cb, next, head, list) { |
393 | if (!cl || mei_cl_cmp_id(cl, cb->cl)) { | 393 | if (!cl || mei_cl_cmp_id(cl, cb->cl)) { |
394 | list_del_init(&cb->list); | 394 | list_del_init(&cb->list); |
395 | if (free) | 395 | if (free) |
@@ -399,25 +399,42 @@ static void __mei_io_list_flush(struct mei_cl_cb *list, | |||
399 | } | 399 | } |
400 | 400 | ||
401 | /** | 401 | /** |
402 | * mei_io_list_flush - removes list entry belonging to cl. | 402 | * mei_io_list_flush_cl - removes list entry belonging to cl. |
403 | * | 403 | * |
404 | * @list: An instance of our list structure | 404 | * @head: An instance of our list structure |
405 | * @cl: host client | 405 | * @cl: host client |
406 | */ | 406 | */ |
407 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) | 407 | static inline void mei_io_list_flush_cl(struct list_head *head, |
408 | const struct mei_cl *cl) | ||
408 | { | 409 | { |
409 | __mei_io_list_flush(list, cl, false); | 410 | __mei_io_list_flush_cl(head, cl, false); |
410 | } | 411 | } |
411 | 412 | ||
412 | /** | 413 | /** |
413 | * mei_io_list_free - removes cb belonging to cl and free them | 414 | * mei_io_list_free_cl - removes cb belonging to cl and free them |
414 | * | 415 | * |
415 | * @list: An instance of our list structure | 416 | * @head: An instance of our list structure |
416 | * @cl: host client | 417 | * @cl: host client |
417 | */ | 418 | */ |
418 | static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) | 419 | static inline void mei_io_list_free_cl(struct list_head *head, |
420 | const struct mei_cl *cl) | ||
419 | { | 421 | { |
420 | __mei_io_list_flush(list, cl, true); | 422 | __mei_io_list_flush_cl(head, cl, true); |
423 | } | ||
424 | |||
425 | /** | ||
426 | * mei_io_list_free_fp - free cb from a list that matches file pointer | ||
427 | * | ||
428 | * @head: io list | ||
429 | * @fp: file pointer (matching cb file object), may be NULL | ||
430 | */ | ||
431 | void mei_io_list_free_fp(struct list_head *head, const struct file *fp) | ||
432 | { | ||
433 | struct mei_cl_cb *cb, *next; | ||
434 | |||
435 | list_for_each_entry_safe(cb, next, head, list) | ||
436 | if (!fp || fp == cb->fp) | ||
437 | mei_io_cb_free(cb); | ||
421 | } | 438 | } |
422 | 439 | ||
423 | /** | 440 | /** |
@@ -479,7 +496,7 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, | |||
479 | if (!cb) | 496 | if (!cb) |
480 | return NULL; | 497 | return NULL; |
481 | 498 | ||
482 | list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list); | 499 | list_add_tail(&cb->list, &cl->dev->ctrl_wr_list); |
483 | return cb; | 500 | return cb; |
484 | } | 501 | } |
485 | 502 | ||
@@ -504,27 +521,6 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp) | |||
504 | } | 521 | } |
505 | 522 | ||
506 | /** | 523 | /** |
507 | * mei_cl_read_cb_flush - free client's read pending and completed cbs | ||
508 | * for a specific file | ||
509 | * | ||
510 | * @cl: host client | ||
511 | * @fp: file pointer (matching cb file object), may be NULL | ||
512 | */ | ||
513 | void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp) | ||
514 | { | ||
515 | struct mei_cl_cb *cb, *next; | ||
516 | |||
517 | list_for_each_entry_safe(cb, next, &cl->rd_completed, list) | ||
518 | if (!fp || fp == cb->fp) | ||
519 | mei_io_cb_free(cb); | ||
520 | |||
521 | |||
522 | list_for_each_entry_safe(cb, next, &cl->rd_pending, list) | ||
523 | if (!fp || fp == cb->fp) | ||
524 | mei_io_cb_free(cb); | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * mei_cl_flush_queues - flushes queue lists belonging to cl. | 524 | * mei_cl_flush_queues - flushes queue lists belonging to cl. |
529 | * | 525 | * |
530 | * @cl: host client | 526 | * @cl: host client |
@@ -542,18 +538,16 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) | |||
542 | dev = cl->dev; | 538 | dev = cl->dev; |
543 | 539 | ||
544 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | 540 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); |
545 | mei_io_list_free(&cl->dev->write_list, cl); | 541 | mei_io_list_free_cl(&cl->dev->write_list, cl); |
546 | mei_io_list_free(&cl->dev->write_waiting_list, cl); | 542 | mei_io_list_free_cl(&cl->dev->write_waiting_list, cl); |
547 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | 543 | mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl); |
548 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | 544 | mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl); |
549 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); | 545 | mei_io_list_free_fp(&cl->rd_pending, fp); |
550 | 546 | mei_io_list_free_fp(&cl->rd_completed, fp); | |
551 | mei_cl_read_cb_flush(cl, fp); | ||
552 | 547 | ||
553 | return 0; | 548 | return 0; |
554 | } | 549 | } |
555 | 550 | ||
556 | |||
557 | /** | 551 | /** |
558 | * mei_cl_init - initializes cl. | 552 | * mei_cl_init - initializes cl. |
559 | * | 553 | * |
@@ -756,7 +750,7 @@ static void mei_cl_wake_all(struct mei_cl *cl) | |||
756 | * | 750 | * |
757 | * @cl: host client | 751 | * @cl: host client |
758 | */ | 752 | */ |
759 | void mei_cl_set_disconnected(struct mei_cl *cl) | 753 | static void mei_cl_set_disconnected(struct mei_cl *cl) |
760 | { | 754 | { |
761 | struct mei_device *dev = cl->dev; | 755 | struct mei_device *dev = cl->dev; |
762 | 756 | ||
@@ -765,15 +759,18 @@ void mei_cl_set_disconnected(struct mei_cl *cl) | |||
765 | return; | 759 | return; |
766 | 760 | ||
767 | cl->state = MEI_FILE_DISCONNECTED; | 761 | cl->state = MEI_FILE_DISCONNECTED; |
768 | mei_io_list_free(&dev->write_list, cl); | 762 | mei_io_list_free_cl(&dev->write_list, cl); |
769 | mei_io_list_free(&dev->write_waiting_list, cl); | 763 | mei_io_list_free_cl(&dev->write_waiting_list, cl); |
770 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 764 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
771 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 765 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
766 | mei_io_list_free_cl(&dev->amthif_cmd_list, cl); | ||
772 | mei_cl_wake_all(cl); | 767 | mei_cl_wake_all(cl); |
773 | cl->rx_flow_ctrl_creds = 0; | 768 | cl->rx_flow_ctrl_creds = 0; |
774 | cl->tx_flow_ctrl_creds = 0; | 769 | cl->tx_flow_ctrl_creds = 0; |
775 | cl->timer_count = 0; | 770 | cl->timer_count = 0; |
776 | 771 | ||
772 | mei_cl_bus_module_put(cl); | ||
773 | |||
777 | if (!cl->me_cl) | 774 | if (!cl->me_cl) |
778 | return; | 775 | return; |
779 | 776 | ||
@@ -829,7 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
829 | return ret; | 826 | return ret; |
830 | } | 827 | } |
831 | 828 | ||
832 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 829 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
833 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 830 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
834 | mei_schedule_stall_timer(dev); | 831 | mei_schedule_stall_timer(dev); |
835 | 832 | ||
@@ -847,7 +844,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
847 | * Return: 0, OK; otherwise, error. | 844 | * Return: 0, OK; otherwise, error. |
848 | */ | 845 | */ |
849 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, | 846 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, |
850 | struct mei_cl_cb *cmpl_list) | 847 | struct list_head *cmpl_list) |
851 | { | 848 | { |
852 | struct mei_device *dev = cl->dev; | 849 | struct mei_device *dev = cl->dev; |
853 | u32 msg_slots; | 850 | u32 msg_slots; |
@@ -862,7 +859,7 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
862 | 859 | ||
863 | ret = mei_cl_send_disconnect(cl, cb); | 860 | ret = mei_cl_send_disconnect(cl, cb); |
864 | if (ret) | 861 | if (ret) |
865 | list_move_tail(&cb->list, &cmpl_list->list); | 862 | list_move_tail(&cb->list, cmpl_list); |
866 | 863 | ||
867 | return ret; | 864 | return ret; |
868 | } | 865 | } |
@@ -984,7 +981,7 @@ static bool mei_cl_is_other_connecting(struct mei_cl *cl) | |||
984 | 981 | ||
985 | dev = cl->dev; | 982 | dev = cl->dev; |
986 | 983 | ||
987 | list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) { | 984 | list_for_each_entry(cb, &dev->ctrl_rd_list, list) { |
988 | if (cb->fop_type == MEI_FOP_CONNECT && | 985 | if (cb->fop_type == MEI_FOP_CONNECT && |
989 | mei_cl_me_id(cl) == mei_cl_me_id(cb->cl)) | 986 | mei_cl_me_id(cl) == mei_cl_me_id(cb->cl)) |
990 | return true; | 987 | return true; |
@@ -1015,7 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1015 | return ret; | 1012 | return ret; |
1016 | } | 1013 | } |
1017 | 1014 | ||
1018 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1015 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1019 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 1016 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
1020 | mei_schedule_stall_timer(dev); | 1017 | mei_schedule_stall_timer(dev); |
1021 | return 0; | 1018 | return 0; |
@@ -1031,7 +1028,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1031 | * Return: 0, OK; otherwise, error. | 1028 | * Return: 0, OK; otherwise, error. |
1032 | */ | 1029 | */ |
1033 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | 1030 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, |
1034 | struct mei_cl_cb *cmpl_list) | 1031 | struct list_head *cmpl_list) |
1035 | { | 1032 | { |
1036 | struct mei_device *dev = cl->dev; | 1033 | struct mei_device *dev = cl->dev; |
1037 | u32 msg_slots; | 1034 | u32 msg_slots; |
@@ -1049,7 +1046,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1049 | 1046 | ||
1050 | rets = mei_cl_send_connect(cl, cb); | 1047 | rets = mei_cl_send_connect(cl, cb); |
1051 | if (rets) | 1048 | if (rets) |
1052 | list_move_tail(&cb->list, &cmpl_list->list); | 1049 | list_move_tail(&cb->list, cmpl_list); |
1053 | 1050 | ||
1054 | return rets; | 1051 | return rets; |
1055 | } | 1052 | } |
@@ -1077,13 +1074,17 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | |||
1077 | 1074 | ||
1078 | dev = cl->dev; | 1075 | dev = cl->dev; |
1079 | 1076 | ||
1077 | if (!mei_cl_bus_module_get(cl)) | ||
1078 | return -ENODEV; | ||
1079 | |||
1080 | rets = mei_cl_set_connecting(cl, me_cl); | 1080 | rets = mei_cl_set_connecting(cl, me_cl); |
1081 | if (rets) | 1081 | if (rets) |
1082 | return rets; | 1082 | goto nortpm; |
1083 | 1083 | ||
1084 | if (mei_cl_is_fixed_address(cl)) { | 1084 | if (mei_cl_is_fixed_address(cl)) { |
1085 | cl->state = MEI_FILE_CONNECTED; | 1085 | cl->state = MEI_FILE_CONNECTED; |
1086 | return 0; | 1086 | rets = 0; |
1087 | goto nortpm; | ||
1087 | } | 1088 | } |
1088 | 1089 | ||
1089 | rets = pm_runtime_get(dev->dev); | 1090 | rets = pm_runtime_get(dev->dev); |
@@ -1117,8 +1118,8 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | |||
1117 | 1118 | ||
1118 | if (!mei_cl_is_connected(cl)) { | 1119 | if (!mei_cl_is_connected(cl)) { |
1119 | if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { | 1120 | if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { |
1120 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 1121 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
1121 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 1122 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
1122 | /* ignore disconnect return valuue; | 1123 | /* ignore disconnect return valuue; |
1123 | * in case of failure reset will be invoked | 1124 | * in case of failure reset will be invoked |
1124 | */ | 1125 | */ |
@@ -1270,7 +1271,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req) | |||
1270 | * Return: 0 on such and error otherwise. | 1271 | * Return: 0 on such and error otherwise. |
1271 | */ | 1272 | */ |
1272 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | 1273 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, |
1273 | struct mei_cl_cb *cmpl_list) | 1274 | struct list_head *cmpl_list) |
1274 | { | 1275 | { |
1275 | struct mei_device *dev = cl->dev; | 1276 | struct mei_device *dev = cl->dev; |
1276 | u32 msg_slots; | 1277 | u32 msg_slots; |
@@ -1288,11 +1289,11 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1288 | ret = mei_hbm_cl_notify_req(dev, cl, request); | 1289 | ret = mei_hbm_cl_notify_req(dev, cl, request); |
1289 | if (ret) { | 1290 | if (ret) { |
1290 | cl->status = ret; | 1291 | cl->status = ret; |
1291 | list_move_tail(&cb->list, &cmpl_list->list); | 1292 | list_move_tail(&cb->list, cmpl_list); |
1292 | return ret; | 1293 | return ret; |
1293 | } | 1294 | } |
1294 | 1295 | ||
1295 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1296 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1296 | return 0; | 1297 | return 0; |
1297 | } | 1298 | } |
1298 | 1299 | ||
@@ -1325,6 +1326,9 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1325 | return -EOPNOTSUPP; | 1326 | return -EOPNOTSUPP; |
1326 | } | 1327 | } |
1327 | 1328 | ||
1329 | if (!mei_cl_is_connected(cl)) | ||
1330 | return -ENODEV; | ||
1331 | |||
1328 | rets = pm_runtime_get(dev->dev); | 1332 | rets = pm_runtime_get(dev->dev); |
1329 | if (rets < 0 && rets != -EINPROGRESS) { | 1333 | if (rets < 0 && rets != -EINPROGRESS) { |
1330 | pm_runtime_put_noidle(dev->dev); | 1334 | pm_runtime_put_noidle(dev->dev); |
@@ -1344,7 +1348,7 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1344 | rets = -ENODEV; | 1348 | rets = -ENODEV; |
1345 | goto out; | 1349 | goto out; |
1346 | } | 1350 | } |
1347 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1351 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1348 | } | 1352 | } |
1349 | 1353 | ||
1350 | mutex_unlock(&dev->device_lock); | 1354 | mutex_unlock(&dev->device_lock); |
@@ -1419,6 +1423,11 @@ int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev) | |||
1419 | 1423 | ||
1420 | dev = cl->dev; | 1424 | dev = cl->dev; |
1421 | 1425 | ||
1426 | if (!dev->hbm_f_ev_supported) { | ||
1427 | cl_dbg(dev, cl, "notifications not supported\n"); | ||
1428 | return -EOPNOTSUPP; | ||
1429 | } | ||
1430 | |||
1422 | if (!mei_cl_is_connected(cl)) | 1431 | if (!mei_cl_is_connected(cl)) |
1423 | return -ENODEV; | 1432 | return -ENODEV; |
1424 | 1433 | ||
@@ -1519,7 +1528,7 @@ nortpm: | |||
1519 | * Return: 0, OK; otherwise error. | 1528 | * Return: 0, OK; otherwise error. |
1520 | */ | 1529 | */ |
1521 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 1530 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
1522 | struct mei_cl_cb *cmpl_list) | 1531 | struct list_head *cmpl_list) |
1523 | { | 1532 | { |
1524 | struct mei_device *dev; | 1533 | struct mei_device *dev; |
1525 | struct mei_msg_data *buf; | 1534 | struct mei_msg_data *buf; |
@@ -1591,13 +1600,13 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1591 | } | 1600 | } |
1592 | 1601 | ||
1593 | if (mei_hdr.msg_complete) | 1602 | if (mei_hdr.msg_complete) |
1594 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 1603 | list_move_tail(&cb->list, &dev->write_waiting_list); |
1595 | 1604 | ||
1596 | return 0; | 1605 | return 0; |
1597 | 1606 | ||
1598 | err: | 1607 | err: |
1599 | cl->status = rets; | 1608 | cl->status = rets; |
1600 | list_move_tail(&cb->list, &cmpl_list->list); | 1609 | list_move_tail(&cb->list, cmpl_list); |
1601 | return rets; | 1610 | return rets; |
1602 | } | 1611 | } |
1603 | 1612 | ||
@@ -1687,9 +1696,9 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1687 | 1696 | ||
1688 | out: | 1697 | out: |
1689 | if (mei_hdr.msg_complete) | 1698 | if (mei_hdr.msg_complete) |
1690 | list_add_tail(&cb->list, &dev->write_waiting_list.list); | 1699 | list_add_tail(&cb->list, &dev->write_waiting_list); |
1691 | else | 1700 | else |
1692 | list_add_tail(&cb->list, &dev->write_list.list); | 1701 | list_add_tail(&cb->list, &dev->write_list); |
1693 | 1702 | ||
1694 | cb = NULL; | 1703 | cb = NULL; |
1695 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { | 1704 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { |