mei: me_client lookup function to return me_client object
[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/export.h>
18 #include <linux/pci.h>
19 #include <linux/sched.h>
20 #include <linux/wait.h>
21 #include <linux/mei.h>
22 #include <linux/pm_runtime.h>
23
24 #include "mei_dev.h"
25 #include "hbm.h"
26 #include "client.h"
27
28 static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
29 {
30 #define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
31         switch (status) {
32         MEI_CL_CS(SUCCESS);
33         MEI_CL_CS(NOT_FOUND);
34         MEI_CL_CS(ALREADY_STARTED);
35         MEI_CL_CS(OUT_OF_RESOURCES);
36         MEI_CL_CS(MESSAGE_SMALL);
37         default: return "unknown";
38         }
39 #undef MEI_CL_CCS
40 }
41
42 /**
43  * mei_cl_conn_status_to_errno - convert client connect response
44  * status to error code
45  *
46  * @status: client connect response status
47  *
48  * returns corresponding error code
49  */
50 static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
51 {
52         switch (status) {
53         case MEI_CL_CONN_SUCCESS:          return 0;
54         case MEI_CL_CONN_NOT_FOUND:        return -ENOTTY;
55         case MEI_CL_CONN_ALREADY_STARTED:  return -EBUSY;
56         case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
57         case MEI_CL_CONN_MESSAGE_SMALL:    return -EINVAL;
58         default:                           return -EINVAL;
59         }
60 }
61
62 /**
63  * mei_hbm_idle - set hbm to idle state
64  *
65  * @dev: the device structure
66  */
67 void mei_hbm_idle(struct mei_device *dev)
68 {
69         dev->init_clients_timer = 0;
70         dev->hbm_state = MEI_HBM_IDLE;
71 }
72
73 /**
74  * mei_hbm_reset - reset hbm counters and book keeping data structurs
75  *
76  * @dev: the device structure
77  */
78 void mei_hbm_reset(struct mei_device *dev)
79 {
80         dev->me_clients_num = 0;
81         dev->me_client_presentation_num = 0;
82         dev->me_client_index = 0;
83
84         kfree(dev->me_clients);
85         dev->me_clients = NULL;
86
87         mei_hbm_idle(dev);
88 }
89
90 /**
91  * mei_hbm_me_cl_allocate - allocates storage for me clients
92  *
93  * @dev: the device structure
94  *
95  * returns 0 on success -ENOMEM on allocation failure
96  */
97 static int mei_hbm_me_cl_allocate(struct mei_device *dev)
98 {
99         struct mei_me_client *clients;
100         int b;
101
102         mei_hbm_reset(dev);
103
104         /* count how many ME clients we have */
105         for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
106                 dev->me_clients_num++;
107
108         if (dev->me_clients_num == 0)
109                 return 0;
110
111         dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n",
112                 dev->me_clients_num * sizeof(struct mei_me_client));
113         /* allocate storage for ME clients representation */
114         clients = kcalloc(dev->me_clients_num,
115                         sizeof(struct mei_me_client), GFP_KERNEL);
116         if (!clients) {
117                 dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
118                 return -ENOMEM;
119         }
120         dev->me_clients = clients;
121         return 0;
122 }
123
124 /**
125  * mei_hbm_cl_hdr - construct client hbm header
126  *
127  * @cl: client
128  * @hbm_cmd: host bus message command
129  * @buf: buffer for cl header
130  * @len: buffer length
131  */
132 static inline
133 void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
134 {
135         struct mei_hbm_cl_cmd *cmd = buf;
136
137         memset(cmd, 0, len);
138
139         cmd->hbm_cmd = hbm_cmd;
140         cmd->host_addr = cl->host_client_id;
141         cmd->me_addr = cl->me_client_id;
142 }
143
144 /**
145  * mei_hbm_cl_write - write simple hbm client message
146  *
147  * @dev: the device structure
148  * @cl: client
149  * @hbm_cmd: host bus message command
150  * @len: buffer length
151  */
152 static inline
153 int mei_hbm_cl_write(struct mei_device *dev,
154                      struct mei_cl *cl, u8 hbm_cmd, size_t len)
155 {
156         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
157
158         mei_hbm_hdr(mei_hdr, len);
159         mei_hbm_cl_hdr(cl, hbm_cmd, dev->wr_msg.data, len);
160
161         return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
162 }
163
164 /**
165  * mei_hbm_cl_addr_equal - tells if they have the same address
166  *
167  * @cl: - client
168  * @buf: buffer with cl header
169  *
170  * returns true if addresses are the same
171  */
172 static inline
173 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
174 {
175         struct mei_hbm_cl_cmd *cmd = buf;
176         return cl->host_client_id == cmd->host_addr &&
177                 cl->me_client_id == cmd->me_addr;
178 }
179
180
181 int mei_hbm_start_wait(struct mei_device *dev)
182 {
183         int ret;
184         if (dev->hbm_state > MEI_HBM_START)
185                 return 0;
186
187         mutex_unlock(&dev->device_lock);
188         ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
189                         dev->hbm_state == MEI_HBM_IDLE ||
190                         dev->hbm_state >= MEI_HBM_STARTED,
191                         mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
192         mutex_lock(&dev->device_lock);
193
194         if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
195                 dev->hbm_state = MEI_HBM_IDLE;
196                 dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
197                 return -ETIME;
198         }
199         return 0;
200 }
201
202 /**
203  * mei_hbm_start_req - sends start request message.
204  *
205  * @dev: the device structure
206  *
207  * returns 0 on success and < 0 on failure
208  */
209 int mei_hbm_start_req(struct mei_device *dev)
210 {
211         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
212         struct hbm_host_version_request *start_req;
213         const size_t len = sizeof(struct hbm_host_version_request);
214         int ret;
215
216         mei_hbm_hdr(mei_hdr, len);
217
218         /* host start message */
219         start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
220         memset(start_req, 0, len);
221         start_req->hbm_cmd = HOST_START_REQ_CMD;
222         start_req->host_version.major_version = HBM_MAJOR_VERSION;
223         start_req->host_version.minor_version = HBM_MINOR_VERSION;
224
225         dev->hbm_state = MEI_HBM_IDLE;
226         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
227         if (ret) {
228                 dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
229                         ret);
230                 return ret;
231         }
232
233         dev->hbm_state = MEI_HBM_START;
234         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
235         return 0;
236 }
237
238 /*
239  * mei_hbm_enum_clients_req - sends enumeration client request message.
240  *
241  * @dev: the device structure
242  *
243  * returns 0 on success and < 0 on failure
244  */
245 static int mei_hbm_enum_clients_req(struct mei_device *dev)
246 {
247         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
248         struct hbm_host_enum_request *enum_req;
249         const size_t len = sizeof(struct hbm_host_enum_request);
250         int ret;
251
252         /* enumerate clients */
253         mei_hbm_hdr(mei_hdr, len);
254
255         enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
256         memset(enum_req, 0, len);
257         enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
258
259         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
260         if (ret) {
261                 dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
262                         ret);
263                 return ret;
264         }
265         dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
266         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
267         return 0;
268 }
269
270 /**
271  * mei_hbm_prop_req - request property for a single client
272  *
273  * @dev: the device structure
274  *
275  * returns 0 on success and < 0 on failure
276  */
277
278 static int mei_hbm_prop_req(struct mei_device *dev)
279 {
280
281         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
282         struct hbm_props_request *prop_req;
283         const size_t len = sizeof(struct hbm_props_request);
284         unsigned long next_client_index;
285         unsigned long client_num;
286         int ret;
287
288         client_num = dev->me_client_presentation_num;
289
290         next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
291                                           dev->me_client_index);
292
293         /* We got all client properties */
294         if (next_client_index == MEI_CLIENTS_MAX) {
295                 dev->hbm_state = MEI_HBM_STARTED;
296                 schedule_work(&dev->init_work);
297
298                 return 0;
299         }
300
301         dev->me_clients[client_num].client_id = next_client_index;
302         dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
303
304         mei_hbm_hdr(mei_hdr, len);
305         prop_req = (struct hbm_props_request *)dev->wr_msg.data;
306
307         memset(prop_req, 0, sizeof(struct hbm_props_request));
308
309
310         prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
311         prop_req->me_addr = next_client_index;
312
313         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
314         if (ret) {
315                 dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
316                         ret);
317                 return ret;
318         }
319
320         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
321         dev->me_client_index = next_client_index;
322
323         return 0;
324 }
325
326 /*
327  * mei_hbm_pg - sends pg command
328  *
329  * @dev: the device structure
330  * @pg_cmd: the pg command code
331  *
332  * This function returns -EIO on write failure
333  */
334 int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
335 {
336         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
337         struct hbm_power_gate *req;
338         const size_t len = sizeof(struct hbm_power_gate);
339         int ret;
340
341         mei_hbm_hdr(mei_hdr, len);
342
343         req = (struct hbm_power_gate *)dev->wr_msg.data;
344         memset(req, 0, len);
345         req->hbm_cmd = pg_cmd;
346
347         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
348         if (ret)
349                 dev_err(&dev->pdev->dev, "power gate command write failed.\n");
350         return ret;
351 }
352 EXPORT_SYMBOL_GPL(mei_hbm_pg);
353
354 /**
355  * mei_hbm_stop_req - send stop request message
356  *
357  * @dev - mei device
358  * @cl: client info
359  *
360  * This function returns -EIO on write failure
361  */
362 static int mei_hbm_stop_req(struct mei_device *dev)
363 {
364         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
365         struct hbm_host_stop_request *req =
366                         (struct hbm_host_stop_request *)dev->wr_msg.data;
367         const size_t len = sizeof(struct hbm_host_stop_request);
368
369         mei_hbm_hdr(mei_hdr, len);
370
371         memset(req, 0, len);
372         req->hbm_cmd = HOST_STOP_REQ_CMD;
373         req->reason = DRIVER_STOP_REQUEST;
374
375         return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
376 }
377
378 /**
379  * mei_hbm_cl_flow_control_req - sends flow control request.
380  *
381  * @dev: the device structure
382  * @cl: client info
383  *
384  * This function returns -EIO on write failure
385  */
386 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
387 {
388         const size_t len = sizeof(struct hbm_flow_control);
389         cl_dbg(dev, cl, "sending flow control\n");
390         return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, len);
391 }
392
393 /**
394  * mei_hbm_add_single_flow_creds - adds single buffer credentials.
395  *
396  * @dev: the device structure
397  * @flow: flow control.
398  *
399  * return 0 on success, < 0 otherwise
400  */
401 static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
402                                   struct hbm_flow_control *flow)
403 {
404         struct mei_me_client *me_cl;
405
406         me_cl = mei_me_cl_by_id(dev, flow->me_addr);
407         if (!me_cl) {
408                 dev_err(&dev->pdev->dev, "no such me client %d\n",
409                         flow->me_addr);
410                 return -ENOENT;
411         }
412
413         if (WARN_ON(me_cl->props.single_recv_buf == 0))
414                 return -EINVAL;
415
416         me_cl->mei_flow_ctrl_creds++;
417         dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
418             flow->me_addr, me_cl->mei_flow_ctrl_creds);
419
420         return 0;
421 }
422
423 /**
424  * mei_hbm_cl_flow_control_res - flow control response from me
425  *
426  * @dev: the device structure
427  * @flow_control: flow control response bus message
428  */
429 static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
430                 struct hbm_flow_control *flow_control)
431 {
432         struct mei_cl *cl;
433
434         if (!flow_control->host_addr) {
435                 /* single receive buffer */
436                 mei_hbm_add_single_flow_creds(dev, flow_control);
437                 return;
438         }
439
440         /* normal connection */
441         list_for_each_entry(cl, &dev->file_list, link) {
442                 if (mei_hbm_cl_addr_equal(cl, flow_control)) {
443                         cl->mei_flow_ctrl_creds++;
444                         dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
445                                 flow_control->host_addr, flow_control->me_addr);
446                         dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
447                                     cl->mei_flow_ctrl_creds);
448                                 break;
449                 }
450         }
451 }
452
453
454 /**
455  * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
456  *
457  * @dev: the device structure
458  * @cl: a client to disconnect from
459  *
460  * This function returns -EIO on write failure
461  */
462 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
463 {
464         const size_t len = sizeof(struct hbm_client_connect_request);
465         return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, len);
466 }
467
468 /**
469  * mei_hbm_cl_disconnect_rsp - sends disconnect respose to the FW
470  *
471  * @dev: the device structure
472  * @cl: a client to disconnect from
473  *
474  * This function returns -EIO on write failure
475  */
476 int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
477 {
478         const size_t len = sizeof(struct hbm_client_connect_response);
479         return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, len);
480 }
481
482 /**
483  * mei_hbm_cl_disconnect_res - disconnect response from ME
484  *
485  * @dev: the device structure
486  * @rs: disconnect response bus message
487  */
488 static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
489                 struct hbm_client_connect_response *rs)
490 {
491         struct mei_cl *cl;
492         struct mei_cl_cb *cb, *next;
493
494         dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
495                         rs->me_addr, rs->host_addr, rs->status);
496
497         list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
498                 cl = cb->cl;
499
500                 /* this should not happen */
501                 if (WARN_ON(!cl)) {
502                         list_del(&cb->list);
503                         return;
504                 }
505
506                 if (mei_hbm_cl_addr_equal(cl, rs)) {
507                         list_del(&cb->list);
508                         if (rs->status == MEI_CL_DISCONN_SUCCESS)
509                                 cl->state = MEI_FILE_DISCONNECTED;
510
511                         cl->status = 0;
512                         cl->timer_count = 0;
513                         break;
514                 }
515         }
516 }
517
518 /**
519  * mei_hbm_cl_connect_req - send connection request to specific me client
520  *
521  * @dev: the device structure
522  * @cl: a client to connect to
523  *
524  * returns -EIO on write failure
525  */
526 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
527 {
528         const size_t len = sizeof(struct hbm_client_connect_request);
529         return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, len);
530 }
531
532 /**
533  * mei_hbm_cl_connect_res - connect response from the ME
534  *
535  * @dev: the device structure
536  * @rs: connect response bus message
537  */
538 static void mei_hbm_cl_connect_res(struct mei_device *dev,
539                 struct hbm_client_connect_response *rs)
540 {
541
542         struct mei_cl *cl;
543         struct mei_cl_cb *cb, *next;
544
545         dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
546                         rs->me_addr, rs->host_addr,
547                         mei_cl_conn_status_str(rs->status));
548
549         cl = NULL;
550
551         list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
552
553                 cl = cb->cl;
554                 /* this should not happen */
555                 if (WARN_ON(!cl)) {
556                         list_del_init(&cb->list);
557                         continue;
558                 }
559
560                 if (cb->fop_type !=  MEI_FOP_CONNECT)
561                         continue;
562
563                 if (mei_hbm_cl_addr_equal(cl, rs)) {
564                         list_del(&cb->list);
565                         break;
566                 }
567         }
568
569         if (!cl)
570                 return;
571
572         cl->timer_count = 0;
573         if (rs->status == MEI_CL_CONN_SUCCESS)
574                 cl->state = MEI_FILE_CONNECTED;
575         else
576                 cl->state = MEI_FILE_DISCONNECTED;
577         cl->status = mei_cl_conn_status_to_errno(rs->status);
578 }
579
580
581 /**
582  * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
583  *  host sends disconnect response
584  *
585  * @dev: the device structure.
586  * @disconnect_req: disconnect request bus message from the me
587  *
588  * returns -ENOMEM on allocation failure
589  */
590 static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
591                 struct hbm_client_connect_request *disconnect_req)
592 {
593         struct mei_cl *cl;
594         struct mei_cl_cb *cb;
595
596         list_for_each_entry(cl, &dev->file_list, link) {
597                 if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
598                         dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
599                                         disconnect_req->host_addr,
600                                         disconnect_req->me_addr);
601                         cl->state = MEI_FILE_DISCONNECTED;
602                         cl->timer_count = 0;
603
604                         cb = mei_io_cb_init(cl, NULL);
605                         if (!cb)
606                                 return -ENOMEM;
607                         cb->fop_type = MEI_FOP_DISCONNECT_RSP;
608                         cl_dbg(dev, cl, "add disconnect response as first\n");
609                         list_add(&cb->list, &dev->ctrl_wr_list.list);
610
611                         break;
612                 }
613         }
614         return 0;
615 }
616
617
618 /**
619  * mei_hbm_version_is_supported - checks whether the driver can
620  *     support the hbm version of the device
621  *
622  * @dev: the device structure
623  * returns true if driver can support hbm version of the device
624  */
625 bool mei_hbm_version_is_supported(struct mei_device *dev)
626 {
627         return  (dev->version.major_version < HBM_MAJOR_VERSION) ||
628                 (dev->version.major_version == HBM_MAJOR_VERSION &&
629                  dev->version.minor_version <= HBM_MINOR_VERSION);
630 }
631
632 /**
633  * mei_hbm_dispatch - bottom half read routine after ISR to
634  * handle the read bus message cmd processing.
635  *
636  * @dev: the device structure
637  * @mei_hdr: header of bus message
638  *
639  * returns 0 on success and < 0 on failure
640  */
641 int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
642 {
643         struct mei_bus_message *mei_msg;
644         struct mei_me_client *me_client;
645         struct hbm_host_version_response *version_res;
646         struct hbm_client_connect_response *connect_res;
647         struct hbm_client_connect_response *disconnect_res;
648         struct hbm_client_connect_request *disconnect_req;
649         struct hbm_flow_control *flow_control;
650         struct hbm_props_response *props_res;
651         struct hbm_host_enum_response *enum_res;
652
653         /* read the message to our buffer */
654         BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
655         mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
656         mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
657
658         /* ignore spurious message and prevent reset nesting
659          * hbm is put to idle during system reset
660          */
661         if (dev->hbm_state == MEI_HBM_IDLE) {
662                 dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n");
663                 return 0;
664         }
665
666         switch (mei_msg->hbm_cmd) {
667         case HOST_START_RES_CMD:
668                 dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
669
670                 dev->init_clients_timer = 0;
671
672                 version_res = (struct hbm_host_version_response *)mei_msg;
673
674                 dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
675                                 HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
676                                 version_res->me_max_version.major_version,
677                                 version_res->me_max_version.minor_version);
678
679                 if (version_res->host_version_supported) {
680                         dev->version.major_version = HBM_MAJOR_VERSION;
681                         dev->version.minor_version = HBM_MINOR_VERSION;
682                 } else {
683                         dev->version.major_version =
684                                 version_res->me_max_version.major_version;
685                         dev->version.minor_version =
686                                 version_res->me_max_version.minor_version;
687                 }
688
689                 if (!mei_hbm_version_is_supported(dev)) {
690                         dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
691
692                         dev->hbm_state = MEI_HBM_STOPPED;
693                         if (mei_hbm_stop_req(dev)) {
694                                 dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
695                                 return -EIO;
696                         }
697                         break;
698                 }
699
700                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
701                     dev->hbm_state != MEI_HBM_START) {
702                         dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
703                                 dev->dev_state, dev->hbm_state);
704                         return -EPROTO;
705                 }
706
707                 dev->hbm_state = MEI_HBM_STARTED;
708
709                 if (mei_hbm_enum_clients_req(dev)) {
710                         dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
711                         return -EIO;
712                 }
713
714                 wake_up_interruptible(&dev->wait_recvd_msg);
715                 break;
716
717         case CLIENT_CONNECT_RES_CMD:
718                 dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
719
720                 connect_res = (struct hbm_client_connect_response *) mei_msg;
721                 mei_hbm_cl_connect_res(dev, connect_res);
722                 wake_up(&dev->wait_recvd_msg);
723                 break;
724
725         case CLIENT_DISCONNECT_RES_CMD:
726                 dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
727
728                 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
729                 mei_hbm_cl_disconnect_res(dev, disconnect_res);
730                 wake_up(&dev->wait_recvd_msg);
731                 break;
732
733         case MEI_FLOW_CONTROL_CMD:
734                 dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
735
736                 flow_control = (struct hbm_flow_control *) mei_msg;
737                 mei_hbm_cl_flow_control_res(dev, flow_control);
738                 break;
739
740         case MEI_PG_ISOLATION_ENTRY_RES_CMD:
741                 dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n");
742                 dev->pg_event = MEI_PG_EVENT_RECEIVED;
743                 if (waitqueue_active(&dev->wait_pg))
744                         wake_up(&dev->wait_pg);
745                 break;
746
747         case MEI_PG_ISOLATION_EXIT_REQ_CMD:
748                 dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n");
749                 dev->pg_event = MEI_PG_EVENT_RECEIVED;
750                 if (waitqueue_active(&dev->wait_pg))
751                         wake_up(&dev->wait_pg);
752                 else
753                         /*
754                         * If the driver is not waiting on this then
755                         * this is HW initiated exit from PG.
756                         * Start runtime pm resume sequence to exit from PG.
757                         */
758                         pm_request_resume(&dev->pdev->dev);
759                 break;
760
761         case HOST_CLIENT_PROPERTIES_RES_CMD:
762                 dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
763
764                 dev->init_clients_timer = 0;
765
766                 if (dev->me_clients == NULL) {
767                         dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n");
768                         return -EPROTO;
769                 }
770
771                 props_res = (struct hbm_props_response *)mei_msg;
772                 me_client = &dev->me_clients[dev->me_client_presentation_num];
773
774                 if (props_res->status) {
775                         dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
776                                 props_res->status);
777                         return -EPROTO;
778                 }
779
780                 if (me_client->client_id != props_res->me_addr) {
781                         dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n",
782                                 me_client->client_id, props_res->me_addr);
783                         return -EPROTO;
784                 }
785
786                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
787                     dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
788                         dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
789                                 dev->dev_state, dev->hbm_state);
790                         return -EPROTO;
791                 }
792
793                 me_client->props = props_res->client_properties;
794                 dev->me_client_index++;
795                 dev->me_client_presentation_num++;
796
797                 /* request property for the next client */
798                 if (mei_hbm_prop_req(dev))
799                         return -EIO;
800
801                 break;
802
803         case HOST_ENUM_RES_CMD:
804                 dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
805
806                 dev->init_clients_timer = 0;
807
808                 enum_res = (struct hbm_host_enum_response *) mei_msg;
809                 BUILD_BUG_ON(sizeof(dev->me_clients_map)
810                                 < sizeof(enum_res->valid_addresses));
811                 memcpy(dev->me_clients_map, enum_res->valid_addresses,
812                         sizeof(enum_res->valid_addresses));
813
814                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
815                     dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
816                         dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
817                                 dev->dev_state, dev->hbm_state);
818                         return -EPROTO;
819                 }
820
821                 if (mei_hbm_me_cl_allocate(dev)) {
822                         dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n");
823                         return -ENOMEM;
824                 }
825
826                 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
827
828                 /* first property request */
829                 if (mei_hbm_prop_req(dev))
830                         return -EIO;
831
832                 break;
833
834         case HOST_STOP_RES_CMD:
835                 dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
836
837                 dev->init_clients_timer = 0;
838
839                 if (dev->hbm_state != MEI_HBM_STOPPED) {
840                         dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
841                                 dev->dev_state, dev->hbm_state);
842                         return -EPROTO;
843                 }
844
845                 dev->dev_state = MEI_DEV_POWER_DOWN;
846                 dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
847                 /* force the reset */
848                 return -EPROTO;
849                 break;
850
851         case CLIENT_DISCONNECT_REQ_CMD:
852                 dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
853
854                 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
855                 mei_hbm_fw_disconnect_req(dev, disconnect_req);
856                 break;
857
858         case ME_STOP_REQ_CMD:
859                 dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
860                 dev->hbm_state = MEI_HBM_STOPPED;
861                 if (mei_hbm_stop_req(dev)) {
862                         dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
863                         return -EIO;
864                 }
865                 break;
866         default:
867                 BUG();
868                 break;
869
870         }
871         return 0;
872 }
873