diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2015-07-23 14:37:12 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-08-03 20:25:51 -0400 |
commit | 70ef835c84b3b88e274a53bf80a70940ae178a91 (patch) | |
tree | 8404cb25e3671d6ab273f0c48de87c2435e8868b | |
parent | 6009595a66e460af0b170d736398c49395cb4499 (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.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 92 | ||||
-rw-r--r-- | drivers/misc/mei/hw.h | 50 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 2 |
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 | */ | ||
356 | static 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 | */ | ||
389 | static 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 | */ | ||
216 | struct hbm_host_enum_request { | 231 | struct 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 | ||
221 | struct hbm_host_enum_response { | 237 | struct 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 | */ | ||
275 | struct 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 | */ | ||
291 | struct 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; |