Commit | Line | Data |
---|---|---|
bb1b0133 TW |
1 | /* |
2 | * | |
3 | * Intel Management Engine Interface (Intel MEI) Linux driver | |
4 | * Copyright (c) 2003-2012, Intel Corporation. | |
5 | * | |
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. | |
9 | * | |
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 | |
13 | * more details. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <linux/pci.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/wait.h> | |
20 | #include <linux/mei.h> | |
21 | ||
22 | #include "mei_dev.h" | |
23 | #include "interface.h" | |
24 | ||
cd51ed64 TW |
25 | /** |
26 | * mei_hbm_cl_hdr - construct client hbm header | |
27 | * @cl: - client | |
28 | * @hbm_cmd: host bus message command | |
29 | * @buf: buffer for cl header | |
30 | * @len: buffer length | |
31 | */ | |
32 | static inline | |
33 | void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len) | |
34 | { | |
35 | struct mei_hbm_cl_cmd *cmd = buf; | |
36 | ||
37 | memset(cmd, 0, len); | |
38 | ||
39 | cmd->hbm_cmd = hbm_cmd; | |
40 | cmd->host_addr = cl->host_client_id; | |
41 | cmd->me_addr = cl->me_client_id; | |
42 | } | |
43 | ||
44 | /** | |
45 | * same_disconn_addr - tells if they have the same address | |
46 | * | |
47 | * @file: private data of the file object. | |
48 | * @disconn: disconnection request. | |
49 | * | |
50 | * returns true if addres are same | |
51 | */ | |
52 | static inline | |
53 | bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) | |
54 | { | |
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; | |
58 | } | |
59 | ||
60 | ||
6bbda15f TW |
61 | /** |
62 | * is_treat_specially_client - checks if the message belongs | |
63 | * to the file private data. | |
64 | * | |
65 | * @cl: private data of the file object | |
66 | * @rs: connect response bus message | |
67 | * | |
68 | */ | |
69 | static bool is_treat_specially_client(struct mei_cl *cl, | |
70 | struct hbm_client_connect_response *rs) | |
71 | { | |
72 | if (mei_hbm_cl_addr_equal(cl, rs)) { | |
73 | if (!rs->status) { | |
74 | cl->state = MEI_FILE_CONNECTED; | |
75 | cl->status = 0; | |
76 | ||
77 | } else { | |
78 | cl->state = MEI_FILE_DISCONNECTED; | |
79 | cl->status = -ENODEV; | |
80 | } | |
81 | cl->timer_count = 0; | |
82 | ||
83 | return true; | |
84 | } | |
85 | return false; | |
86 | } | |
87 | ||
bb1b0133 | 88 | /** |
8120e720 | 89 | * mei_hbm_start_req - sends start request message. |
bb1b0133 TW |
90 | * |
91 | * @dev: the device structure | |
bb1b0133 | 92 | */ |
8120e720 | 93 | void mei_hbm_start_req(struct mei_device *dev) |
bb1b0133 | 94 | { |
e46f1874 | 95 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
96 | struct hbm_host_version_request *start_req; |
97 | const size_t len = sizeof(struct hbm_host_version_request); | |
98 | ||
e46f1874 | 99 | mei_hbm_hdr(mei_hdr, len); |
bb1b0133 TW |
100 | |
101 | /* host start message */ | |
e46f1874 | 102 | start_req = (struct hbm_host_version_request *)dev->wr_msg.data; |
bb1b0133 TW |
103 | memset(start_req, 0, len); |
104 | start_req->hbm_cmd = HOST_START_REQ_CMD; | |
105 | start_req->host_version.major_version = HBM_MAJOR_VERSION; | |
106 | start_req->host_version.minor_version = HBM_MINOR_VERSION; | |
107 | ||
108 | dev->recvd_msg = false; | |
e46f1874 | 109 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { |
bb1b0133 TW |
110 | dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); |
111 | dev->dev_state = MEI_DEV_RESETING; | |
112 | mei_reset(dev, 1); | |
113 | } | |
114 | dev->init_clients_state = MEI_START_MESSAGE; | |
115 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | |
116 | return ; | |
117 | } | |
118 | ||
119 | /** | |
8120e720 | 120 | * mei_hbm_enum_clients_req - sends enumeration client request message. |
bb1b0133 TW |
121 | * |
122 | * @dev: the device structure | |
123 | * | |
124 | * returns none. | |
125 | */ | |
8120e720 | 126 | static void mei_hbm_enum_clients_req(struct mei_device *dev) |
bb1b0133 | 127 | { |
e46f1874 | 128 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
129 | struct hbm_host_enum_request *enum_req; |
130 | const size_t len = sizeof(struct hbm_host_enum_request); | |
131 | /* enumerate clients */ | |
e46f1874 | 132 | mei_hbm_hdr(mei_hdr, len); |
bb1b0133 | 133 | |
e46f1874 TW |
134 | enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data; |
135 | memset(enum_req, 0, len); | |
bb1b0133 TW |
136 | enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; |
137 | ||
e46f1874 | 138 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { |
bb1b0133 TW |
139 | dev->dev_state = MEI_DEV_RESETING; |
140 | dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); | |
141 | mei_reset(dev, 1); | |
142 | } | |
143 | dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; | |
144 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | |
145 | return; | |
146 | } | |
147 | ||
8120e720 TW |
148 | /** |
149 | * mei_hbm_prop_requsest - request property for a single client | |
150 | * | |
151 | * @dev: the device structure | |
152 | * | |
153 | * returns none. | |
154 | */ | |
bb1b0133 | 155 | |
8120e720 | 156 | static int mei_hbm_prop_req(struct mei_device *dev) |
bb1b0133 TW |
157 | { |
158 | ||
e46f1874 | 159 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
160 | struct hbm_props_request *prop_req; |
161 | const size_t len = sizeof(struct hbm_props_request); | |
162 | unsigned long next_client_index; | |
163 | u8 client_num; | |
164 | ||
165 | ||
166 | client_num = dev->me_client_presentation_num; | |
167 | ||
168 | next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, | |
169 | dev->me_client_index); | |
170 | ||
171 | /* We got all client properties */ | |
172 | if (next_client_index == MEI_CLIENTS_MAX) { | |
173 | schedule_work(&dev->init_work); | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
178 | dev->me_clients[client_num].client_id = next_client_index; | |
179 | dev->me_clients[client_num].mei_flow_ctrl_creds = 0; | |
180 | ||
e46f1874 TW |
181 | mei_hbm_hdr(mei_hdr, len); |
182 | prop_req = (struct hbm_props_request *)dev->wr_msg.data; | |
bb1b0133 TW |
183 | |
184 | memset(prop_req, 0, sizeof(struct hbm_props_request)); | |
185 | ||
186 | ||
187 | prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | |
188 | prop_req->address = next_client_index; | |
189 | ||
e46f1874 | 190 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { |
bb1b0133 TW |
191 | dev->dev_state = MEI_DEV_RESETING; |
192 | dev_err(&dev->pdev->dev, "Properties request command failed\n"); | |
193 | mei_reset(dev, 1); | |
194 | ||
195 | return -EIO; | |
196 | } | |
197 | ||
198 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | |
199 | dev->me_client_index = next_client_index; | |
200 | ||
201 | return 0; | |
202 | } | |
203 | ||
e46f1874 TW |
204 | /** |
205 | * mei_hbm_stop_req_prepare - perpare stop request message | |
206 | * | |
207 | * @dev - mei device | |
208 | * @mei_hdr - mei message header | |
209 | * @data - hbm message body buffer | |
210 | */ | |
211 | static void mei_hbm_stop_req_prepare(struct mei_device *dev, | |
212 | struct mei_msg_hdr *mei_hdr, unsigned char *data) | |
213 | { | |
214 | struct hbm_host_stop_request *req = | |
215 | (struct hbm_host_stop_request *)data; | |
216 | const size_t len = sizeof(struct hbm_host_stop_request); | |
217 | ||
218 | mei_hbm_hdr(mei_hdr, len); | |
219 | ||
220 | memset(req, 0, len); | |
221 | req->hbm_cmd = HOST_STOP_REQ_CMD; | |
222 | req->reason = DRIVER_STOP_REQUEST; | |
223 | } | |
224 | ||
bb1b0133 | 225 | /** |
8120e720 | 226 | * mei_hbm_cl_flow_control_req - sends flow control requst. |
bb1b0133 TW |
227 | * |
228 | * @dev: the device structure | |
8120e720 | 229 | * @cl: client info |
bb1b0133 TW |
230 | * |
231 | * This function returns -EIO on write failure | |
232 | */ | |
8120e720 | 233 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl) |
bb1b0133 | 234 | { |
e46f1874 | 235 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
236 | const size_t len = sizeof(struct hbm_flow_control); |
237 | ||
e46f1874 TW |
238 | mei_hbm_hdr(mei_hdr, len); |
239 | mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len); | |
bb1b0133 | 240 | |
bb1b0133 TW |
241 | dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", |
242 | cl->host_client_id, cl->me_client_id); | |
243 | ||
e46f1874 | 244 | return mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
bb1b0133 TW |
245 | } |
246 | ||
6bbda15f TW |
247 | /** |
248 | * add_single_flow_creds - adds single buffer credentials. | |
249 | * | |
250 | * @file: private data ot the file object. | |
251 | * @flow: flow control. | |
252 | */ | |
253 | static void mei_hbm_add_single_flow_creds(struct mei_device *dev, | |
254 | struct hbm_flow_control *flow) | |
255 | { | |
256 | struct mei_me_client *client; | |
257 | int i; | |
258 | ||
259 | for (i = 0; i < dev->me_clients_num; i++) { | |
260 | client = &dev->me_clients[i]; | |
261 | if (client && flow->me_addr == client->client_id) { | |
262 | if (client->props.single_recv_buf) { | |
263 | client->mei_flow_ctrl_creds++; | |
264 | dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n", | |
265 | flow->me_addr); | |
266 | dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n", | |
267 | client->mei_flow_ctrl_creds); | |
268 | } else { | |
269 | BUG(); /* error in flow control */ | |
270 | } | |
271 | } | |
272 | } | |
273 | } | |
274 | ||
275 | /** | |
276 | * mei_hbm_cl_flow_control_res - flow control response from me | |
277 | * | |
278 | * @dev: the device structure | |
279 | * @flow_control: flow control response bus message | |
280 | */ | |
281 | static void mei_hbm_cl_flow_control_res(struct mei_device *dev, | |
282 | struct hbm_flow_control *flow_control) | |
283 | { | |
284 | struct mei_cl *cl = NULL; | |
285 | struct mei_cl *next = NULL; | |
286 | ||
287 | if (!flow_control->host_addr) { | |
288 | /* single receive buffer */ | |
289 | mei_hbm_add_single_flow_creds(dev, flow_control); | |
290 | return; | |
291 | } | |
292 | ||
293 | /* normal connection */ | |
294 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { | |
295 | if (mei_hbm_cl_addr_equal(cl, flow_control)) { | |
296 | cl->mei_flow_ctrl_creds++; | |
297 | dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n", | |
298 | flow_control->host_addr, flow_control->me_addr); | |
299 | dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n", | |
300 | cl->mei_flow_ctrl_creds); | |
301 | break; | |
302 | } | |
303 | } | |
304 | } | |
305 | ||
306 | ||
bb1b0133 | 307 | /** |
8120e720 | 308 | * mei_hbm_cl_disconnect_req - sends disconnect message to fw. |
bb1b0133 TW |
309 | * |
310 | * @dev: the device structure | |
8120e720 | 311 | * @cl: a client to disconnect from |
bb1b0133 TW |
312 | * |
313 | * This function returns -EIO on write failure | |
314 | */ | |
8120e720 | 315 | int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl) |
bb1b0133 | 316 | { |
e46f1874 | 317 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
318 | const size_t len = sizeof(struct hbm_client_connect_request); |
319 | ||
e46f1874 TW |
320 | mei_hbm_hdr(mei_hdr, len); |
321 | mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len); | |
bb1b0133 | 322 | |
e46f1874 | 323 | return mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
bb1b0133 TW |
324 | } |
325 | ||
6bbda15f TW |
326 | /** |
327 | * mei_hbm_cl_disconnect_res - disconnect response from ME | |
328 | * | |
329 | * @dev: the device structure | |
330 | * @rs: disconnect response bus message | |
331 | */ | |
332 | static void mei_hbm_cl_disconnect_res(struct mei_device *dev, | |
333 | struct hbm_client_connect_response *rs) | |
334 | { | |
335 | struct mei_cl *cl; | |
336 | struct mei_cl_cb *pos = NULL, *next = NULL; | |
337 | ||
338 | dev_dbg(&dev->pdev->dev, | |
339 | "disconnect_response:\n" | |
340 | "ME Client = %d\n" | |
341 | "Host Client = %d\n" | |
342 | "Status = %d\n", | |
343 | rs->me_addr, | |
344 | rs->host_addr, | |
345 | rs->status); | |
346 | ||
347 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { | |
348 | cl = pos->cl; | |
349 | ||
350 | if (!cl) { | |
351 | list_del(&pos->list); | |
352 | return; | |
353 | } | |
354 | ||
355 | dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n"); | |
356 | if (mei_hbm_cl_addr_equal(cl, rs)) { | |
357 | list_del(&pos->list); | |
358 | if (!rs->status) | |
359 | cl->state = MEI_FILE_DISCONNECTED; | |
360 | ||
361 | cl->status = 0; | |
362 | cl->timer_count = 0; | |
363 | break; | |
364 | } | |
365 | } | |
366 | } | |
367 | ||
bb1b0133 | 368 | /** |
8120e720 | 369 | * mei_hbm_cl_connect_req - send connection request to specific me client |
bb1b0133 TW |
370 | * |
371 | * @dev: the device structure | |
8120e720 | 372 | * @cl: a client to connect to |
bb1b0133 | 373 | * |
8120e720 | 374 | * returns -EIO on write failure |
bb1b0133 | 375 | */ |
8120e720 | 376 | int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) |
bb1b0133 | 377 | { |
e46f1874 | 378 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
bb1b0133 TW |
379 | const size_t len = sizeof(struct hbm_client_connect_request); |
380 | ||
e46f1874 TW |
381 | mei_hbm_hdr(mei_hdr, len); |
382 | mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len); | |
bb1b0133 | 383 | |
e46f1874 | 384 | return mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
bb1b0133 TW |
385 | } |
386 | ||
6bbda15f TW |
387 | /** |
388 | * mei_hbm_cl_connect_res - connect resposne from the ME | |
389 | * | |
390 | * @dev: the device structure | |
391 | * @rs: connect response bus message | |
392 | */ | |
393 | static void mei_hbm_cl_connect_res(struct mei_device *dev, | |
394 | struct hbm_client_connect_response *rs) | |
395 | { | |
396 | ||
397 | struct mei_cl *cl; | |
398 | struct mei_cl_cb *pos = NULL, *next = NULL; | |
399 | ||
400 | dev_dbg(&dev->pdev->dev, | |
401 | "connect_response:\n" | |
402 | "ME Client = %d\n" | |
403 | "Host Client = %d\n" | |
404 | "Status = %d\n", | |
405 | rs->me_addr, | |
406 | rs->host_addr, | |
407 | rs->status); | |
408 | ||
409 | /* if WD or iamthif client treat specially */ | |
410 | ||
411 | if (is_treat_specially_client(&dev->wd_cl, rs)) { | |
412 | dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); | |
413 | mei_watchdog_register(dev); | |
414 | ||
415 | return; | |
416 | } | |
417 | ||
418 | if (is_treat_specially_client(&dev->iamthif_cl, rs)) { | |
419 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | |
420 | return; | |
421 | } | |
422 | list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { | |
423 | ||
424 | cl = pos->cl; | |
425 | if (!cl) { | |
426 | list_del(&pos->list); | |
427 | return; | |
428 | } | |
429 | if (pos->fop_type == MEI_FOP_IOCTL) { | |
430 | if (is_treat_specially_client(cl, rs)) { | |
431 | list_del(&pos->list); | |
432 | cl->status = 0; | |
433 | cl->timer_count = 0; | |
434 | break; | |
435 | } | |
436 | } | |
437 | } | |
438 | } | |
439 | ||
440 | ||
bb1b0133 | 441 | /** |
8120e720 TW |
442 | * mei_client_disconnect_request - disconnect request initiated by me |
443 | * host sends disoconnect response | |
bb1b0133 TW |
444 | * |
445 | * @dev: the device structure. | |
8120e720 | 446 | * @disconnect_req: disconnect request bus message from the me |
bb1b0133 | 447 | */ |
8120e720 | 448 | static void mei_hbm_fw_disconnect_req(struct mei_device *dev, |
bb1b0133 TW |
449 | struct hbm_client_connect_request *disconnect_req) |
450 | { | |
cd51ed64 | 451 | struct mei_cl *cl, *next; |
bb1b0133 TW |
452 | const size_t len = sizeof(struct hbm_client_connect_response); |
453 | ||
cd51ed64 TW |
454 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { |
455 | if (mei_hbm_cl_addr_equal(cl, disconnect_req)) { | |
bb1b0133 TW |
456 | dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", |
457 | disconnect_req->host_addr, | |
458 | disconnect_req->me_addr); | |
cd51ed64 TW |
459 | cl->state = MEI_FILE_DISCONNECTED; |
460 | cl->timer_count = 0; | |
461 | if (cl == &dev->wd_cl) | |
bb1b0133 | 462 | dev->wd_pending = false; |
cd51ed64 | 463 | else if (cl == &dev->iamthif_cl) |
bb1b0133 TW |
464 | dev->iamthif_timer = 0; |
465 | ||
466 | /* prepare disconnect response */ | |
e46f1874 | 467 | mei_hbm_hdr(&dev->wr_ext_msg.hdr, len); |
cd51ed64 | 468 | mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD, |
e46f1874 | 469 | dev->wr_ext_msg.data, len); |
bb1b0133 TW |
470 | break; |
471 | } | |
472 | } | |
473 | } | |
474 | ||
475 | ||
476 | /** | |
477 | * mei_hbm_dispatch - bottom half read routine after ISR to | |
478 | * handle the read bus message cmd processing. | |
479 | * | |
480 | * @dev: the device structure | |
481 | * @mei_hdr: header of bus message | |
482 | */ | |
483 | void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |
484 | { | |
485 | struct mei_bus_message *mei_msg; | |
486 | struct mei_me_client *me_client; | |
487 | struct hbm_host_version_response *version_res; | |
488 | struct hbm_client_connect_response *connect_res; | |
489 | struct hbm_client_connect_response *disconnect_res; | |
490 | struct hbm_client_connect_request *disconnect_req; | |
491 | struct hbm_flow_control *flow_control; | |
492 | struct hbm_props_response *props_res; | |
493 | struct hbm_host_enum_response *enum_res; | |
bb1b0133 TW |
494 | |
495 | /* read the message to our buffer */ | |
496 | BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf)); | |
497 | mei_read_slots(dev, dev->rd_msg_buf, hdr->length); | |
498 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; | |
499 | ||
500 | switch (mei_msg->hbm_cmd) { | |
501 | case HOST_START_RES_CMD: | |
502 | version_res = (struct hbm_host_version_response *)mei_msg; | |
e46f1874 | 503 | if (!version_res->host_version_supported) { |
bb1b0133 | 504 | dev->version = version_res->me_max_version; |
e46f1874 | 505 | dev_dbg(&dev->pdev->dev, "version mismatch.\n"); |
bb1b0133 | 506 | |
e46f1874 TW |
507 | mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, |
508 | dev->wr_msg.data); | |
509 | mei_write_message(dev, &dev->wr_msg.hdr, | |
510 | dev->wr_msg.data); | |
511 | return; | |
512 | } | |
bb1b0133 | 513 | |
e46f1874 TW |
514 | dev->version.major_version = HBM_MAJOR_VERSION; |
515 | dev->version.minor_version = HBM_MINOR_VERSION; | |
516 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | |
517 | dev->init_clients_state == MEI_START_MESSAGE) { | |
518 | dev->init_clients_timer = 0; | |
8120e720 | 519 | mei_hbm_enum_clients_req(dev); |
e46f1874 TW |
520 | } else { |
521 | dev->recvd_msg = false; | |
522 | dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n"); | |
523 | mei_reset(dev, 1); | |
bb1b0133 TW |
524 | return; |
525 | } | |
526 | ||
527 | dev->recvd_msg = true; | |
528 | dev_dbg(&dev->pdev->dev, "host start response message received.\n"); | |
529 | break; | |
530 | ||
531 | case CLIENT_CONNECT_RES_CMD: | |
532 | connect_res = (struct hbm_client_connect_response *) mei_msg; | |
6bbda15f | 533 | mei_hbm_cl_connect_res(dev, connect_res); |
bb1b0133 TW |
534 | dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); |
535 | wake_up(&dev->wait_recvd_msg); | |
536 | break; | |
537 | ||
538 | case CLIENT_DISCONNECT_RES_CMD: | |
539 | disconnect_res = (struct hbm_client_connect_response *) mei_msg; | |
6bbda15f | 540 | mei_hbm_cl_disconnect_res(dev, disconnect_res); |
bb1b0133 TW |
541 | dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); |
542 | wake_up(&dev->wait_recvd_msg); | |
543 | break; | |
544 | ||
545 | case MEI_FLOW_CONTROL_CMD: | |
546 | flow_control = (struct hbm_flow_control *) mei_msg; | |
6bbda15f | 547 | mei_hbm_cl_flow_control_res(dev, flow_control); |
bb1b0133 TW |
548 | dev_dbg(&dev->pdev->dev, "client flow control response message received.\n"); |
549 | break; | |
550 | ||
551 | case HOST_CLIENT_PROPERTIES_RES_CMD: | |
552 | props_res = (struct hbm_props_response *)mei_msg; | |
553 | me_client = &dev->me_clients[dev->me_client_presentation_num]; | |
554 | ||
555 | if (props_res->status || !dev->me_clients) { | |
556 | dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); | |
557 | mei_reset(dev, 1); | |
558 | return; | |
559 | } | |
560 | ||
561 | if (me_client->client_id != props_res->address) { | |
562 | dev_err(&dev->pdev->dev, | |
563 | "Host client properties reply mismatch\n"); | |
564 | mei_reset(dev, 1); | |
565 | ||
566 | return; | |
567 | } | |
568 | ||
569 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || | |
570 | dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { | |
571 | dev_err(&dev->pdev->dev, | |
572 | "Unexpected client properties reply\n"); | |
573 | mei_reset(dev, 1); | |
574 | ||
575 | return; | |
576 | } | |
577 | ||
578 | me_client->props = props_res->client_properties; | |
579 | dev->me_client_index++; | |
580 | dev->me_client_presentation_num++; | |
581 | ||
8120e720 TW |
582 | /* request property for the next client */ |
583 | mei_hbm_prop_req(dev); | |
bb1b0133 TW |
584 | |
585 | break; | |
586 | ||
587 | case HOST_ENUM_RES_CMD: | |
588 | enum_res = (struct hbm_host_enum_response *) mei_msg; | |
589 | memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); | |
590 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | |
591 | dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) { | |
592 | dev->init_clients_timer = 0; | |
593 | dev->me_client_presentation_num = 0; | |
594 | dev->me_client_index = 0; | |
595 | mei_allocate_me_clients_storage(dev); | |
596 | dev->init_clients_state = | |
597 | MEI_CLIENT_PROPERTIES_MESSAGE; | |
598 | ||
8120e720 TW |
599 | /* first property reqeust */ |
600 | mei_hbm_prop_req(dev); | |
bb1b0133 TW |
601 | } else { |
602 | dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); | |
603 | mei_reset(dev, 1); | |
604 | return; | |
605 | } | |
606 | break; | |
607 | ||
608 | case HOST_STOP_RES_CMD: | |
609 | dev->dev_state = MEI_DEV_DISABLED; | |
610 | dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n"); | |
611 | mei_reset(dev, 1); | |
612 | break; | |
613 | ||
614 | case CLIENT_DISCONNECT_REQ_CMD: | |
615 | /* search for client */ | |
616 | disconnect_req = (struct hbm_client_connect_request *)mei_msg; | |
8120e720 | 617 | mei_hbm_fw_disconnect_req(dev, disconnect_req); |
bb1b0133 TW |
618 | break; |
619 | ||
620 | case ME_STOP_REQ_CMD: | |
bb1b0133 | 621 | |
e46f1874 TW |
622 | mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, |
623 | dev->wr_ext_msg.data); | |
bb1b0133 | 624 | break; |
bb1b0133 TW |
625 | default: |
626 | BUG(); | |
627 | break; | |
628 | ||
629 | } | |
630 | } | |
631 |