aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Usyskin <alexander.usyskin@intel.com>2015-07-23 14:37:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-03 20:25:51 -0400
commit18901357e70ae29e3fd1c58712a6847c2ae52eae (patch)
treed0aa7e5a5ace95881a146f85c3f41047b5dd79e0
parent70ef835c84b3b88e274a53bf80a70940ae178a91 (diff)
mei: disconnect on connection request timeout
For the FW with HBM version >= 2.0 we don't need to reset the whole device in case of a particular client failing to connect, it is enough to send disconnect a request to bring the device to the stable state. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/mei/client.c85
-rw-r--r--drivers/misc/mei/debugfs.c2
-rw-r--r--drivers/misc/mei/hbm.c4
-rw-r--r--drivers/misc/mei/hw.h6
-rw-r--r--drivers/misc/mei/interrupt.c20
-rw-r--r--drivers/misc/mei/mei_dev.h7
6 files changed, 95 insertions, 29 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 9dacea7a9a60..40285e02b612 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb,
836 return ret; 836 return ret;
837} 837}
838 838
839
840
841/** 839/**
842 * mei_cl_disconnect - disconnect host client from the me one 840 * __mei_cl_disconnect - disconnect host client from the me one
841 * internal function runtime pm has to be already acquired
843 * 842 *
844 * @cl: host client 843 * @cl: host client
845 * 844 *
846 * Locking: called under "dev->device_lock" lock
847 *
848 * Return: 0 on success, <0 on failure. 845 * Return: 0 on success, <0 on failure.
849 */ 846 */
850int mei_cl_disconnect(struct mei_cl *cl) 847static int __mei_cl_disconnect(struct mei_cl *cl)
851{ 848{
852 struct mei_device *dev; 849 struct mei_device *dev;
853 struct mei_cl_cb *cb; 850 struct mei_cl_cb *cb;
854 int rets; 851 int rets;
855 852
856 if (WARN_ON(!cl || !cl->dev))
857 return -ENODEV;
858
859 dev = cl->dev; 853 dev = cl->dev;
860 854
861 cl_dbg(dev, cl, "disconnecting"); 855 if (WARN_ON(!pm_runtime_active(dev->dev)))
862 856 return -EFAULT;
863 if (!mei_cl_is_connected(cl))
864 return 0;
865
866 if (mei_cl_is_fixed_address(cl)) {
867 mei_cl_set_disconnected(cl);
868 return 0;
869 }
870
871 rets = pm_runtime_get(dev->dev);
872 if (rets < 0 && rets != -EINPROGRESS) {
873 pm_runtime_put_noidle(dev->dev);
874 cl_err(dev, cl, "rpm: get failed %d\n", rets);
875 return rets;
876 }
877 857
878 cl->state = MEI_FILE_DISCONNECTING; 858 cl->state = MEI_FILE_DISCONNECTING;
879 859
@@ -910,11 +890,52 @@ out:
910 if (!rets) 890 if (!rets)
911 cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); 891 cl_dbg(dev, cl, "successfully disconnected from FW client.\n");
912 892
893 mei_io_cb_free(cb);
894 return rets;
895}
896
897/**
898 * mei_cl_disconnect - disconnect host client from the me one
899 *
900 * @cl: host client
901 *
902 * Locking: called under "dev->device_lock" lock
903 *
904 * Return: 0 on success, <0 on failure.
905 */
906int mei_cl_disconnect(struct mei_cl *cl)
907{
908 struct mei_device *dev;
909 int rets;
910
911 if (WARN_ON(!cl || !cl->dev))
912 return -ENODEV;
913
914 dev = cl->dev;
915
916 cl_dbg(dev, cl, "disconnecting");
917
918 if (!mei_cl_is_connected(cl))
919 return 0;
920
921 if (mei_cl_is_fixed_address(cl)) {
922 mei_cl_set_disconnected(cl);
923 return 0;
924 }
925
926 rets = pm_runtime_get(dev->dev);
927 if (rets < 0 && rets != -EINPROGRESS) {
928 pm_runtime_put_noidle(dev->dev);
929 cl_err(dev, cl, "rpm: get failed %d\n", rets);
930 return rets;
931 }
932
933 rets = __mei_cl_disconnect(cl);
934
913 cl_dbg(dev, cl, "rpm: autosuspend\n"); 935 cl_dbg(dev, cl, "rpm: autosuspend\n");
914 pm_runtime_mark_last_busy(dev->dev); 936 pm_runtime_mark_last_busy(dev->dev);
915 pm_runtime_put_autosuspend(dev->dev); 937 pm_runtime_put_autosuspend(dev->dev);
916 938
917 mei_io_cb_free(cb);
918 return rets; 939 return rets;
919} 940}
920 941
@@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
1059 mutex_unlock(&dev->device_lock); 1080 mutex_unlock(&dev->device_lock);
1060 wait_event_timeout(cl->wait, 1081 wait_event_timeout(cl->wait,
1061 (cl->state == MEI_FILE_CONNECTED || 1082 (cl->state == MEI_FILE_CONNECTED ||
1083 cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
1062 cl->state == MEI_FILE_DISCONNECT_REPLY), 1084 cl->state == MEI_FILE_DISCONNECT_REPLY),
1063 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); 1085 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
1064 mutex_lock(&dev->device_lock); 1086 mutex_lock(&dev->device_lock);
1065 1087
1066 if (!mei_cl_is_connected(cl)) { 1088 if (!mei_cl_is_connected(cl)) {
1089 if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) {
1090 mei_io_list_flush(&dev->ctrl_rd_list, cl);
1091 mei_io_list_flush(&dev->ctrl_wr_list, cl);
1092 /* ignore disconnect return valuue;
1093 * in case of failure reset will be invoked
1094 */
1095 __mei_cl_disconnect(cl);
1096 rets = -EFAULT;
1097 goto out;
1098 }
1099
1067 /* timeout or something went really wrong */ 1100 /* timeout or something went really wrong */
1068 if (!cl->status) 1101 if (!cl->status)
1069 cl->status = -EFAULT; 1102 cl->status = -EFAULT;
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index a65a1e6f386f..e39cfe6bc5bc 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
156 dev->hbm_f_pg_supported); 156 dev->hbm_f_pg_supported);
157 pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", 157 pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
158 dev->hbm_f_dc_supported); 158 dev->hbm_f_dc_supported);
159 pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n",
160 dev->hbm_f_dot_supported);
159 } 161 }
160 162
161 pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", 163 pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index d4dba639db37..07a8ea8362a3 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
774 774
775 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) 775 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
776 dev->hbm_f_dc_supported = 1; 776 dev->hbm_f_dc_supported = 1;
777
778 /* disconnect on connect timeout instead of link reset */
779 if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
780 dev->hbm_f_dot_supported = 1;
777} 781}
778 782
779/** 783/**
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 815f40a604b9..e961be392fae 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -52,6 +52,12 @@
52#define HBM_MINOR_VERSION_DC 0 52#define HBM_MINOR_VERSION_DC 0
53#define HBM_MAJOR_VERSION_DC 2 53#define HBM_MAJOR_VERSION_DC 2
54 54
55/*
56 * MEI version with disconnect on connection timeout support
57 */
58#define HBM_MINOR_VERSION_DOT 0
59#define HBM_MAJOR_VERSION_DOT 2
60
55/* Host bus message command opcode */ 61/* Host bus message command opcode */
56#define MEI_HBM_CMD_OP_MSK 0x7f 62#define MEI_HBM_CMD_OP_MSK 0x7f
57/* Host bus message command RESPONSE */ 63/* Host bus message command RESPONSE */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 3f3405269c39..89d8e1304077 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -424,6 +424,24 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
424EXPORT_SYMBOL_GPL(mei_irq_write_handler); 424EXPORT_SYMBOL_GPL(mei_irq_write_handler);
425 425
426 426
427/**
428 * mei_connect_timeout - connect/disconnect timeouts
429 *
430 * @cl: host client
431 */
432static void mei_connect_timeout(struct mei_cl *cl)
433{
434 struct mei_device *dev = cl->dev;
435
436 if (cl->state == MEI_FILE_CONNECTING) {
437 if (dev->hbm_f_dot_supported) {
438 cl->state = MEI_FILE_DISCONNECT_REQUIRED;
439 wake_up(&cl->wait);
440 return;
441 }
442 }
443 mei_reset(dev);
444}
427 445
428/** 446/**
429 * mei_timer - timer function. 447 * mei_timer - timer function.
@@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work)
464 if (cl->timer_count) { 482 if (cl->timer_count) {
465 if (--cl->timer_count == 0) { 483 if (--cl->timer_count == 0) {
466 dev_err(dev->dev, "timer: connect/disconnect timeout.\n"); 484 dev_err(dev->dev, "timer: connect/disconnect timeout.\n");
467 mei_reset(dev); 485 mei_connect_timeout(cl);
468 goto out; 486 goto out;
469 } 487 }
470 } 488 }
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 33823f4a1cf2..8bd46cd95b7a 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -89,6 +89,7 @@ enum file_state {
89 MEI_FILE_CONNECTED, 89 MEI_FILE_CONNECTED,
90 MEI_FILE_DISCONNECTING, 90 MEI_FILE_DISCONNECTING,
91 MEI_FILE_DISCONNECT_REPLY, 91 MEI_FILE_DISCONNECT_REPLY,
92 MEI_FILE_DISCONNECT_REQUIRED,
92 MEI_FILE_DISCONNECTED, 93 MEI_FILE_DISCONNECTED,
93}; 94};
94 95
@@ -407,8 +408,9 @@ const char *mei_pg_state_str(enum mei_pg_state state);
407 * @wr_msg : the buffer for hbm control messages 408 * @wr_msg : the buffer for hbm control messages
408 * 409 *
409 * @version : HBM protocol version in use 410 * @version : HBM protocol version in use
410 * @hbm_f_pg_supported : hbm feature pgi protocol 411 * @hbm_f_pg_supported : hbm feature pgi protocol
411 * @hbm_f_dc_supported : hbm feature dynamic clients 412 * @hbm_f_dc_supported : hbm feature dynamic clients
413 * @hbm_f_dot_supported : hbm feature disconnect on timeout
412 * 414 *
413 * @me_clients_rwsem: rw lock over me_clients list 415 * @me_clients_rwsem: rw lock over me_clients list
414 * @me_clients : list of FW clients 416 * @me_clients : list of FW clients
@@ -503,6 +505,7 @@ struct mei_device {
503 struct hbm_version version; 505 struct hbm_version version;
504 unsigned int hbm_f_pg_supported:1; 506 unsigned int hbm_f_pg_supported:1;
505 unsigned int hbm_f_dc_supported:1; 507 unsigned int hbm_f_dc_supported:1;
508 unsigned int hbm_f_dot_supported:1;
506 509
507 struct rw_semaphore me_clients_rwsem; 510 struct rw_semaphore me_clients_rwsem;
508 struct list_head me_clients; 511 struct list_head me_clients;