xref: /linux/drivers/misc/mei/hbm.c (revision d91517839e5d95adc0cf4b28caa7af62a71de526)
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 "hbm.h"
24 #include "hw-me.h"
25 
26 /**
27  * mei_hbm_me_cl_allocate - allocates storage for me clients
28  *
29  * @dev: the device structure
30  *
31  * returns 0 on success -ENOMEM on allocation failure
32  */
33 static int mei_hbm_me_cl_allocate(struct mei_device *dev)
34 {
35 	struct mei_me_client *clients;
36 	int b;
37 
38 	dev->me_clients_num = 0;
39 	dev->me_client_presentation_num = 0;
40 	dev->me_client_index = 0;
41 
42 	/* count how many ME clients we have */
43 	for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
44 		dev->me_clients_num++;
45 
46 	if (dev->me_clients_num == 0)
47 		return 0;
48 
49 	kfree(dev->me_clients);
50 	dev->me_clients = NULL;
51 
52 	dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n",
53 		dev->me_clients_num * sizeof(struct mei_me_client));
54 	/* allocate storage for ME clients representation */
55 	clients = kcalloc(dev->me_clients_num,
56 			sizeof(struct mei_me_client), GFP_KERNEL);
57 	if (!clients) {
58 		dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
59 		return -ENOMEM;
60 	}
61 	dev->me_clients = clients;
62 	return 0;
63 }
64 
65 /**
66  * mei_hbm_cl_hdr - construct client hbm header
67  *
68  * @cl: - client
69  * @hbm_cmd: host bus message command
70  * @buf: buffer for cl header
71  * @len: buffer length
72  */
73 static inline
74 void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
75 {
76 	struct mei_hbm_cl_cmd *cmd = buf;
77 
78 	memset(cmd, 0, len);
79 
80 	cmd->hbm_cmd = hbm_cmd;
81 	cmd->host_addr = cl->host_client_id;
82 	cmd->me_addr = cl->me_client_id;
83 }
84 
85 /**
86  * mei_hbm_cl_addr_equal - tells if they have the same address
87  *
88  * @cl: - client
89  * @buf: buffer with cl header
90  *
91  * returns true if addresses are the same
92  */
93 static inline
94 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
95 {
96 	struct mei_hbm_cl_cmd *cmd = buf;
97 	return cl->host_client_id == cmd->host_addr &&
98 		cl->me_client_id == cmd->me_addr;
99 }
100 
101 
102 /**
103  * is_treat_specially_client - checks if the message belongs
104  * to the file private data.
105  *
106  * @cl: private data of the file object
107  * @rs: connect response bus message
108  *
109  */
110 static bool is_treat_specially_client(struct mei_cl *cl,
111 		struct hbm_client_connect_response *rs)
112 {
113 	if (mei_hbm_cl_addr_equal(cl, rs)) {
114 		if (!rs->status) {
115 			cl->state = MEI_FILE_CONNECTED;
116 			cl->status = 0;
117 
118 		} else {
119 			cl->state = MEI_FILE_DISCONNECTED;
120 			cl->status = -ENODEV;
121 		}
122 		cl->timer_count = 0;
123 
124 		return true;
125 	}
126 	return false;
127 }
128 
129 /**
130  * mei_hbm_idle - set hbm to idle state
131  *
132  * @dev: the device structure
133  */
134 void mei_hbm_idle(struct mei_device *dev)
135 {
136 	dev->init_clients_timer = 0;
137 	dev->hbm_state = MEI_HBM_IDLE;
138 }
139 
140 int mei_hbm_start_wait(struct mei_device *dev)
141 {
142 	int ret;
143 	if (dev->hbm_state > MEI_HBM_START)
144 		return 0;
145 
146 	mutex_unlock(&dev->device_lock);
147 	ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
148 			dev->hbm_state == MEI_HBM_IDLE ||
149 			dev->hbm_state >= MEI_HBM_STARTED,
150 			mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
151 	mutex_lock(&dev->device_lock);
152 
153 	if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
154 		dev->hbm_state = MEI_HBM_IDLE;
155 		dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
156 		return -ETIMEDOUT;
157 	}
158 	return 0;
159 }
160 
161 /**
162  * mei_hbm_start_req - sends start request message.
163  *
164  * @dev: the device structure
165  *
166  * returns 0 on success and < 0 on failure
167  */
168 int mei_hbm_start_req(struct mei_device *dev)
169 {
170 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
171 	struct hbm_host_version_request *start_req;
172 	const size_t len = sizeof(struct hbm_host_version_request);
173 	int ret;
174 
175 	mei_hbm_hdr(mei_hdr, len);
176 
177 	/* host start message */
178 	start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
179 	memset(start_req, 0, len);
180 	start_req->hbm_cmd = HOST_START_REQ_CMD;
181 	start_req->host_version.major_version = HBM_MAJOR_VERSION;
182 	start_req->host_version.minor_version = HBM_MINOR_VERSION;
183 
184 	dev->hbm_state = MEI_HBM_IDLE;
185 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
186 	if (ret) {
187 		dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
188 			ret);
189 		return ret;
190 	}
191 
192 	dev->hbm_state = MEI_HBM_START;
193 	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
194 	return 0;
195 }
196 
197 /*
198  * mei_hbm_enum_clients_req - sends enumeration client request message.
199  *
200  * @dev: the device structure
201  *
202  * returns 0 on success and < 0 on failure
203  */
204 static int mei_hbm_enum_clients_req(struct mei_device *dev)
205 {
206 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
207 	struct hbm_host_enum_request *enum_req;
208 	const size_t len = sizeof(struct hbm_host_enum_request);
209 	int ret;
210 
211 	/* enumerate clients */
212 	mei_hbm_hdr(mei_hdr, len);
213 
214 	enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
215 	memset(enum_req, 0, len);
216 	enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
217 
218 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
219 	if (ret) {
220 		dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
221 			ret);
222 		return ret;
223 	}
224 	dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
225 	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
226 	return 0;
227 }
228 
229 /**
230  * mei_hbm_prop_req - request property for a single client
231  *
232  * @dev: the device structure
233  *
234  * returns 0 on success and < 0 on failure
235  */
236 
237 static int mei_hbm_prop_req(struct mei_device *dev)
238 {
239 
240 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
241 	struct hbm_props_request *prop_req;
242 	const size_t len = sizeof(struct hbm_props_request);
243 	unsigned long next_client_index;
244 	unsigned long client_num;
245 	int ret;
246 
247 	client_num = dev->me_client_presentation_num;
248 
249 	next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
250 					  dev->me_client_index);
251 
252 	/* We got all client properties */
253 	if (next_client_index == MEI_CLIENTS_MAX) {
254 		dev->hbm_state = MEI_HBM_STARTED;
255 		schedule_work(&dev->init_work);
256 
257 		return 0;
258 	}
259 
260 	dev->me_clients[client_num].client_id = next_client_index;
261 	dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
262 
263 	mei_hbm_hdr(mei_hdr, len);
264 	prop_req = (struct hbm_props_request *)dev->wr_msg.data;
265 
266 	memset(prop_req, 0, sizeof(struct hbm_props_request));
267 
268 
269 	prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
270 	prop_req->address = next_client_index;
271 
272 	ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
273 	if (ret) {
274 		dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
275 			ret);
276 		return ret;
277 	}
278 
279 	dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
280 	dev->me_client_index = next_client_index;
281 
282 	return 0;
283 }
284 
285 /**
286  * mei_hbm_stop_req_prepare - prepare stop request message
287  *
288  * @dev - mei device
289  * @mei_hdr - mei message header
290  * @data - hbm message body buffer
291  */
292 static void mei_hbm_stop_req_prepare(struct mei_device *dev,
293 		struct mei_msg_hdr *mei_hdr, unsigned char *data)
294 {
295 	struct hbm_host_stop_request *req =
296 			(struct hbm_host_stop_request *)data;
297 	const size_t len = sizeof(struct hbm_host_stop_request);
298 
299 	mei_hbm_hdr(mei_hdr, len);
300 
301 	memset(req, 0, len);
302 	req->hbm_cmd = HOST_STOP_REQ_CMD;
303 	req->reason = DRIVER_STOP_REQUEST;
304 }
305 
306 /**
307  * mei_hbm_cl_flow_control_req - sends flow control request.
308  *
309  * @dev: the device structure
310  * @cl: client info
311  *
312  * This function returns -EIO on write failure
313  */
314 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
315 {
316 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
317 	const size_t len = sizeof(struct hbm_flow_control);
318 
319 	mei_hbm_hdr(mei_hdr, len);
320 	mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
321 
322 	dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
323 		cl->host_client_id, cl->me_client_id);
324 
325 	return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
326 }
327 
328 /**
329  * mei_hbm_add_single_flow_creds - adds single buffer credentials.
330  *
331  * @dev: the device structure
332  * @flow: flow control.
333  */
334 static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
335 				  struct hbm_flow_control *flow)
336 {
337 	struct mei_me_client *client;
338 	int i;
339 
340 	for (i = 0; i < dev->me_clients_num; i++) {
341 		client = &dev->me_clients[i];
342 		if (client && flow->me_addr == client->client_id) {
343 			if (client->props.single_recv_buf) {
344 				client->mei_flow_ctrl_creds++;
345 				dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
346 				    flow->me_addr);
347 				dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
348 				    client->mei_flow_ctrl_creds);
349 			} else {
350 				BUG();	/* error in flow control */
351 			}
352 		}
353 	}
354 }
355 
356 /**
357  * mei_hbm_cl_flow_control_res - flow control response from me
358  *
359  * @dev: the device structure
360  * @flow_control: flow control response bus message
361  */
362 static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
363 		struct hbm_flow_control *flow_control)
364 {
365 	struct mei_cl *cl = NULL;
366 	struct mei_cl *next = NULL;
367 
368 	if (!flow_control->host_addr) {
369 		/* single receive buffer */
370 		mei_hbm_add_single_flow_creds(dev, flow_control);
371 		return;
372 	}
373 
374 	/* normal connection */
375 	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
376 		if (mei_hbm_cl_addr_equal(cl, flow_control)) {
377 			cl->mei_flow_ctrl_creds++;
378 			dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
379 				flow_control->host_addr, flow_control->me_addr);
380 			dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
381 				    cl->mei_flow_ctrl_creds);
382 				break;
383 		}
384 	}
385 }
386 
387 
388 /**
389  * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
390  *
391  * @dev: the device structure
392  * @cl: a client to disconnect from
393  *
394  * This function returns -EIO on write failure
395  */
396 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
397 {
398 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
399 	const size_t len = sizeof(struct hbm_client_connect_request);
400 
401 	mei_hbm_hdr(mei_hdr, len);
402 	mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
403 
404 	return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
405 }
406 
407 /**
408  * mei_hbm_cl_disconnect_res - disconnect response from ME
409  *
410  * @dev: the device structure
411  * @rs: disconnect response bus message
412  */
413 static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
414 		struct hbm_client_connect_response *rs)
415 {
416 	struct mei_cl *cl;
417 	struct mei_cl_cb *pos = NULL, *next = NULL;
418 
419 	dev_dbg(&dev->pdev->dev,
420 			"disconnect_response:\n"
421 			"ME Client = %d\n"
422 			"Host Client = %d\n"
423 			"Status = %d\n",
424 			rs->me_addr,
425 			rs->host_addr,
426 			rs->status);
427 
428 	list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
429 		cl = pos->cl;
430 
431 		if (!cl) {
432 			list_del(&pos->list);
433 			return;
434 		}
435 
436 		dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
437 		if (mei_hbm_cl_addr_equal(cl, rs)) {
438 			list_del(&pos->list);
439 			if (!rs->status)
440 				cl->state = MEI_FILE_DISCONNECTED;
441 
442 			cl->status = 0;
443 			cl->timer_count = 0;
444 			break;
445 		}
446 	}
447 }
448 
449 /**
450  * mei_hbm_cl_connect_req - send connection request to specific me client
451  *
452  * @dev: the device structure
453  * @cl: a client to connect to
454  *
455  * returns -EIO on write failure
456  */
457 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
458 {
459 	struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
460 	const size_t len = sizeof(struct hbm_client_connect_request);
461 
462 	mei_hbm_hdr(mei_hdr, len);
463 	mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
464 
465 	return mei_write_message(dev, mei_hdr,  dev->wr_msg.data);
466 }
467 
468 /**
469  * mei_hbm_cl_connect_res - connect response from the ME
470  *
471  * @dev: the device structure
472  * @rs: connect response bus message
473  */
474 static void mei_hbm_cl_connect_res(struct mei_device *dev,
475 		struct hbm_client_connect_response *rs)
476 {
477 
478 	struct mei_cl *cl;
479 	struct mei_cl_cb *pos = NULL, *next = NULL;
480 
481 	dev_dbg(&dev->pdev->dev,
482 			"connect_response:\n"
483 			"ME Client = %d\n"
484 			"Host Client = %d\n"
485 			"Status = %d\n",
486 			rs->me_addr,
487 			rs->host_addr,
488 			rs->status);
489 
490 	/* if WD or iamthif client treat specially */
491 
492 	if (is_treat_specially_client(&dev->wd_cl, rs)) {
493 		dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
494 		mei_watchdog_register(dev);
495 
496 		return;
497 	}
498 
499 	if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
500 		dev->iamthif_state = MEI_IAMTHIF_IDLE;
501 		return;
502 	}
503 	list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
504 
505 		cl = pos->cl;
506 		if (!cl) {
507 			list_del(&pos->list);
508 			return;
509 		}
510 		if (pos->fop_type == MEI_FOP_IOCTL) {
511 			if (is_treat_specially_client(cl, rs)) {
512 				list_del(&pos->list);
513 				cl->status = 0;
514 				cl->timer_count = 0;
515 				break;
516 			}
517 		}
518 	}
519 }
520 
521 
522 /**
523  * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
524  *  host sends disconnect response
525  *
526  * @dev: the device structure.
527  * @disconnect_req: disconnect request bus message from the me
528  */
529 static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
530 		struct hbm_client_connect_request *disconnect_req)
531 {
532 	struct mei_cl *cl, *next;
533 	const size_t len = sizeof(struct hbm_client_connect_response);
534 
535 	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
536 		if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
537 			dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
538 					disconnect_req->host_addr,
539 					disconnect_req->me_addr);
540 			cl->state = MEI_FILE_DISCONNECTED;
541 			cl->timer_count = 0;
542 			if (cl == &dev->wd_cl)
543 				dev->wd_pending = false;
544 			else if (cl == &dev->iamthif_cl)
545 				dev->iamthif_timer = 0;
546 
547 			/* prepare disconnect response */
548 			mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
549 			mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
550 					 dev->wr_ext_msg.data, len);
551 			break;
552 		}
553 	}
554 }
555 
556 
557 /**
558  * mei_hbm_version_is_supported - checks whether the driver can
559  *     support the hbm version of the device
560  *
561  * @dev: the device structure
562  * returns true if driver can support hbm version of the device
563  */
564 bool mei_hbm_version_is_supported(struct mei_device *dev)
565 {
566 	return	(dev->version.major_version < HBM_MAJOR_VERSION) ||
567 		(dev->version.major_version == HBM_MAJOR_VERSION &&
568 		 dev->version.minor_version <= HBM_MINOR_VERSION);
569 }
570 
571 /**
572  * mei_hbm_dispatch - bottom half read routine after ISR to
573  * handle the read bus message cmd processing.
574  *
575  * @dev: the device structure
576  * @mei_hdr: header of bus message
577  *
578  * returns 0 on success and < 0 on failure
579  */
580 int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
581 {
582 	struct mei_bus_message *mei_msg;
583 	struct mei_me_client *me_client;
584 	struct hbm_host_version_response *version_res;
585 	struct hbm_client_connect_response *connect_res;
586 	struct hbm_client_connect_response *disconnect_res;
587 	struct hbm_client_connect_request *disconnect_req;
588 	struct hbm_flow_control *flow_control;
589 	struct hbm_props_response *props_res;
590 	struct hbm_host_enum_response *enum_res;
591 
592 	/* read the message to our buffer */
593 	BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
594 	mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
595 	mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
596 
597 	/* ignore spurious message and prevent reset nesting
598 	 * hbm is put to idle during system reset
599 	 */
600 	if (dev->hbm_state == MEI_HBM_IDLE) {
601 		dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n");
602 		return 0;
603 	}
604 
605 	switch (mei_msg->hbm_cmd) {
606 	case HOST_START_RES_CMD:
607 		dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
608 
609 		dev->init_clients_timer = 0;
610 
611 		version_res = (struct hbm_host_version_response *)mei_msg;
612 
613 		dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
614 				HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
615 				version_res->me_max_version.major_version,
616 				version_res->me_max_version.minor_version);
617 
618 		if (version_res->host_version_supported) {
619 			dev->version.major_version = HBM_MAJOR_VERSION;
620 			dev->version.minor_version = HBM_MINOR_VERSION;
621 		} else {
622 			dev->version.major_version =
623 				version_res->me_max_version.major_version;
624 			dev->version.minor_version =
625 				version_res->me_max_version.minor_version;
626 		}
627 
628 		if (!mei_hbm_version_is_supported(dev)) {
629 			dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
630 
631 			dev->hbm_state = MEI_HBM_STOPPED;
632 			mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
633 						dev->wr_msg.data);
634 			if (mei_write_message(dev, &dev->wr_msg.hdr,
635 					dev->wr_msg.data)) {
636 				dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
637 				return -EIO;
638 			}
639 			break;
640 		}
641 
642 		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
643 		    dev->hbm_state != MEI_HBM_START) {
644 			dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
645 				dev->dev_state, dev->hbm_state);
646 			return -EPROTO;
647 		}
648 
649 		dev->hbm_state = MEI_HBM_STARTED;
650 
651 		if (mei_hbm_enum_clients_req(dev)) {
652 			dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
653 			return -EIO;
654 		}
655 
656 		wake_up_interruptible(&dev->wait_recvd_msg);
657 		break;
658 
659 	case CLIENT_CONNECT_RES_CMD:
660 		dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
661 
662 		connect_res = (struct hbm_client_connect_response *) mei_msg;
663 		mei_hbm_cl_connect_res(dev, connect_res);
664 		wake_up(&dev->wait_recvd_msg);
665 		break;
666 
667 	case CLIENT_DISCONNECT_RES_CMD:
668 		dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
669 
670 		disconnect_res = (struct hbm_client_connect_response *) mei_msg;
671 		mei_hbm_cl_disconnect_res(dev, disconnect_res);
672 		wake_up(&dev->wait_recvd_msg);
673 		break;
674 
675 	case MEI_FLOW_CONTROL_CMD:
676 		dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
677 
678 		flow_control = (struct hbm_flow_control *) mei_msg;
679 		mei_hbm_cl_flow_control_res(dev, flow_control);
680 		break;
681 
682 	case HOST_CLIENT_PROPERTIES_RES_CMD:
683 		dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
684 
685 		dev->init_clients_timer = 0;
686 
687 		if (dev->me_clients == NULL) {
688 			dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n");
689 			return -EPROTO;
690 		}
691 
692 		props_res = (struct hbm_props_response *)mei_msg;
693 		me_client = &dev->me_clients[dev->me_client_presentation_num];
694 
695 		if (props_res->status) {
696 			dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
697 				props_res->status);
698 			return -EPROTO;
699 		}
700 
701 		if (me_client->client_id != props_res->address) {
702 			dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n",
703 				me_client->client_id, props_res->address);
704 			return -EPROTO;
705 		}
706 
707 		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
708 		    dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
709 			dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
710 				dev->dev_state, dev->hbm_state);
711 			return -EPROTO;
712 		}
713 
714 		me_client->props = props_res->client_properties;
715 		dev->me_client_index++;
716 		dev->me_client_presentation_num++;
717 
718 		/* request property for the next client */
719 		if (mei_hbm_prop_req(dev))
720 			return -EIO;
721 
722 		break;
723 
724 	case HOST_ENUM_RES_CMD:
725 		dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
726 
727 		dev->init_clients_timer = 0;
728 
729 		enum_res = (struct hbm_host_enum_response *) mei_msg;
730 		BUILD_BUG_ON(sizeof(dev->me_clients_map)
731 				< sizeof(enum_res->valid_addresses));
732 		memcpy(dev->me_clients_map, enum_res->valid_addresses,
733 			sizeof(enum_res->valid_addresses));
734 
735 		if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
736 		    dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
737 			dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
738 				dev->dev_state, dev->hbm_state);
739 			return -EPROTO;
740 		}
741 
742 		if (mei_hbm_me_cl_allocate(dev)) {
743 			dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n");
744 			return -ENOMEM;
745 		}
746 
747 		dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
748 
749 		/* first property request */
750 		if (mei_hbm_prop_req(dev))
751 			return -EIO;
752 
753 		break;
754 
755 	case HOST_STOP_RES_CMD:
756 		dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
757 
758 		dev->init_clients_timer = 0;
759 
760 		if (dev->hbm_state != MEI_HBM_STOPPED) {
761 			dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
762 				dev->dev_state, dev->hbm_state);
763 			return -EPROTO;
764 		}
765 
766 		dev->dev_state = MEI_DEV_POWER_DOWN;
767 		dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
768 		/* force the reset */
769 		return -EPROTO;
770 		break;
771 
772 	case CLIENT_DISCONNECT_REQ_CMD:
773 		dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
774 
775 		disconnect_req = (struct hbm_client_connect_request *)mei_msg;
776 		mei_hbm_fw_disconnect_req(dev, disconnect_req);
777 		break;
778 
779 	case ME_STOP_REQ_CMD:
780 		dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
781 
782 		dev->hbm_state = MEI_HBM_STOPPED;
783 		mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
784 					dev->wr_ext_msg.data);
785 		break;
786 	default:
787 		BUG();
788 		break;
789 
790 	}
791 	return 0;
792 }
793 
794