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