3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2012, Intel Corporation.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 #include <linux/pci.h>
18 #include <linux/sched.h>
19 #include <linux/wait.h>
20 #include <linux/mei.h>
23 #include "interface.h"
26 * mei_hbm_cl_hdr - construct client hbm header
28 * @hbm_cmd: host bus message command
29 * @buf: buffer for cl header
33 void mei_hbm_cl_hdr(struct mei_cl
*cl
, u8 hbm_cmd
, void *buf
, size_t len
)
35 struct mei_hbm_cl_cmd
*cmd
= buf
;
39 cmd
->hbm_cmd
= hbm_cmd
;
40 cmd
->host_addr
= cl
->host_client_id
;
41 cmd
->me_addr
= cl
->me_client_id
;
45 * same_disconn_addr - tells if they have the same address
47 * @file: private data of the file object.
48 * @disconn: disconnection request.
50 * returns true if addres are same
53 bool mei_hbm_cl_addr_equal(struct mei_cl
*cl
, void *buf
)
55 struct mei_hbm_cl_cmd
*cmd
= buf
;
56 return cl
->host_client_id
== cmd
->host_addr
&&
57 cl
->me_client_id
== cmd
->me_addr
;
62 * mei_hbm_start_req - sends start request message.
64 * @dev: the device structure
66 void mei_hbm_start_req(struct mei_device
*dev
)
68 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
69 struct hbm_host_version_request
*start_req
;
70 const size_t len
= sizeof(struct hbm_host_version_request
);
72 mei_hbm_hdr(mei_hdr
, len
);
74 /* host start message */
75 start_req
= (struct hbm_host_version_request
*)dev
->wr_msg
.data
;
76 memset(start_req
, 0, len
);
77 start_req
->hbm_cmd
= HOST_START_REQ_CMD
;
78 start_req
->host_version
.major_version
= HBM_MAJOR_VERSION
;
79 start_req
->host_version
.minor_version
= HBM_MINOR_VERSION
;
81 dev
->recvd_msg
= false;
82 if (mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
)) {
83 dev_dbg(&dev
->pdev
->dev
, "write send version message to FW fail.\n");
84 dev
->dev_state
= MEI_DEV_RESETING
;
87 dev
->init_clients_state
= MEI_START_MESSAGE
;
88 dev
->init_clients_timer
= MEI_CLIENTS_INIT_TIMEOUT
;
93 * mei_hbm_enum_clients_req - sends enumeration client request message.
95 * @dev: the device structure
99 static void mei_hbm_enum_clients_req(struct mei_device
*dev
)
101 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
102 struct hbm_host_enum_request
*enum_req
;
103 const size_t len
= sizeof(struct hbm_host_enum_request
);
104 /* enumerate clients */
105 mei_hbm_hdr(mei_hdr
, len
);
107 enum_req
= (struct hbm_host_enum_request
*)dev
->wr_msg
.data
;
108 memset(enum_req
, 0, len
);
109 enum_req
->hbm_cmd
= HOST_ENUM_REQ_CMD
;
111 if (mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
)) {
112 dev
->dev_state
= MEI_DEV_RESETING
;
113 dev_dbg(&dev
->pdev
->dev
, "write send enumeration request message to FW fail.\n");
116 dev
->init_clients_state
= MEI_ENUM_CLIENTS_MESSAGE
;
117 dev
->init_clients_timer
= MEI_CLIENTS_INIT_TIMEOUT
;
122 * mei_hbm_prop_requsest - request property for a single client
124 * @dev: the device structure
129 static int mei_hbm_prop_req(struct mei_device
*dev
)
132 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
133 struct hbm_props_request
*prop_req
;
134 const size_t len
= sizeof(struct hbm_props_request
);
135 unsigned long next_client_index
;
139 client_num
= dev
->me_client_presentation_num
;
141 next_client_index
= find_next_bit(dev
->me_clients_map
, MEI_CLIENTS_MAX
,
142 dev
->me_client_index
);
144 /* We got all client properties */
145 if (next_client_index
== MEI_CLIENTS_MAX
) {
146 schedule_work(&dev
->init_work
);
151 dev
->me_clients
[client_num
].client_id
= next_client_index
;
152 dev
->me_clients
[client_num
].mei_flow_ctrl_creds
= 0;
154 mei_hbm_hdr(mei_hdr
, len
);
155 prop_req
= (struct hbm_props_request
*)dev
->wr_msg
.data
;
157 memset(prop_req
, 0, sizeof(struct hbm_props_request
));
160 prop_req
->hbm_cmd
= HOST_CLIENT_PROPERTIES_REQ_CMD
;
161 prop_req
->address
= next_client_index
;
163 if (mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
)) {
164 dev
->dev_state
= MEI_DEV_RESETING
;
165 dev_err(&dev
->pdev
->dev
, "Properties request command failed\n");
171 dev
->init_clients_timer
= MEI_CLIENTS_INIT_TIMEOUT
;
172 dev
->me_client_index
= next_client_index
;
178 * mei_hbm_stop_req_prepare - perpare stop request message
181 * @mei_hdr - mei message header
182 * @data - hbm message body buffer
184 static void mei_hbm_stop_req_prepare(struct mei_device
*dev
,
185 struct mei_msg_hdr
*mei_hdr
, unsigned char *data
)
187 struct hbm_host_stop_request
*req
=
188 (struct hbm_host_stop_request
*)data
;
189 const size_t len
= sizeof(struct hbm_host_stop_request
);
191 mei_hbm_hdr(mei_hdr
, len
);
194 req
->hbm_cmd
= HOST_STOP_REQ_CMD
;
195 req
->reason
= DRIVER_STOP_REQUEST
;
199 * mei_hbm_cl_flow_control_req - sends flow control requst.
201 * @dev: the device structure
204 * This function returns -EIO on write failure
206 int mei_hbm_cl_flow_control_req(struct mei_device
*dev
, struct mei_cl
*cl
)
208 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
209 const size_t len
= sizeof(struct hbm_flow_control
);
211 mei_hbm_hdr(mei_hdr
, len
);
212 mei_hbm_cl_hdr(cl
, MEI_FLOW_CONTROL_CMD
, dev
->wr_msg
.data
, len
);
214 dev_dbg(&dev
->pdev
->dev
, "sending flow control host client = %d, ME client = %d\n",
215 cl
->host_client_id
, cl
->me_client_id
);
217 return mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
);
221 * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
223 * @dev: the device structure
224 * @cl: a client to disconnect from
226 * This function returns -EIO on write failure
228 int mei_hbm_cl_disconnect_req(struct mei_device
*dev
, struct mei_cl
*cl
)
230 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
231 const size_t len
= sizeof(struct hbm_client_connect_request
);
233 mei_hbm_hdr(mei_hdr
, len
);
234 mei_hbm_cl_hdr(cl
, CLIENT_DISCONNECT_REQ_CMD
, dev
->wr_msg
.data
, len
);
236 return mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
);
240 * mei_hbm_cl_connect_req - send connection request to specific me client
242 * @dev: the device structure
243 * @cl: a client to connect to
245 * returns -EIO on write failure
247 int mei_hbm_cl_connect_req(struct mei_device
*dev
, struct mei_cl
*cl
)
249 struct mei_msg_hdr
*mei_hdr
= &dev
->wr_msg
.hdr
;
250 const size_t len
= sizeof(struct hbm_client_connect_request
);
252 mei_hbm_hdr(mei_hdr
, len
);
253 mei_hbm_cl_hdr(cl
, CLIENT_CONNECT_REQ_CMD
, dev
->wr_msg
.data
, len
);
255 return mei_write_message(dev
, mei_hdr
, dev
->wr_msg
.data
);
259 * mei_client_disconnect_request - disconnect request initiated by me
260 * host sends disoconnect response
262 * @dev: the device structure.
263 * @disconnect_req: disconnect request bus message from the me
265 static void mei_hbm_fw_disconnect_req(struct mei_device
*dev
,
266 struct hbm_client_connect_request
*disconnect_req
)
268 struct mei_cl
*cl
, *next
;
269 const size_t len
= sizeof(struct hbm_client_connect_response
);
271 list_for_each_entry_safe(cl
, next
, &dev
->file_list
, link
) {
272 if (mei_hbm_cl_addr_equal(cl
, disconnect_req
)) {
273 dev_dbg(&dev
->pdev
->dev
, "disconnect request host client %d ME client %d.\n",
274 disconnect_req
->host_addr
,
275 disconnect_req
->me_addr
);
276 cl
->state
= MEI_FILE_DISCONNECTED
;
278 if (cl
== &dev
->wd_cl
)
279 dev
->wd_pending
= false;
280 else if (cl
== &dev
->iamthif_cl
)
281 dev
->iamthif_timer
= 0;
283 /* prepare disconnect response */
284 mei_hbm_hdr(&dev
->wr_ext_msg
.hdr
, len
);
285 mei_hbm_cl_hdr(cl
, CLIENT_DISCONNECT_RES_CMD
,
286 dev
->wr_ext_msg
.data
, len
);
294 * mei_hbm_dispatch - bottom half read routine after ISR to
295 * handle the read bus message cmd processing.
297 * @dev: the device structure
298 * @mei_hdr: header of bus message
300 void mei_hbm_dispatch(struct mei_device
*dev
, struct mei_msg_hdr
*hdr
)
302 struct mei_bus_message
*mei_msg
;
303 struct mei_me_client
*me_client
;
304 struct hbm_host_version_response
*version_res
;
305 struct hbm_client_connect_response
*connect_res
;
306 struct hbm_client_connect_response
*disconnect_res
;
307 struct hbm_client_connect_request
*disconnect_req
;
308 struct hbm_flow_control
*flow_control
;
309 struct hbm_props_response
*props_res
;
310 struct hbm_host_enum_response
*enum_res
;
312 /* read the message to our buffer */
313 BUG_ON(hdr
->length
>= sizeof(dev
->rd_msg_buf
));
314 mei_read_slots(dev
, dev
->rd_msg_buf
, hdr
->length
);
315 mei_msg
= (struct mei_bus_message
*)dev
->rd_msg_buf
;
317 switch (mei_msg
->hbm_cmd
) {
318 case HOST_START_RES_CMD
:
319 version_res
= (struct hbm_host_version_response
*)mei_msg
;
320 if (!version_res
->host_version_supported
) {
321 dev
->version
= version_res
->me_max_version
;
322 dev_dbg(&dev
->pdev
->dev
, "version mismatch.\n");
324 mei_hbm_stop_req_prepare(dev
, &dev
->wr_msg
.hdr
,
326 mei_write_message(dev
, &dev
->wr_msg
.hdr
,
331 dev
->version
.major_version
= HBM_MAJOR_VERSION
;
332 dev
->version
.minor_version
= HBM_MINOR_VERSION
;
333 if (dev
->dev_state
== MEI_DEV_INIT_CLIENTS
&&
334 dev
->init_clients_state
== MEI_START_MESSAGE
) {
335 dev
->init_clients_timer
= 0;
336 mei_hbm_enum_clients_req(dev
);
338 dev
->recvd_msg
= false;
339 dev_dbg(&dev
->pdev
->dev
, "reset due to received hbm: host start\n");
344 dev
->recvd_msg
= true;
345 dev_dbg(&dev
->pdev
->dev
, "host start response message received.\n");
348 case CLIENT_CONNECT_RES_CMD
:
349 connect_res
= (struct hbm_client_connect_response
*) mei_msg
;
350 mei_client_connect_response(dev
, connect_res
);
351 dev_dbg(&dev
->pdev
->dev
, "client connect response message received.\n");
352 wake_up(&dev
->wait_recvd_msg
);
355 case CLIENT_DISCONNECT_RES_CMD
:
356 disconnect_res
= (struct hbm_client_connect_response
*) mei_msg
;
357 mei_client_disconnect_response(dev
, disconnect_res
);
358 dev_dbg(&dev
->pdev
->dev
, "client disconnect response message received.\n");
359 wake_up(&dev
->wait_recvd_msg
);
362 case MEI_FLOW_CONTROL_CMD
:
363 flow_control
= (struct hbm_flow_control
*) mei_msg
;
364 mei_client_flow_control_response(dev
, flow_control
);
365 dev_dbg(&dev
->pdev
->dev
, "client flow control response message received.\n");
368 case HOST_CLIENT_PROPERTIES_RES_CMD
:
369 props_res
= (struct hbm_props_response
*)mei_msg
;
370 me_client
= &dev
->me_clients
[dev
->me_client_presentation_num
];
372 if (props_res
->status
|| !dev
->me_clients
) {
373 dev_dbg(&dev
->pdev
->dev
, "reset due to received host client properties response bus message wrong status.\n");
378 if (me_client
->client_id
!= props_res
->address
) {
379 dev_err(&dev
->pdev
->dev
,
380 "Host client properties reply mismatch\n");
386 if (dev
->dev_state
!= MEI_DEV_INIT_CLIENTS
||
387 dev
->init_clients_state
!= MEI_CLIENT_PROPERTIES_MESSAGE
) {
388 dev_err(&dev
->pdev
->dev
,
389 "Unexpected client properties reply\n");
395 me_client
->props
= props_res
->client_properties
;
396 dev
->me_client_index
++;
397 dev
->me_client_presentation_num
++;
399 /* request property for the next client */
400 mei_hbm_prop_req(dev
);
404 case HOST_ENUM_RES_CMD
:
405 enum_res
= (struct hbm_host_enum_response
*) mei_msg
;
406 memcpy(dev
->me_clients_map
, enum_res
->valid_addresses
, 32);
407 if (dev
->dev_state
== MEI_DEV_INIT_CLIENTS
&&
408 dev
->init_clients_state
== MEI_ENUM_CLIENTS_MESSAGE
) {
409 dev
->init_clients_timer
= 0;
410 dev
->me_client_presentation_num
= 0;
411 dev
->me_client_index
= 0;
412 mei_allocate_me_clients_storage(dev
);
413 dev
->init_clients_state
=
414 MEI_CLIENT_PROPERTIES_MESSAGE
;
416 /* first property reqeust */
417 mei_hbm_prop_req(dev
);
419 dev_dbg(&dev
->pdev
->dev
, "reset due to received host enumeration clients response bus message.\n");
425 case HOST_STOP_RES_CMD
:
426 dev
->dev_state
= MEI_DEV_DISABLED
;
427 dev_dbg(&dev
->pdev
->dev
, "resetting because of FW stop response.\n");
431 case CLIENT_DISCONNECT_REQ_CMD
:
432 /* search for client */
433 disconnect_req
= (struct hbm_client_connect_request
*)mei_msg
;
434 mei_hbm_fw_disconnect_req(dev
, disconnect_req
);
437 case ME_STOP_REQ_CMD
:
439 mei_hbm_stop_req_prepare(dev
, &dev
->wr_ext_msg
.hdr
,
440 dev
->wr_ext_msg
.data
);