tty: serial: samsung: drop uart_port->lock before calling tty_flip_buffer_push()
[firefly-linux-kernel-4.4.55.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  *
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, "wating 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_dispatch - bottom half read routine after ISR to
540  * handle the read bus message cmd processing.
541  *
542  * @dev: the device structure
543  * @mei_hdr: header of bus message
544  */
545 void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
546 {
547         struct mei_bus_message *mei_msg;
548         struct mei_me_client *me_client;
549         struct hbm_host_version_response *version_res;
550         struct hbm_client_connect_response *connect_res;
551         struct hbm_client_connect_response *disconnect_res;
552         struct hbm_client_connect_request *disconnect_req;
553         struct hbm_flow_control *flow_control;
554         struct hbm_props_response *props_res;
555         struct hbm_host_enum_response *enum_res;
556
557         /* read the message to our buffer */
558         BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
559         mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
560         mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
561
562         switch (mei_msg->hbm_cmd) {
563         case HOST_START_RES_CMD:
564                 version_res = (struct hbm_host_version_response *)mei_msg;
565                 if (!version_res->host_version_supported) {
566                         dev->version = version_res->me_max_version;
567                         dev_dbg(&dev->pdev->dev, "version mismatch.\n");
568
569                         dev->hbm_state = MEI_HBM_STOP;
570                         mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
571                                                 dev->wr_msg.data);
572                         mei_write_message(dev, &dev->wr_msg.hdr,
573                                         dev->wr_msg.data);
574
575                         return;
576                 }
577
578                 dev->version.major_version = HBM_MAJOR_VERSION;
579                 dev->version.minor_version = HBM_MINOR_VERSION;
580                 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
581                     dev->hbm_state == MEI_HBM_START) {
582                         dev->init_clients_timer = 0;
583                         mei_hbm_enum_clients_req(dev);
584                 } else {
585                         dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
586                         mei_reset(dev, 1);
587                         return;
588                 }
589
590                 wake_up_interruptible(&dev->wait_recvd_msg);
591                 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
592                 break;
593
594         case CLIENT_CONNECT_RES_CMD:
595                 connect_res = (struct hbm_client_connect_response *) mei_msg;
596                 mei_hbm_cl_connect_res(dev, connect_res);
597                 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
598                 wake_up(&dev->wait_recvd_msg);
599                 break;
600
601         case CLIENT_DISCONNECT_RES_CMD:
602                 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
603                 mei_hbm_cl_disconnect_res(dev, disconnect_res);
604                 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
605                 wake_up(&dev->wait_recvd_msg);
606                 break;
607
608         case MEI_FLOW_CONTROL_CMD:
609                 flow_control = (struct hbm_flow_control *) mei_msg;
610                 mei_hbm_cl_flow_control_res(dev, flow_control);
611                 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
612                 break;
613
614         case HOST_CLIENT_PROPERTIES_RES_CMD:
615                 props_res = (struct hbm_props_response *)mei_msg;
616                 me_client = &dev->me_clients[dev->me_client_presentation_num];
617
618                 if (props_res->status || !dev->me_clients) {
619                         dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n");
620                         mei_reset(dev, 1);
621                         return;
622                 }
623
624                 if (me_client->client_id != props_res->address) {
625                         dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n");
626                         mei_reset(dev, 1);
627                         return;
628                 }
629
630                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
631                     dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
632                         dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
633                         mei_reset(dev, 1);
634
635                         return;
636                 }
637
638                 me_client->props = props_res->client_properties;
639                 dev->me_client_index++;
640                 dev->me_client_presentation_num++;
641
642                 /* request property for the next client */
643                 mei_hbm_prop_req(dev);
644
645                 break;
646
647         case HOST_ENUM_RES_CMD:
648                 enum_res = (struct hbm_host_enum_response *) mei_msg;
649                 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
650                 if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
651                     dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
652                                 dev->init_clients_timer = 0;
653                                 dev->me_client_presentation_num = 0;
654                                 dev->me_client_index = 0;
655                                 mei_hbm_me_cl_allocate(dev);
656                                 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
657
658                                 /* first property reqeust */
659                                 mei_hbm_prop_req(dev);
660                 } else {
661                         dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
662                         mei_reset(dev, 1);
663                         return;
664                 }
665                 break;
666
667         case HOST_STOP_RES_CMD:
668
669                 if (dev->hbm_state != MEI_HBM_STOP)
670                         dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
671                 dev->dev_state = MEI_DEV_DISABLED;
672                 dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
673                 mei_reset(dev, 1);
674                 break;
675
676         case CLIENT_DISCONNECT_REQ_CMD:
677                 /* search for client */
678                 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
679                 mei_hbm_fw_disconnect_req(dev, disconnect_req);
680                 break;
681
682         case ME_STOP_REQ_CMD:
683
684                 dev->hbm_state = MEI_HBM_STOP;
685                 mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
686                                         dev->wr_ext_msg.data);
687                 break;
688         default:
689                 BUG();
690                 break;
691
692         }
693 }
694