]> Pileus Git - ~andy/linux/blob - drivers/misc/mei/hbm.c
Merge branch 'stmmac'
[~andy/linux] / drivers / misc / mei / hbm.c
1 /*
2  *
3  * Intel Management Engine Interface (Intel MEI) Linux driver
4  * Copyright (c) 2003-2012, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #include <linux/pci.h>
18 #include <linux/sched.h>
19 #include <linux/wait.h>
20 #include <linux/mei.h>
21
22 #include "mei_dev.h"
23 #include "hbm.h"
24 #include "hw-me.h"
25
26 /**
27  * mei_hbm_me_cl_allocate - allocates storage for me clients
28  *
29  * @dev: the device structure
30  *
31  * returns 0 on success -ENOMEM on allocation failure
32  */
33 static int mei_hbm_me_cl_allocate(struct mei_device *dev)
34 {
35         struct mei_me_client *clients;
36         int b;
37
38         dev->me_clients_num = 0;
39         dev->me_client_presentation_num = 0;
40         dev->me_client_index = 0;
41
42         /* count how many ME clients we have */
43         for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
44                 dev->me_clients_num++;
45
46         if (dev->me_clients_num == 0)
47                 return 0;
48
49         kfree(dev->me_clients);
50         dev->me_clients = NULL;
51
52         dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n",
53                 dev->me_clients_num * sizeof(struct mei_me_client));
54         /* allocate storage for ME clients representation */
55         clients = kcalloc(dev->me_clients_num,
56                         sizeof(struct mei_me_client), GFP_KERNEL);
57         if (!clients) {
58                 dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
59                 return -ENOMEM;
60         }
61         dev->me_clients = clients;
62         return 0;
63 }
64
65 /**
66  * mei_hbm_cl_hdr - construct client hbm header
67  *
68  * @cl: - client
69  * @hbm_cmd: host bus message command
70  * @buf: buffer for cl header
71  * @len: buffer length
72  */
73 static inline
74 void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
75 {
76         struct mei_hbm_cl_cmd *cmd = buf;
77
78         memset(cmd, 0, len);
79
80         cmd->hbm_cmd = hbm_cmd;
81         cmd->host_addr = cl->host_client_id;
82         cmd->me_addr = cl->me_client_id;
83 }
84
85 /**
86  * mei_hbm_cl_addr_equal - tells if they have the same address
87  *
88  * @cl: - client
89  * @buf: buffer with cl header
90  *
91  * returns true if addresses are the same
92  */
93 static inline
94 bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
95 {
96         struct mei_hbm_cl_cmd *cmd = buf;
97         return cl->host_client_id == cmd->host_addr &&
98                 cl->me_client_id == cmd->me_addr;
99 }
100
101
102 /**
103  * is_treat_specially_client - checks if the message belongs
104  * to the file private data.
105  *
106  * @cl: private data of the file object
107  * @rs: connect response bus message
108  *
109  */
110 static bool is_treat_specially_client(struct mei_cl *cl,
111                 struct hbm_client_connect_response *rs)
112 {
113         if (mei_hbm_cl_addr_equal(cl, rs)) {
114                 if (!rs->status) {
115                         cl->state = MEI_FILE_CONNECTED;
116                         cl->status = 0;
117
118                 } else {
119                         cl->state = MEI_FILE_DISCONNECTED;
120                         cl->status = -ENODEV;
121                 }
122                 cl->timer_count = 0;
123
124                 return true;
125         }
126         return false;
127 }
128
129 /**
130  * mei_hbm_idle - set hbm to idle state
131  *
132  * @dev: the device structure
133  */
134 void mei_hbm_idle(struct mei_device *dev)
135 {
136         dev->init_clients_timer = 0;
137         dev->hbm_state = MEI_HBM_IDLE;
138 }
139
140 int mei_hbm_start_wait(struct mei_device *dev)
141 {
142         int ret;
143         if (dev->hbm_state > MEI_HBM_START)
144                 return 0;
145
146         mutex_unlock(&dev->device_lock);
147         ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
148                         dev->hbm_state == MEI_HBM_IDLE ||
149                         dev->hbm_state >= MEI_HBM_STARTED,
150                         mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
151         mutex_lock(&dev->device_lock);
152
153         if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
154                 dev->hbm_state = MEI_HBM_IDLE;
155                 dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
156                 return -ETIMEDOUT;
157         }
158         return 0;
159 }
160
161 /**
162  * mei_hbm_start_req - sends start request message.
163  *
164  * @dev: the device structure
165  *
166  * returns 0 on success and < 0 on failure
167  */
168 int mei_hbm_start_req(struct mei_device *dev)
169 {
170         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
171         struct hbm_host_version_request *start_req;
172         const size_t len = sizeof(struct hbm_host_version_request);
173         int ret;
174
175         mei_hbm_hdr(mei_hdr, len);
176
177         /* host start message */
178         start_req = (struct hbm_host_version_request *)dev->wr_msg.data;
179         memset(start_req, 0, len);
180         start_req->hbm_cmd = HOST_START_REQ_CMD;
181         start_req->host_version.major_version = HBM_MAJOR_VERSION;
182         start_req->host_version.minor_version = HBM_MINOR_VERSION;
183
184         dev->hbm_state = MEI_HBM_IDLE;
185         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
186         if (ret) {
187                 dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
188                         ret);
189                 return ret;
190         }
191
192         dev->hbm_state = MEI_HBM_START;
193         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
194         return 0;
195 }
196
197 /*
198  * mei_hbm_enum_clients_req - sends enumeration client request message.
199  *
200  * @dev: the device structure
201  *
202  * returns 0 on success and < 0 on failure
203  */
204 static int mei_hbm_enum_clients_req(struct mei_device *dev)
205 {
206         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
207         struct hbm_host_enum_request *enum_req;
208         const size_t len = sizeof(struct hbm_host_enum_request);
209         int ret;
210
211         /* enumerate clients */
212         mei_hbm_hdr(mei_hdr, len);
213
214         enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data;
215         memset(enum_req, 0, len);
216         enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
217
218         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
219         if (ret) {
220                 dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
221                         ret);
222                 return ret;
223         }
224         dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
225         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
226         return 0;
227 }
228
229 /**
230  * mei_hbm_prop_req - request property for a single client
231  *
232  * @dev: the device structure
233  *
234  * returns 0 on success and < 0 on failure
235  */
236
237 static int mei_hbm_prop_req(struct mei_device *dev)
238 {
239
240         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
241         struct hbm_props_request *prop_req;
242         const size_t len = sizeof(struct hbm_props_request);
243         unsigned long next_client_index;
244         unsigned long client_num;
245         int ret;
246
247         client_num = dev->me_client_presentation_num;
248
249         next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX,
250                                           dev->me_client_index);
251
252         /* We got all client properties */
253         if (next_client_index == MEI_CLIENTS_MAX) {
254                 dev->hbm_state = MEI_HBM_STARTED;
255                 schedule_work(&dev->init_work);
256
257                 return 0;
258         }
259
260         dev->me_clients[client_num].client_id = next_client_index;
261         dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
262
263         mei_hbm_hdr(mei_hdr, len);
264         prop_req = (struct hbm_props_request *)dev->wr_msg.data;
265
266         memset(prop_req, 0, sizeof(struct hbm_props_request));
267
268
269         prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
270         prop_req->address = next_client_index;
271
272         ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
273         if (ret) {
274                 dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
275                         ret);
276                 return ret;
277         }
278
279         dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
280         dev->me_client_index = next_client_index;
281
282         return 0;
283 }
284
285 /**
286  * mei_hbm_stop_req_prepare - prepare stop request message
287  *
288  * @dev - mei device
289  * @mei_hdr - mei message header
290  * @data - hbm message body buffer
291  */
292 static void mei_hbm_stop_req_prepare(struct mei_device *dev,
293                 struct mei_msg_hdr *mei_hdr, unsigned char *data)
294 {
295         struct hbm_host_stop_request *req =
296                         (struct hbm_host_stop_request *)data;
297         const size_t len = sizeof(struct hbm_host_stop_request);
298
299         mei_hbm_hdr(mei_hdr, len);
300
301         memset(req, 0, len);
302         req->hbm_cmd = HOST_STOP_REQ_CMD;
303         req->reason = DRIVER_STOP_REQUEST;
304 }
305
306 /**
307  * mei_hbm_cl_flow_control_req - sends flow control request.
308  *
309  * @dev: the device structure
310  * @cl: client info
311  *
312  * This function returns -EIO on write failure
313  */
314 int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
315 {
316         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
317         const size_t len = sizeof(struct hbm_flow_control);
318
319         mei_hbm_hdr(mei_hdr, len);
320         mei_hbm_cl_hdr(cl, MEI_FLOW_CONTROL_CMD, dev->wr_msg.data, len);
321
322         dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
323                 cl->host_client_id, cl->me_client_id);
324
325         return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
326 }
327
328 /**
329  * mei_hbm_add_single_flow_creds - adds single buffer credentials.
330  *
331  * @dev: the device structure
332  * @flow: flow control.
333  */
334 static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
335                                   struct hbm_flow_control *flow)
336 {
337         struct mei_me_client *client;
338         int i;
339
340         for (i = 0; i < dev->me_clients_num; i++) {
341                 client = &dev->me_clients[i];
342                 if (client && flow->me_addr == client->client_id) {
343                         if (client->props.single_recv_buf) {
344                                 client->mei_flow_ctrl_creds++;
345                                 dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
346                                     flow->me_addr);
347                                 dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
348                                     client->mei_flow_ctrl_creds);
349                         } else {
350                                 BUG();  /* error in flow control */
351                         }
352                 }
353         }
354 }
355
356 /**
357  * mei_hbm_cl_flow_control_res - flow control response from me
358  *
359  * @dev: the device structure
360  * @flow_control: flow control response bus message
361  */
362 static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
363                 struct hbm_flow_control *flow_control)
364 {
365         struct mei_cl *cl = NULL;
366         struct mei_cl *next = NULL;
367
368         if (!flow_control->host_addr) {
369                 /* single receive buffer */
370                 mei_hbm_add_single_flow_creds(dev, flow_control);
371                 return;
372         }
373
374         /* normal connection */
375         list_for_each_entry_safe(cl, next, &dev->file_list, link) {
376                 if (mei_hbm_cl_addr_equal(cl, flow_control)) {
377                         cl->mei_flow_ctrl_creds++;
378                         dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
379                                 flow_control->host_addr, flow_control->me_addr);
380                         dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
381                                     cl->mei_flow_ctrl_creds);
382                                 break;
383                 }
384         }
385 }
386
387
388 /**
389  * mei_hbm_cl_disconnect_req - sends disconnect message to fw.
390  *
391  * @dev: the device structure
392  * @cl: a client to disconnect from
393  *
394  * This function returns -EIO on write failure
395  */
396 int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
397 {
398         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
399         const size_t len = sizeof(struct hbm_client_connect_request);
400
401         mei_hbm_hdr(mei_hdr, len);
402         mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, dev->wr_msg.data, len);
403
404         return mei_write_message(dev, mei_hdr, dev->wr_msg.data);
405 }
406
407 /**
408  * mei_hbm_cl_disconnect_res - disconnect response from ME
409  *
410  * @dev: the device structure
411  * @rs: disconnect response bus message
412  */
413 static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
414                 struct hbm_client_connect_response *rs)
415 {
416         struct mei_cl *cl;
417         struct mei_cl_cb *pos = NULL, *next = NULL;
418
419         dev_dbg(&dev->pdev->dev,
420                         "disconnect_response:\n"
421                         "ME Client = %d\n"
422                         "Host Client = %d\n"
423                         "Status = %d\n",
424                         rs->me_addr,
425                         rs->host_addr,
426                         rs->status);
427
428         list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
429                 cl = pos->cl;
430
431                 if (!cl) {
432                         list_del(&pos->list);
433                         return;
434                 }
435
436                 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
437                 if (mei_hbm_cl_addr_equal(cl, rs)) {
438                         list_del(&pos->list);
439                         if (!rs->status)
440                                 cl->state = MEI_FILE_DISCONNECTED;
441
442                         cl->status = 0;
443                         cl->timer_count = 0;
444                         break;
445                 }
446         }
447 }
448
449 /**
450  * mei_hbm_cl_connect_req - send connection request to specific me client
451  *
452  * @dev: the device structure
453  * @cl: a client to connect to
454  *
455  * returns -EIO on write failure
456  */
457 int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
458 {
459         struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
460         const size_t len = sizeof(struct hbm_client_connect_request);
461
462         mei_hbm_hdr(mei_hdr, len);
463         mei_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, dev->wr_msg.data, len);
464
465         return mei_write_message(dev, mei_hdr,  dev->wr_msg.data);
466 }
467
468 /**
469  * mei_hbm_cl_connect_res - connect response from the ME
470  *
471  * @dev: the device structure
472  * @rs: connect response bus message
473  */
474 static void mei_hbm_cl_connect_res(struct mei_device *dev,
475                 struct hbm_client_connect_response *rs)
476 {
477
478         struct mei_cl *cl;
479         struct mei_cl_cb *pos = NULL, *next = NULL;
480
481         dev_dbg(&dev->pdev->dev,
482                         "connect_response:\n"
483                         "ME Client = %d\n"
484                         "Host Client = %d\n"
485                         "Status = %d\n",
486                         rs->me_addr,
487                         rs->host_addr,
488                         rs->status);
489
490         /* if WD or iamthif client treat specially */
491
492         if (is_treat_specially_client(&dev->wd_cl, rs)) {
493                 dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
494                 mei_watchdog_register(dev);
495
496                 return;
497         }
498
499         if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
500                 dev->iamthif_state = MEI_IAMTHIF_IDLE;
501                 return;
502         }
503         list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
504
505                 cl = pos->cl;
506                 if (!cl) {
507                         list_del(&pos->list);
508                         return;
509                 }
510                 if (pos->fop_type == MEI_FOP_IOCTL) {
511                         if (is_treat_specially_client(cl, rs)) {
512                                 list_del(&pos->list);
513                                 cl->status = 0;
514                                 cl->timer_count = 0;
515                                 break;
516                         }
517                 }
518         }
519 }
520
521
522 /**
523  * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware
524  *  host sends disconnect response
525  *
526  * @dev: the device structure.
527  * @disconnect_req: disconnect request bus message from the me
528  */
529 static void mei_hbm_fw_disconnect_req(struct mei_device *dev,
530                 struct hbm_client_connect_request *disconnect_req)
531 {
532         struct mei_cl *cl, *next;
533         const size_t len = sizeof(struct hbm_client_connect_response);
534
535         list_for_each_entry_safe(cl, next, &dev->file_list, link) {
536                 if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
537                         dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
538                                         disconnect_req->host_addr,
539                                         disconnect_req->me_addr);
540                         cl->state = MEI_FILE_DISCONNECTED;
541                         cl->timer_count = 0;
542                         if (cl == &dev->wd_cl)
543                                 dev->wd_pending = false;
544                         else if (cl == &dev->iamthif_cl)
545                                 dev->iamthif_timer = 0;
546
547                         /* prepare disconnect response */
548                         mei_hbm_hdr(&dev->wr_ext_msg.hdr, len);
549                         mei_hbm_cl_hdr(cl, CLIENT_DISCONNECT_RES_CMD,
550                                          dev->wr_ext_msg.data, len);
551                         break;
552                 }
553         }
554 }
555
556
557 /**
558  * mei_hbm_version_is_supported - checks whether the driver can
559  *     support the hbm version of the device
560  *
561  * @dev: the device structure
562  * returns true if driver can support hbm version of the device
563  */
564 bool mei_hbm_version_is_supported(struct mei_device *dev)
565 {
566         return  (dev->version.major_version < HBM_MAJOR_VERSION) ||
567                 (dev->version.major_version == HBM_MAJOR_VERSION &&
568                  dev->version.minor_version <= HBM_MINOR_VERSION);
569 }
570
571 /**
572  * mei_hbm_dispatch - bottom half read routine after ISR to
573  * handle the read bus message cmd processing.
574  *
575  * @dev: the device structure
576  * @mei_hdr: header of bus message
577  *
578  * returns 0 on success and < 0 on failure
579  */
580 int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
581 {
582         struct mei_bus_message *mei_msg;
583         struct mei_me_client *me_client;
584         struct hbm_host_version_response *version_res;
585         struct hbm_client_connect_response *connect_res;
586         struct hbm_client_connect_response *disconnect_res;
587         struct hbm_client_connect_request *disconnect_req;
588         struct hbm_flow_control *flow_control;
589         struct hbm_props_response *props_res;
590         struct hbm_host_enum_response *enum_res;
591
592         /* read the message to our buffer */
593         BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
594         mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
595         mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
596
597         /* ignore spurious message and prevent reset nesting
598          * hbm is put to idle during system reset
599          */
600         if (dev->hbm_state == MEI_HBM_IDLE) {
601                 dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n");
602                 return 0;
603         }
604
605         switch (mei_msg->hbm_cmd) {
606         case HOST_START_RES_CMD:
607                 dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
608
609                 dev->init_clients_timer = 0;
610
611                 version_res = (struct hbm_host_version_response *)mei_msg;
612
613                 dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
614                                 HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
615                                 version_res->me_max_version.major_version,
616                                 version_res->me_max_version.minor_version);
617
618                 if (version_res->host_version_supported) {
619                         dev->version.major_version = HBM_MAJOR_VERSION;
620                         dev->version.minor_version = HBM_MINOR_VERSION;
621                 } else {
622                         dev->version.major_version =
623                                 version_res->me_max_version.major_version;
624                         dev->version.minor_version =
625                                 version_res->me_max_version.minor_version;
626                 }
627
628                 if (!mei_hbm_version_is_supported(dev)) {
629                         dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
630
631                         dev->hbm_state = MEI_HBM_STOPPED;
632                         mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
633                                                 dev->wr_msg.data);
634                         if (mei_write_message(dev, &dev->wr_msg.hdr,
635                                         dev->wr_msg.data)) {
636                                 dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
637                                 return -EIO;
638                         }
639                         break;
640                 }
641
642                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
643                     dev->hbm_state != MEI_HBM_START) {
644                         dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
645                                 dev->dev_state, dev->hbm_state);
646                         return -EPROTO;
647                 }
648
649                 dev->hbm_state = MEI_HBM_STARTED;
650
651                 if (mei_hbm_enum_clients_req(dev)) {
652                         dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
653                         return -EIO;
654                 }
655
656                 wake_up_interruptible(&dev->wait_recvd_msg);
657                 break;
658
659         case CLIENT_CONNECT_RES_CMD:
660                 dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
661
662                 connect_res = (struct hbm_client_connect_response *) mei_msg;
663                 mei_hbm_cl_connect_res(dev, connect_res);
664                 wake_up(&dev->wait_recvd_msg);
665                 break;
666
667         case CLIENT_DISCONNECT_RES_CMD:
668                 dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
669
670                 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
671                 mei_hbm_cl_disconnect_res(dev, disconnect_res);
672                 wake_up(&dev->wait_recvd_msg);
673                 break;
674
675         case MEI_FLOW_CONTROL_CMD:
676                 dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
677
678                 flow_control = (struct hbm_flow_control *) mei_msg;
679                 mei_hbm_cl_flow_control_res(dev, flow_control);
680                 break;
681
682         case HOST_CLIENT_PROPERTIES_RES_CMD:
683                 dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
684
685                 dev->init_clients_timer = 0;
686
687                 if (dev->me_clients == NULL) {
688                         dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n");
689                         return -EPROTO;
690                 }
691
692                 props_res = (struct hbm_props_response *)mei_msg;
693                 me_client = &dev->me_clients[dev->me_client_presentation_num];
694
695                 if (props_res->status) {
696                         dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
697                                 props_res->status);
698                         return -EPROTO;
699                 }
700
701                 if (me_client->client_id != props_res->address) {
702                         dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n",
703                                 me_client->client_id, props_res->address);
704                         return -EPROTO;
705                 }
706
707                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
708                     dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
709                         dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
710                                 dev->dev_state, dev->hbm_state);
711                         return -EPROTO;
712                 }
713
714                 me_client->props = props_res->client_properties;
715                 dev->me_client_index++;
716                 dev->me_client_presentation_num++;
717
718                 /* request property for the next client */
719                 if (mei_hbm_prop_req(dev))
720                         return -EIO;
721
722                 break;
723
724         case HOST_ENUM_RES_CMD:
725                 dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
726
727                 dev->init_clients_timer = 0;
728
729                 enum_res = (struct hbm_host_enum_response *) mei_msg;
730                 BUILD_BUG_ON(sizeof(dev->me_clients_map)
731                                 < sizeof(enum_res->valid_addresses));
732                 memcpy(dev->me_clients_map, enum_res->valid_addresses,
733                         sizeof(enum_res->valid_addresses));
734
735                 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
736                     dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
737                         dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
738                                 dev->dev_state, dev->hbm_state);
739                         return -EPROTO;
740                 }
741
742                 if (mei_hbm_me_cl_allocate(dev)) {
743                         dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n");
744                         return -ENOMEM;
745                 }
746
747                 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
748
749                 /* first property request */
750                 if (mei_hbm_prop_req(dev))
751                         return -EIO;
752
753                 break;
754
755         case HOST_STOP_RES_CMD:
756                 dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
757
758                 dev->init_clients_timer = 0;
759
760                 if (dev->hbm_state != MEI_HBM_STOPPED) {
761                         dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
762                                 dev->dev_state, dev->hbm_state);
763                         return -EPROTO;
764                 }
765
766                 dev->dev_state = MEI_DEV_POWER_DOWN;
767                 dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
768                 /* force the reset */
769                 return -EPROTO;
770                 break;
771
772         case CLIENT_DISCONNECT_REQ_CMD:
773                 dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
774
775                 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
776                 mei_hbm_fw_disconnect_req(dev, disconnect_req);
777                 break;
778
779         case ME_STOP_REQ_CMD:
780                 dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
781
782                 dev->hbm_state = MEI_HBM_STOPPED;
783                 mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
784                                         dev->wr_ext_msg.data);
785                 break;
786         default:
787                 BUG();
788                 break;
789
790         }
791         return 0;
792 }
793