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