aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2015-07-23 14:37:12 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-03 20:25:51 -0400
commit70ef835c84b3b88e274a53bf80a70940ae178a91 (patch)
tree8404cb25e3671d6ab273f0c48de87c2435e8868b
parent6009595a66e460af0b170d736398c49395cb4499 (diff)
mei: support for dynamic clients
HBM version 2.0 and above allows ME clients in the system to register/unregister after the system is fully initialized. Clients may be added or removed after enum_resp message was received 1. To preserve backward compatibility the driver can opt-in to receive client add messages by setting allow_add field in enum_req 2. A new client is added upon reception of MEI_HBM_ADD_CLIENT_REQ_CMD 3. A client is removed in a lazy manner when connection request respond with MEI_HBMS_CLIENT_NOT_FOUND status Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/mei/debugfs.c2
-rw-r--r--drivers/misc/mei/hbm.c92
-rw-r--r--drivers/misc/mei/hw.h50
-rw-r--r--drivers/misc/mei/mei_dev.h2
4 files changed, 144 insertions, 2 deletions
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index eb868341247f..a65a1e6f386f 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -154,6 +154,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
154 pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n"); 154 pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n");
155 pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n", 155 pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n",
156 dev->hbm_f_pg_supported); 156 dev->hbm_f_pg_supported);
157 pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n",
158 dev->hbm_f_dc_supported);
157 } 159 }
158 160
159 pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", 161 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 a4f283165a33..d4dba639db37 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -299,6 +299,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev)
299 enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data; 299 enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
300 memset(enum_req, 0, len); 300 memset(enum_req, 0, len);
301 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; 301 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
302 enum_req->allow_add = dev->hbm_f_dc_supported;
302 303
303 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); 304 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
304 if (ret) { 305 if (ret) {
@@ -344,6 +345,64 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
344} 345}
345 346
346/** 347/**
348 * mei_hbm_add_cl_resp - send response to fw on client add request
349 *
350 * @dev: the device structure
351 * @addr: me address
352 * @status: response status
353 *
354 * Return: 0 on success and < 0 on failure
355 */
356static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status)
357{
358 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
359 struct hbm_add_client_response *resp;
360 const size_t len = sizeof(struct hbm_add_client_response);
361 int ret;
362
363 dev_dbg(dev->dev, "adding client response\n");
364
365 resp = (struct hbm_add_client_response *)dev->wr_msg.data;
366
367 mei_hbm_hdr(mei_hdr, len);
368 memset(resp, 0, sizeof(struct hbm_add_client_response));
369
370 resp->hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD;
371 resp->me_addr = addr;
372 resp->status = status;
373
374 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
375 if (ret)
376 dev_err(dev->dev, "add client response write failed: ret = %d\n",
377 ret);
378 return ret;
379}
380
381/**
382 * mei_hbm_fw_add_cl_req - request from the fw to add a client
383 *
384 * @dev: the device structure
385 * @req: add client request
386 *
387 * Return: 0 on success and < 0 on failure
388 */
389static int mei_hbm_fw_add_cl_req(struct mei_device *dev,
390 struct hbm_add_client_request *req)
391{
392 int ret;
393 u8 status = MEI_HBMS_SUCCESS;
394
395 BUILD_BUG_ON(sizeof(struct hbm_add_client_request) !=
396 sizeof(struct hbm_props_response));
397
398 ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req);
399 if (ret)
400 status = !MEI_HBMS_SUCCESS;
401
402 return mei_hbm_add_cl_resp(dev, req->me_addr, status);
403}
404
405/**
347 * mei_hbm_prop_req - request property for a single client 406 * mei_hbm_prop_req - request property for a single client
348 * 407 *
349 * @dev: the device structure 408 * @dev: the device structure
@@ -610,8 +669,11 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
610 669
611 if (rs->status == MEI_CL_CONN_SUCCESS) 670 if (rs->status == MEI_CL_CONN_SUCCESS)
612 cl->state = MEI_FILE_CONNECTED; 671 cl->state = MEI_FILE_CONNECTED;
613 else 672 else {
614 cl->state = MEI_FILE_DISCONNECT_REPLY; 673 cl->state = MEI_FILE_DISCONNECT_REPLY;
674 if (rs->status == MEI_CL_CONN_NOT_FOUND)
675 mei_me_cl_del(dev, cl->me_cl);
676 }
615 cl->status = mei_cl_conn_status_to_errno(rs->status); 677 cl->status = mei_cl_conn_status_to_errno(rs->status);
616} 678}
617 679
@@ -709,6 +771,9 @@ static void mei_hbm_config_features(struct mei_device *dev)
709 if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && 771 if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
710 dev->version.minor_version >= HBM_MINOR_VERSION_PGI) 772 dev->version.minor_version >= HBM_MINOR_VERSION_PGI)
711 dev->hbm_f_pg_supported = 1; 773 dev->hbm_f_pg_supported = 1;
774
775 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
776 dev->hbm_f_dc_supported = 1;
712} 777}
713 778
714/** 779/**
@@ -740,6 +805,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
740 struct hbm_host_version_response *version_res; 805 struct hbm_host_version_response *version_res;
741 struct hbm_props_response *props_res; 806 struct hbm_props_response *props_res;
742 struct hbm_host_enum_response *enum_res; 807 struct hbm_host_enum_response *enum_res;
808 struct hbm_add_client_request *add_cl_req;
809 int ret;
743 810
744 struct mei_hbm_cl_cmd *cl_cmd; 811 struct mei_hbm_cl_cmd *cl_cmd;
745 struct hbm_client_connect_request *disconnect_req; 812 struct hbm_client_connect_request *disconnect_req;
@@ -937,6 +1004,29 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
937 return -EIO; 1004 return -EIO;
938 } 1005 }
939 break; 1006 break;
1007
1008 case MEI_HBM_ADD_CLIENT_REQ_CMD:
1009 dev_dbg(dev->dev, "hbm: add client request received\n");
1010 /*
1011 * after the host receives the enum_resp
1012 * message clients may be added or removed
1013 */
1014 if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS &&
1015 dev->hbm_state >= MEI_HBM_STOPPED) {
1016 dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n",
1017 dev->dev_state, dev->hbm_state);
1018 return -EPROTO;
1019 }
1020 add_cl_req = (struct hbm_add_client_request *)mei_msg;
1021 ret = mei_hbm_fw_add_cl_req(dev, add_cl_req);
1022 if (ret) {
1023 dev_err(dev->dev, "hbm: add client: failed to send response %d\n",
1024 ret);
1025 return -EIO;
1026 }
1027 dev_dbg(dev->dev, "hbm: add client request processed\n");
1028 break;
1029
940 default: 1030 default:
941 BUG(); 1031 BUG();
942 break; 1032 break;
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index 16fef6dc4dd7..815f40a604b9 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -46,6 +46,12 @@
46#define HBM_MINOR_VERSION_PGI 1 46#define HBM_MINOR_VERSION_PGI 1
47#define HBM_MAJOR_VERSION_PGI 1 47#define HBM_MAJOR_VERSION_PGI 1
48 48
49/*
50 * MEI version with Dynamic clients support
51 */
52#define HBM_MINOR_VERSION_DC 0
53#define HBM_MAJOR_VERSION_DC 2
54
49/* Host bus message command opcode */ 55/* Host bus message command opcode */
50#define MEI_HBM_CMD_OP_MSK 0x7f 56#define MEI_HBM_CMD_OP_MSK 0x7f
51/* Host bus message command RESPONSE */ 57/* Host bus message command RESPONSE */
@@ -81,6 +87,8 @@
81#define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b 87#define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b
82#define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b 88#define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b
83 89
90#define MEI_HBM_ADD_CLIENT_REQ_CMD 0x0f
91#define MEI_HBM_ADD_CLIENT_RES_CMD 0x8f
84/* 92/*
85 * MEI Stop Reason 93 * MEI Stop Reason
86 * used by hbm_host_stop_request.reason 94 * used by hbm_host_stop_request.reason
@@ -213,9 +221,17 @@ struct hbm_me_stop_request {
213 u8 reserved[2]; 221 u8 reserved[2];
214} __packed; 222} __packed;
215 223
224/**
225 * struct hbm_host_enum_request - enumeration request from host to fw
226 *
227 * @hbm_cmd: bus message command header
228 * @allow_add: allow dynamic clients add HBM version >= 2.0
229 * @reserved: reserved
230 */
216struct hbm_host_enum_request { 231struct hbm_host_enum_request {
217 u8 hbm_cmd; 232 u8 hbm_cmd;
218 u8 reserved[3]; 233 u8 allow_add;
234 u8 reserved[2];
219} __packed; 235} __packed;
220 236
221struct hbm_host_enum_response { 237struct hbm_host_enum_response {
@@ -248,6 +264,38 @@ struct hbm_props_response {
248} __packed; 264} __packed;
249 265
250/** 266/**
267 * struct hbm_add_client_request - request to add a client
268 * might be sent by fw after enumeration has already completed
269 *
270 * @hbm_cmd: bus message command header
271 * @me_addr: address of the client in ME
272 * @reserved: reserved
273 * @client_properties: client properties
274 */
275struct hbm_add_client_request {
276 u8 hbm_cmd;
277 u8 me_addr;
278 u8 reserved[2];
279 struct mei_client_properties client_properties;
280} __packed;
281
282/**
283 * struct hbm_add_client_response - response to add a client
284 * sent by the host to report client addition status to fw
285 *
286 * @hbm_cmd: bus message command header
287 * @me_addr: address of the client in ME
288 * @status: if HBMS_SUCCESS then the client can now accept connections.
289 * @reserved: reserved
290 */
291struct hbm_add_client_response {
292 u8 hbm_cmd;
293 u8 me_addr;
294 u8 status;
295 u8 reserved[1];
296} __packed;
297
298/**
251 * struct hbm_power_gate - power gate request/response 299 * struct hbm_power_gate - power gate request/response
252 * 300 *
253 * @hbm_cmd: bus message command header 301 * @hbm_cmd: bus message command header
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 71c55f4cabb4..33823f4a1cf2 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -408,6 +408,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
408 * 408 *
409 * @version : HBM protocol version in use 409 * @version : HBM protocol version in use
410 * @hbm_f_pg_supported : hbm feature pgi protocol 410 * @hbm_f_pg_supported : hbm feature pgi protocol
411 * @hbm_f_dc_supported : hbm feature dynamic clients
411 * 412 *
412 * @me_clients_rwsem: rw lock over me_clients list 413 * @me_clients_rwsem: rw lock over me_clients list
413 * @me_clients : list of FW clients 414 * @me_clients : list of FW clients
@@ -501,6 +502,7 @@ struct mei_device {
501 502
502 struct hbm_version version; 503 struct hbm_version version;
503 unsigned int hbm_f_pg_supported:1; 504 unsigned int hbm_f_pg_supported:1;
505 unsigned int hbm_f_dc_supported:1;
504 506
505 struct rw_semaphore me_clients_rwsem; 507 struct rw_semaphore me_clients_rwsem;
506 struct list_head me_clients; 508 struct list_head me_clients;