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