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