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