OSDN Git Service

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