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>
This commit is contained in:
		
							parent
							
								
									6009595a66
								
							
						
					
					
						commit
						70ef835c84
					
				| @ -154,6 +154,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, | ||||
| 		pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n"); | ||||
| 		pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n", | ||||
| 				 dev->hbm_f_pg_supported); | ||||
| 		pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", | ||||
| 				 dev->hbm_f_dc_supported); | ||||
| 	} | ||||
| 
 | ||||
| 	pos += scnprintf(buf + pos, bufsz - pos, "pg:  %s, %s\n", | ||||
|  | ||||
| @ -299,6 +299,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev) | ||||
| 	enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data; | ||||
| 	memset(enum_req, 0, len); | ||||
| 	enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; | ||||
| 	enum_req->allow_add = dev->hbm_f_dc_supported; | ||||
| 
 | ||||
| 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); | ||||
| 	if (ret) { | ||||
| @ -343,6 +344,64 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * mei_hbm_add_cl_resp - send response to fw on client add request | ||||
|  * | ||||
|  * @dev: the device structure | ||||
|  * @addr: me address | ||||
|  * @status: response status | ||||
|  * | ||||
|  * Return: 0 on success and < 0 on failure | ||||
|  */ | ||||
| static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) | ||||
| { | ||||
| 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; | ||||
| 	struct hbm_add_client_response *resp; | ||||
| 	const size_t len = sizeof(struct hbm_add_client_response); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	dev_dbg(dev->dev, "adding client response\n"); | ||||
| 
 | ||||
| 	resp = (struct hbm_add_client_response *)dev->wr_msg.data; | ||||
| 
 | ||||
| 	mei_hbm_hdr(mei_hdr, len); | ||||
| 	memset(resp, 0, sizeof(struct hbm_add_client_response)); | ||||
| 
 | ||||
| 	resp->hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD; | ||||
| 	resp->me_addr = addr; | ||||
| 	resp->status  = status; | ||||
| 
 | ||||
| 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); | ||||
| 	if (ret) | ||||
| 		dev_err(dev->dev, "add client response write failed: ret = %d\n", | ||||
| 			ret); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * mei_hbm_fw_add_cl_req - request from the fw to add a client | ||||
|  * | ||||
|  * @dev: the device structure | ||||
|  * @req: add client request | ||||
|  * | ||||
|  * Return: 0 on success and < 0 on failure | ||||
|  */ | ||||
| static int mei_hbm_fw_add_cl_req(struct mei_device *dev, | ||||
| 			      struct hbm_add_client_request *req) | ||||
| { | ||||
| 	int ret; | ||||
| 	u8 status = MEI_HBMS_SUCCESS; | ||||
| 
 | ||||
| 	BUILD_BUG_ON(sizeof(struct hbm_add_client_request) != | ||||
| 			sizeof(struct hbm_props_response)); | ||||
| 
 | ||||
| 	ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req); | ||||
| 	if (ret) | ||||
| 		status = !MEI_HBMS_SUCCESS; | ||||
| 
 | ||||
| 	return mei_hbm_add_cl_resp(dev, req->me_addr, status); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * mei_hbm_prop_req - request property for a single client | ||||
|  * | ||||
| @ -610,8 +669,11 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl, | ||||
| 
 | ||||
| 	if (rs->status == MEI_CL_CONN_SUCCESS) | ||||
| 		cl->state = MEI_FILE_CONNECTED; | ||||
| 	else | ||||
| 	else { | ||||
| 		cl->state = MEI_FILE_DISCONNECT_REPLY; | ||||
| 		if (rs->status == MEI_CL_CONN_NOT_FOUND) | ||||
| 			mei_me_cl_del(dev, cl->me_cl); | ||||
| 	} | ||||
| 	cl->status = mei_cl_conn_status_to_errno(rs->status); | ||||
| } | ||||
| 
 | ||||
| @ -709,6 +771,9 @@ static void mei_hbm_config_features(struct mei_device *dev) | ||||
| 	if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && | ||||
| 	    dev->version.minor_version >= HBM_MINOR_VERSION_PGI) | ||||
| 		dev->hbm_f_pg_supported = 1; | ||||
| 
 | ||||
| 	if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) | ||||
| 		dev->hbm_f_dc_supported = 1; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -740,6 +805,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | ||||
| 	struct hbm_host_version_response *version_res; | ||||
| 	struct hbm_props_response *props_res; | ||||
| 	struct hbm_host_enum_response *enum_res; | ||||
| 	struct hbm_add_client_request *add_cl_req; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	struct mei_hbm_cl_cmd *cl_cmd; | ||||
| 	struct hbm_client_connect_request *disconnect_req; | ||||
| @ -937,6 +1004,29 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
| 	case MEI_HBM_ADD_CLIENT_REQ_CMD: | ||||
| 		dev_dbg(dev->dev, "hbm: add client request received\n"); | ||||
| 		/*
 | ||||
| 		 * after the host receives the enum_resp | ||||
| 		 * message clients may be added or removed | ||||
| 		 */ | ||||
| 		if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS && | ||||
| 		    dev->hbm_state >= MEI_HBM_STOPPED) { | ||||
| 			dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n", | ||||
| 				dev->dev_state, dev->hbm_state); | ||||
| 			return -EPROTO; | ||||
| 		} | ||||
| 		add_cl_req = (struct hbm_add_client_request *)mei_msg; | ||||
| 		ret = mei_hbm_fw_add_cl_req(dev, add_cl_req); | ||||
| 		if (ret) { | ||||
| 			dev_err(dev->dev, "hbm: add client: failed to send response %d\n", | ||||
| 				ret); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		dev_dbg(dev->dev, "hbm: add client request processed\n"); | ||||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		BUG(); | ||||
| 		break; | ||||
|  | ||||
| @ -46,6 +46,12 @@ | ||||
| #define HBM_MINOR_VERSION_PGI               1 | ||||
| #define HBM_MAJOR_VERSION_PGI               1 | ||||
| 
 | ||||
| /*
 | ||||
|  * MEI version with Dynamic clients support | ||||
|  */ | ||||
| #define HBM_MINOR_VERSION_DC               0 | ||||
| #define HBM_MAJOR_VERSION_DC               2 | ||||
| 
 | ||||
| /* Host bus message command opcode */ | ||||
| #define MEI_HBM_CMD_OP_MSK                  0x7f | ||||
| /* Host bus message command RESPONSE */ | ||||
| @ -81,6 +87,8 @@ | ||||
| #define MEI_PG_ISOLATION_EXIT_REQ_CMD       0x0b | ||||
| #define MEI_PG_ISOLATION_EXIT_RES_CMD       0x8b | ||||
| 
 | ||||
| #define MEI_HBM_ADD_CLIENT_REQ_CMD          0x0f | ||||
| #define MEI_HBM_ADD_CLIENT_RES_CMD          0x8f | ||||
| /*
 | ||||
|  * MEI Stop Reason | ||||
|  * used by hbm_host_stop_request.reason | ||||
| @ -213,9 +221,17 @@ struct hbm_me_stop_request { | ||||
| 	u8 reserved[2]; | ||||
| } __packed; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct hbm_host_enum_request -  enumeration request from host to fw | ||||
|  * | ||||
|  * @hbm_cmd: bus message command header | ||||
|  * @allow_add: allow dynamic clients add HBM version >= 2.0 | ||||
|  * @reserved: reserved | ||||
|  */ | ||||
| struct hbm_host_enum_request { | ||||
| 	u8 hbm_cmd; | ||||
| 	u8 reserved[3]; | ||||
| 	u8 allow_add; | ||||
| 	u8 reserved[2]; | ||||
| } __packed; | ||||
| 
 | ||||
| struct hbm_host_enum_response { | ||||
| @ -247,6 +263,38 @@ struct hbm_props_response { | ||||
| 	struct mei_client_properties client_properties; | ||||
| } __packed; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct hbm_add_client_request - request to add a client | ||||
|  *     might be sent by fw after enumeration has already completed | ||||
|  * | ||||
|  * @hbm_cmd: bus message command header | ||||
|  * @me_addr: address of the client in ME | ||||
|  * @reserved: reserved | ||||
|  * @client_properties: client properties | ||||
|  */ | ||||
| struct hbm_add_client_request { | ||||
| 	u8 hbm_cmd; | ||||
| 	u8 me_addr; | ||||
| 	u8 reserved[2]; | ||||
| 	struct mei_client_properties client_properties; | ||||
| } __packed; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct hbm_add_client_response - response to add a client | ||||
|  *     sent by the host to report client addition status to fw | ||||
|  * | ||||
|  * @hbm_cmd: bus message command header | ||||
|  * @me_addr: address of the client in ME | ||||
|  * @status: if HBMS_SUCCESS then the client can now accept connections. | ||||
|  * @reserved: reserved | ||||
|  */ | ||||
| struct hbm_add_client_response { | ||||
| 	u8 hbm_cmd; | ||||
| 	u8 me_addr; | ||||
| 	u8 status; | ||||
| 	u8 reserved[1]; | ||||
| } __packed; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct hbm_power_gate - power gate request/response | ||||
|  * | ||||
|  | ||||
| @ -408,6 +408,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); | ||||
|  * | ||||
|  * @version     : HBM protocol version in use | ||||
|  * @hbm_f_pg_supported : hbm feature pgi protocol | ||||
|  * @hbm_f_dc_supported : hbm feature dynamic clients | ||||
|  * | ||||
|  * @me_clients_rwsem: rw lock over me_clients list | ||||
|  * @me_clients  : list of FW clients | ||||
| @ -501,6 +502,7 @@ struct mei_device { | ||||
| 
 | ||||
| 	struct hbm_version version; | ||||
| 	unsigned int hbm_f_pg_supported:1; | ||||
| 	unsigned int hbm_f_dc_supported:1; | ||||
| 
 | ||||
| 	struct rw_semaphore me_clients_rwsem; | ||||
| 	struct list_head me_clients; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user