1
2
3
4
5
6#include <linux/export.h>
7#include <linux/sched.h>
8#include <linux/wait.h>
9#include <linux/pm_runtime.h>
10#include <linux/slab.h>
11
12#include <linux/mei.h>
13
14#include "mei_dev.h"
15#include "hbm.h"
16#include "client.h"
17
18static const char *mei_hbm_status_str(enum mei_hbm_status status)
19{
20#define MEI_HBM_STATUS(status) case MEI_HBMS_##status: return #status
21 switch (status) {
22 MEI_HBM_STATUS(SUCCESS);
23 MEI_HBM_STATUS(CLIENT_NOT_FOUND);
24 MEI_HBM_STATUS(ALREADY_EXISTS);
25 MEI_HBM_STATUS(REJECTED);
26 MEI_HBM_STATUS(INVALID_PARAMETER);
27 MEI_HBM_STATUS(NOT_ALLOWED);
28 MEI_HBM_STATUS(ALREADY_STARTED);
29 MEI_HBM_STATUS(NOT_STARTED);
30 default: return "unknown";
31 }
32#undef MEI_HBM_STATUS
33};
34
35static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
36{
37#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
38 switch (status) {
39 MEI_CL_CS(SUCCESS);
40 MEI_CL_CS(NOT_FOUND);
41 MEI_CL_CS(ALREADY_STARTED);
42 MEI_CL_CS(OUT_OF_RESOURCES);
43 MEI_CL_CS(MESSAGE_SMALL);
44 MEI_CL_CS(NOT_ALLOWED);
45 default: return "unknown";
46 }
47#undef MEI_CL_CCS
48}
49
50const char *mei_hbm_state_str(enum mei_hbm_state state)
51{
52#define MEI_HBM_STATE(state) case MEI_HBM_##state: return #state
53 switch (state) {
54 MEI_HBM_STATE(IDLE);
55 MEI_HBM_STATE(STARTING);
56 MEI_HBM_STATE(STARTED);
57 MEI_HBM_STATE(DR_SETUP);
58 MEI_HBM_STATE(ENUM_CLIENTS);
59 MEI_HBM_STATE(CLIENT_PROPERTIES);
60 MEI_HBM_STATE(STOPPED);
61 default:
62 return "unknown";
63 }
64#undef MEI_HBM_STATE
65}
66
67
68
69
70
71
72
73
74
75static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
76{
77 switch (status) {
78 case MEI_CL_CONN_SUCCESS: return 0;
79 case MEI_CL_CONN_NOT_FOUND: return -ENOTTY;
80 case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY;
81 case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
82 case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL;
83 case MEI_CL_CONN_NOT_ALLOWED: return -EBUSY;
84 default: return -EINVAL;
85 }
86}
87
88
89
90
91
92
93
94
95static inline int mei_hbm_write_message(struct mei_device *dev,
96 struct mei_msg_hdr *hdr,
97 const void *data)
98{
99 return mei_write_message(dev, hdr, sizeof(*hdr), data, hdr->length);
100}
101
102
103
104
105
106
107void mei_hbm_idle(struct mei_device *dev)
108{
109 dev->init_clients_timer = 0;
110 dev->hbm_state = MEI_HBM_IDLE;
111}
112
113
114
115
116
117
118void mei_hbm_reset(struct mei_device *dev)
119{
120 mei_me_cl_rm_all(dev);
121
122 mei_hbm_idle(dev);
123}
124
125
126
127
128
129
130
131
132static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
133{
134 hdr->host_addr = 0;
135 hdr->me_addr = 0;
136 hdr->length = length;
137 hdr->msg_complete = 1;
138 hdr->dma_ring = 0;
139 hdr->reserved = 0;
140 hdr->internal = 0;
141}
142
143
144
145
146
147
148
149
150
151static inline
152void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
153{
154 struct mei_hbm_cl_cmd *cmd = buf;
155
156 memset(cmd, 0, len);
157
158 cmd->hbm_cmd = hbm_cmd;
159 cmd->host_addr = mei_cl_host_addr(cl);
160 cmd->me_addr = mei_cl_me_id(cl);
161}
162
163
164
165
166
167
168
169
170
171
172
173
174static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
175 u8 hbm_cmd, void *buf, size_t len)
176{
177 struct mei_msg_hdr mei_hdr;
178
179 mei_hbm_hdr(&mei_hdr, len);
180 mei_hbm_cl_hdr(cl, hbm_cmd, buf, len);
181
182 return mei_hbm_write_message(dev, &mei_hdr, buf);
183}
184
185
186
187
188
189
190
191
192
193
194static inline
195bool mei_hbm_cl_addr_equal(struct mei_cl *cl, struct mei_hbm_cl_cmd *cmd)
196{
197 return mei_cl_host_addr(cl) == cmd->host_addr &&
198 mei_cl_me_id(cl) == cmd->me_addr;
199}
200
201
202
203
204
205
206
207
208
209static inline
210struct mei_cl *mei_hbm_cl_find_by_cmd(struct mei_device *dev, void *buf)
211{
212 struct mei_hbm_cl_cmd *cmd = (struct mei_hbm_cl_cmd *)buf;
213 struct mei_cl *cl;
214
215 list_for_each_entry(cl, &dev->file_list, link)
216 if (mei_hbm_cl_addr_equal(cl, cmd))
217 return cl;
218 return NULL;
219}
220
221
222
223
224
225
226
227
228
229int mei_hbm_start_wait(struct mei_device *dev)
230{
231 int ret;
232
233 if (dev->hbm_state > MEI_HBM_STARTING)
234 return 0;
235
236 mutex_unlock(&dev->device_lock);
237 ret = wait_event_timeout(dev->wait_hbm_start,
238 dev->hbm_state != MEI_HBM_STARTING,
239 mei_secs_to_jiffies(MEI_HBM_TIMEOUT));
240 mutex_lock(&dev->device_lock);
241
242 if (ret == 0 && (dev->hbm_state <= MEI_HBM_STARTING)) {
243 dev->hbm_state = MEI_HBM_IDLE;
244 dev_err(dev->dev, "waiting for mei start failed\n");
245 return -ETIME;
246 }
247 return 0;
248}
249
250
251
252
253
254
255
256
257int mei_hbm_start_req(struct mei_device *dev)
258{
259 struct mei_msg_hdr mei_hdr;
260 struct hbm_host_version_request start_req;
261 const size_t len = sizeof(struct hbm_host_version_request);
262 int ret;
263
264 mei_hbm_reset(dev);
265
266 mei_hbm_hdr(&mei_hdr, len);
267
268
269 memset(&start_req, 0, len);
270 start_req.hbm_cmd = HOST_START_REQ_CMD;
271 start_req.host_version.major_version = HBM_MAJOR_VERSION;
272 start_req.host_version.minor_version = HBM_MINOR_VERSION;
273
274 dev->hbm_state = MEI_HBM_IDLE;
275 ret = mei_hbm_write_message(dev, &mei_hdr, &start_req);
276 if (ret) {
277 dev_err(dev->dev, "version message write failed: ret = %d\n",
278 ret);
279 return ret;
280 }
281
282 dev->hbm_state = MEI_HBM_STARTING;
283 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
284 mei_schedule_stall_timer(dev);
285 return 0;
286}
287
288
289
290
291
292
293
294static int mei_hbm_dma_setup_req(struct mei_device *dev)
295{
296 struct mei_msg_hdr mei_hdr;
297 struct hbm_dma_setup_request req;
298 const size_t len = sizeof(struct hbm_dma_setup_request);
299 unsigned int i;
300 int ret;
301
302 mei_hbm_hdr(&mei_hdr, len);
303
304 memset(&req, 0, len);
305 req.hbm_cmd = MEI_HBM_DMA_SETUP_REQ_CMD;
306 for (i = 0; i < DMA_DSCR_NUM; i++) {
307 phys_addr_t paddr;
308
309 paddr = dev->dr_dscr[i].daddr;
310 req.dma_dscr[i].addr_hi = upper_32_bits(paddr);
311 req.dma_dscr[i].addr_lo = lower_32_bits(paddr);
312 req.dma_dscr[i].size = dev->dr_dscr[i].size;
313 }
314
315 mei_dma_ring_reset(dev);
316
317 ret = mei_hbm_write_message(dev, &mei_hdr, &req);
318 if (ret) {
319 dev_err(dev->dev, "dma setup request write failed: ret = %d.\n",
320 ret);
321 return ret;
322 }
323
324 dev->hbm_state = MEI_HBM_DR_SETUP;
325 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
326 mei_schedule_stall_timer(dev);
327 return 0;
328}
329
330
331
332
333
334
335
336
337static int mei_hbm_enum_clients_req(struct mei_device *dev)
338{
339 struct mei_msg_hdr mei_hdr;
340 struct hbm_host_enum_request enum_req;
341 const size_t len = sizeof(struct hbm_host_enum_request);
342 int ret;
343
344
345 mei_hbm_hdr(&mei_hdr, len);
346
347 memset(&enum_req, 0, len);
348 enum_req.hbm_cmd = HOST_ENUM_REQ_CMD;
349 enum_req.flags |= dev->hbm_f_dc_supported ?
350 MEI_HBM_ENUM_F_ALLOW_ADD : 0;
351 enum_req.flags |= dev->hbm_f_ie_supported ?
352 MEI_HBM_ENUM_F_IMMEDIATE_ENUM : 0;
353
354 ret = mei_hbm_write_message(dev, &mei_hdr, &enum_req);
355 if (ret) {
356 dev_err(dev->dev, "enumeration request write failed: ret = %d.\n",
357 ret);
358 return ret;
359 }
360 dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
361 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
362 mei_schedule_stall_timer(dev);
363 return 0;
364}
365
366
367
368
369
370
371
372
373
374
375static int mei_hbm_me_cl_add(struct mei_device *dev,
376 struct hbm_props_response *res)
377{
378 struct mei_me_client *me_cl;
379 const uuid_le *uuid = &res->client_properties.protocol_name;
380
381 mei_me_cl_rm_by_uuid(dev, uuid);
382
383 me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
384 if (!me_cl)
385 return -ENOMEM;
386
387 mei_me_cl_init(me_cl);
388
389 me_cl->props = res->client_properties;
390 me_cl->client_id = res->me_addr;
391 me_cl->tx_flow_ctrl_creds = 0;
392
393 mei_me_cl_add(dev, me_cl);
394
395 return 0;
396}
397
398
399
400
401
402
403
404
405
406
407static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status)
408{
409 struct mei_msg_hdr mei_hdr;
410 struct hbm_add_client_response resp;
411 const size_t len = sizeof(struct hbm_add_client_response);
412 int ret;
413
414 dev_dbg(dev->dev, "adding client response\n");
415
416 mei_hbm_hdr(&mei_hdr, len);
417
418 memset(&resp, 0, sizeof(struct hbm_add_client_response));
419 resp.hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD;
420 resp.me_addr = addr;
421 resp.status = status;
422
423 ret = mei_hbm_write_message(dev, &mei_hdr, &resp);
424 if (ret)
425 dev_err(dev->dev, "add client response write failed: ret = %d\n",
426 ret);
427 return ret;
428}
429
430
431
432
433
434
435
436
437
438static int mei_hbm_fw_add_cl_req(struct mei_device *dev,
439 struct hbm_add_client_request *req)
440{
441 int ret;
442 u8 status = MEI_HBMS_SUCCESS;
443
444 BUILD_BUG_ON(sizeof(struct hbm_add_client_request) !=
445 sizeof(struct hbm_props_response));
446
447 ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req);
448 if (ret)
449 status = !MEI_HBMS_SUCCESS;
450
451 if (dev->dev_state == MEI_DEV_ENABLED)
452 schedule_work(&dev->bus_rescan_work);
453
454 return mei_hbm_add_cl_resp(dev, req->me_addr, status);
455}
456
457
458
459
460
461
462
463
464
465
466int mei_hbm_cl_notify_req(struct mei_device *dev,
467 struct mei_cl *cl, u8 start)
468{
469
470 struct mei_msg_hdr mei_hdr;
471 struct hbm_notification_request req;
472 const size_t len = sizeof(struct hbm_notification_request);
473 int ret;
474
475 mei_hbm_hdr(&mei_hdr, len);
476 mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, &req, len);
477
478 req.start = start;
479
480 ret = mei_hbm_write_message(dev, &mei_hdr, &req);
481 if (ret)
482 dev_err(dev->dev, "notify request failed: ret = %d\n", ret);
483
484 return ret;
485}
486
487
488
489
490
491
492
493
494
495static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
496{
497 struct hbm_notification_response *rs =
498 (struct hbm_notification_response *)cmd;
499
500 return mei_cl_notify_req2fop(rs->start);
501}
502
503
504
505
506
507
508
509
510
511static void mei_hbm_cl_notify_start_res(struct mei_device *dev,
512 struct mei_cl *cl,
513 struct mei_hbm_cl_cmd *cmd)
514{
515 struct hbm_notification_response *rs =
516 (struct hbm_notification_response *)cmd;
517
518 cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status);
519
520 if (rs->status == MEI_HBMS_SUCCESS ||
521 rs->status == MEI_HBMS_ALREADY_STARTED) {
522 cl->notify_en = true;
523 cl->status = 0;
524 } else {
525 cl->status = -EINVAL;
526 }
527}
528
529
530
531
532
533
534
535
536
537static void mei_hbm_cl_notify_stop_res(struct mei_device *dev,
538 struct mei_cl *cl,
539 struct mei_hbm_cl_cmd *cmd)
540{
541 struct hbm_notification_response *rs =
542 (struct hbm_notification_response *)cmd;
543
544 cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status);
545
546 if (rs->status == MEI_HBMS_SUCCESS ||
547 rs->status == MEI_HBMS_NOT_STARTED) {
548 cl->notify_en = false;
549 cl->status = 0;
550 } else {
551
552 cl->status = -EINVAL;
553 }
554}
555
556
557
558
559
560
561
562static void mei_hbm_cl_notify(struct mei_device *dev,
563 struct mei_hbm_cl_cmd *cmd)
564{
565 struct mei_cl *cl;
566
567 cl = mei_hbm_cl_find_by_cmd(dev, cmd);
568 if (cl)
569 mei_cl_notify(cl);
570}
571
572
573
574
575
576
577
578
579
580static int mei_hbm_prop_req(struct mei_device *dev, unsigned long start_idx)
581{
582 struct mei_msg_hdr mei_hdr;
583 struct hbm_props_request prop_req;
584 const size_t len = sizeof(struct hbm_props_request);
585 unsigned long addr;
586 int ret;
587
588 addr = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, start_idx);
589
590
591 if (addr == MEI_CLIENTS_MAX) {
592 dev->hbm_state = MEI_HBM_STARTED;
593 mei_host_client_init(dev);
594
595 return 0;
596 }
597
598 mei_hbm_hdr(&mei_hdr, len);
599
600 memset(&prop_req, 0, sizeof(struct hbm_props_request));
601
602 prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
603 prop_req.me_addr = addr;
604
605 ret = mei_hbm_write_message(dev, &mei_hdr, &prop_req);
606 if (ret) {
607 dev_err(dev->dev, "properties request write failed: ret = %d\n",
608 ret);
609 return ret;
610 }
611
612 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
613 mei_schedule_stall_timer(dev);
614
615 return 0;
616}
617
618
619
620
621
622
623
624
625
626
627int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd)
628{
629 struct mei_msg_hdr mei_hdr;
630 struct hbm_power_gate req;
631 const size_t len = sizeof(struct hbm_power_gate);
632 int ret;
633
634 if (!dev->hbm_f_pg_supported)
635 return -EOPNOTSUPP;
636
637 mei_hbm_hdr(&mei_hdr, len);
638
639 memset(&req, 0, len);
640 req.hbm_cmd = pg_cmd;
641
642 ret = mei_hbm_write_message(dev, &mei_hdr, &req);
643 if (ret)
644 dev_err(dev->dev, "power gate command write failed.\n");
645 return ret;
646}
647EXPORT_SYMBOL_GPL(mei_hbm_pg);
648
649
650
651
652
653
654
655
656static int mei_hbm_stop_req(struct mei_device *dev)
657{
658 struct mei_msg_hdr mei_hdr;
659 struct hbm_host_stop_request req;
660 const size_t len = sizeof(struct hbm_host_stop_request);
661
662 mei_hbm_hdr(&mei_hdr, len);
663
664 memset(&req, 0, len);
665 req.hbm_cmd = HOST_STOP_REQ_CMD;
666 req.reason = DRIVER_STOP_REQUEST;
667
668 return mei_hbm_write_message(dev, &mei_hdr, &req);
669}
670
671
672
673
674
675
676
677
678
679int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
680{
681 struct hbm_flow_control req;
682
683 cl_dbg(dev, cl, "sending flow control\n");
684 return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD,
685 &req, sizeof(req));
686}
687
688
689
690
691
692
693
694
695
696static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,
697 struct hbm_flow_control *fctrl)
698{
699 struct mei_me_client *me_cl;
700 int rets;
701
702 me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);
703 if (!me_cl) {
704 dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);
705 return -ENOENT;
706 }
707
708 if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
709 rets = -EINVAL;
710 goto out;
711 }
712
713 me_cl->tx_flow_ctrl_creds++;
714 dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
715 fctrl->me_addr, me_cl->tx_flow_ctrl_creds);
716
717 rets = 0;
718out:
719 mei_me_cl_put(me_cl);
720 return rets;
721}
722
723
724
725
726
727
728
729static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
730 struct hbm_flow_control *fctrl)
731{
732 struct mei_cl *cl;
733
734 if (!fctrl->host_addr) {
735
736 mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);
737 return;
738 }
739
740 cl = mei_hbm_cl_find_by_cmd(dev, fctrl);
741 if (cl) {
742 cl->tx_flow_ctrl_creds++;
743 cl_dbg(dev, cl, "flow control creds = %d.\n",
744 cl->tx_flow_ctrl_creds);
745 }
746}
747
748
749
750
751
752
753
754
755
756
757int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
758{
759 struct hbm_client_connect_request req;
760
761 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD,
762 &req, sizeof(req));
763}
764
765
766
767
768
769
770
771
772
773int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
774{
775 struct hbm_client_connect_response resp;
776
777 return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD,
778 &resp, sizeof(resp));
779}
780
781
782
783
784
785
786
787
788
789static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
790 struct mei_hbm_cl_cmd *cmd)
791{
792 struct hbm_client_connect_response *rs =
793 (struct hbm_client_connect_response *)cmd;
794
795 cl_dbg(dev, cl, "hbm: disconnect response status=%d\n", rs->status);
796
797 if (rs->status == MEI_CL_DISCONN_SUCCESS)
798 cl->state = MEI_FILE_DISCONNECT_REPLY;
799 cl->status = 0;
800}
801
802
803
804
805
806
807
808
809
810int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
811{
812 struct hbm_client_connect_request req;
813
814 return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD,
815 &req, sizeof(req));
816}
817
818
819
820
821
822
823
824
825
826static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl,
827 struct mei_hbm_cl_cmd *cmd)
828{
829 struct hbm_client_connect_response *rs =
830 (struct hbm_client_connect_response *)cmd;
831
832 cl_dbg(dev, cl, "hbm: connect response status=%s\n",
833 mei_cl_conn_status_str(rs->status));
834
835 if (rs->status == MEI_CL_CONN_SUCCESS)
836 cl->state = MEI_FILE_CONNECTED;
837 else {
838 cl->state = MEI_FILE_DISCONNECT_REPLY;
839 if (rs->status == MEI_CL_CONN_NOT_FOUND) {
840 mei_me_cl_del(dev, cl->me_cl);
841 if (dev->dev_state == MEI_DEV_ENABLED)
842 schedule_work(&dev->bus_rescan_work);
843 }
844 }
845 cl->status = mei_cl_conn_status_to_errno(rs->status);
846}
847
848
849
850
851
852
853
854
855
856static void mei_hbm_cl_res(struct mei_device *dev,
857 struct mei_hbm_cl_cmd *rs,
858 enum mei_cb_file_ops fop_type)
859{
860 struct mei_cl *cl;
861 struct mei_cl_cb *cb, *next;
862
863 cl = NULL;
864 list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) {
865
866 cl = cb->cl;
867
868 if (cb->fop_type != fop_type)
869 continue;
870
871 if (mei_hbm_cl_addr_equal(cl, rs)) {
872 list_del_init(&cb->list);
873 break;
874 }
875 }
876
877 if (!cl)
878 return;
879
880 switch (fop_type) {
881 case MEI_FOP_CONNECT:
882 mei_hbm_cl_connect_res(dev, cl, rs);
883 break;
884 case MEI_FOP_DISCONNECT:
885 mei_hbm_cl_disconnect_res(dev, cl, rs);
886 break;
887 case MEI_FOP_NOTIFY_START:
888 mei_hbm_cl_notify_start_res(dev, cl, rs);
889 break;
890 case MEI_FOP_NOTIFY_STOP:
891 mei_hbm_cl_notify_stop_res(dev, cl, rs);
892 break;
893 default:
894 return;
895 }
896
897 cl->timer_count = 0;
898 wake_up(&cl->wait);
899}
900
901
902
903
904
905
906
907
908
909
910
911static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
912 struct hbm_client_connect_request *disconnect_req)
913{
914 struct mei_cl *cl;
915 struct mei_cl_cb *cb;
916
917 cl = mei_hbm_cl_find_by_cmd(dev, disconnect_req);
918 if (cl) {
919 cl_warn(dev, cl, "fw disconnect request received\n");
920 cl->state = MEI_FILE_DISCONNECTING;
921 cl->timer_count = 0;
922
923 cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,
924 NULL);
925 if (!cb)
926 return -ENOMEM;
927 }
928 return 0;
929}
930
931
932
933
934
935
936
937
938static int mei_hbm_pg_enter_res(struct mei_device *dev)
939{
940 if (mei_pg_state(dev) != MEI_PG_OFF ||
941 dev->pg_event != MEI_PG_EVENT_WAIT) {
942 dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n",
943 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
944 return -EPROTO;
945 }
946
947 dev->pg_event = MEI_PG_EVENT_RECEIVED;
948 wake_up(&dev->wait_pg);
949
950 return 0;
951}
952
953
954
955
956
957
958void mei_hbm_pg_resume(struct mei_device *dev)
959{
960 pm_request_resume(dev->dev);
961}
962EXPORT_SYMBOL_GPL(mei_hbm_pg_resume);
963
964
965
966
967
968
969
970
971static int mei_hbm_pg_exit_res(struct mei_device *dev)
972{
973 if (mei_pg_state(dev) != MEI_PG_ON ||
974 (dev->pg_event != MEI_PG_EVENT_WAIT &&
975 dev->pg_event != MEI_PG_EVENT_IDLE)) {
976 dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n",
977 mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
978 return -EPROTO;
979 }
980
981 switch (dev->pg_event) {
982 case MEI_PG_EVENT_WAIT:
983 dev->pg_event = MEI_PG_EVENT_RECEIVED;
984 wake_up(&dev->wait_pg);
985 break;
986 case MEI_PG_EVENT_IDLE:
987
988
989
990
991
992 dev->pg_event = MEI_PG_EVENT_RECEIVED;
993 mei_hbm_pg_resume(dev);
994 break;
995 default:
996 WARN(1, "hbm: pg exit response: unexpected pg event = %d\n",
997 dev->pg_event);
998 return -EPROTO;
999 }
1000
1001 return 0;
1002}
1003
1004
1005
1006
1007
1008
1009
1010static void mei_hbm_config_features(struct mei_device *dev)
1011{
1012
1013 dev->hbm_f_pg_supported = 0;
1014 if (dev->version.major_version > HBM_MAJOR_VERSION_PGI)
1015 dev->hbm_f_pg_supported = 1;
1016
1017 if (dev->version.major_version == HBM_MAJOR_VERSION_PGI &&
1018 dev->version.minor_version >= HBM_MINOR_VERSION_PGI)
1019 dev->hbm_f_pg_supported = 1;
1020
1021 dev->hbm_f_dc_supported = 0;
1022 if (dev->version.major_version >= HBM_MAJOR_VERSION_DC)
1023 dev->hbm_f_dc_supported = 1;
1024
1025 dev->hbm_f_ie_supported = 0;
1026 if (dev->version.major_version >= HBM_MAJOR_VERSION_IE)
1027 dev->hbm_f_ie_supported = 1;
1028
1029
1030 dev->hbm_f_dot_supported = 0;
1031 if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
1032 dev->hbm_f_dot_supported = 1;
1033
1034
1035 dev->hbm_f_ev_supported = 0;
1036 if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
1037 dev->hbm_f_ev_supported = 1;
1038
1039
1040 dev->hbm_f_fa_supported = 0;
1041 if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
1042 dev->hbm_f_fa_supported = 1;
1043
1044
1045 dev->hbm_f_os_supported = 0;
1046 if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)
1047 dev->hbm_f_os_supported = 1;
1048
1049
1050 dev->hbm_f_dr_supported = 0;
1051 if (dev->version.major_version > HBM_MAJOR_VERSION_DR ||
1052 (dev->version.major_version == HBM_MAJOR_VERSION_DR &&
1053 dev->version.minor_version >= HBM_MINOR_VERSION_DR))
1054 dev->hbm_f_dr_supported = 1;
1055}
1056
1057
1058
1059
1060
1061
1062
1063
1064bool mei_hbm_version_is_supported(struct mei_device *dev)
1065{
1066 return (dev->version.major_version < HBM_MAJOR_VERSION) ||
1067 (dev->version.major_version == HBM_MAJOR_VERSION &&
1068 dev->version.minor_version <= HBM_MINOR_VERSION);
1069}
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
1081{
1082 struct mei_bus_message *mei_msg;
1083 struct hbm_host_version_response *version_res;
1084 struct hbm_props_response *props_res;
1085 struct hbm_host_enum_response *enum_res;
1086 struct hbm_dma_setup_response *dma_setup_res;
1087 struct hbm_add_client_request *add_cl_req;
1088 int ret;
1089
1090 struct mei_hbm_cl_cmd *cl_cmd;
1091 struct hbm_client_connect_request *disconnect_req;
1092 struct hbm_flow_control *fctrl;
1093
1094
1095 BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
1096 mei_read_slots(dev, dev->rd_msg_buf, hdr->length);
1097 mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
1098 cl_cmd = (struct mei_hbm_cl_cmd *)mei_msg;
1099
1100
1101
1102
1103 if (dev->hbm_state == MEI_HBM_IDLE) {
1104 dev_dbg(dev->dev, "hbm: state is idle ignore spurious messages\n");
1105 return 0;
1106 }
1107
1108 switch (mei_msg->hbm_cmd) {
1109 case HOST_START_RES_CMD:
1110 dev_dbg(dev->dev, "hbm: start: response message received.\n");
1111
1112 dev->init_clients_timer = 0;
1113
1114 version_res = (struct hbm_host_version_response *)mei_msg;
1115
1116 dev_dbg(dev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
1117 HBM_MAJOR_VERSION, HBM_MINOR_VERSION,
1118 version_res->me_max_version.major_version,
1119 version_res->me_max_version.minor_version);
1120
1121 if (version_res->host_version_supported) {
1122 dev->version.major_version = HBM_MAJOR_VERSION;
1123 dev->version.minor_version = HBM_MINOR_VERSION;
1124 } else {
1125 dev->version.major_version =
1126 version_res->me_max_version.major_version;
1127 dev->version.minor_version =
1128 version_res->me_max_version.minor_version;
1129 }
1130
1131 if (!mei_hbm_version_is_supported(dev)) {
1132 dev_warn(dev->dev, "hbm: start: version mismatch - stopping the driver.\n");
1133
1134 dev->hbm_state = MEI_HBM_STOPPED;
1135 if (mei_hbm_stop_req(dev)) {
1136 dev_err(dev->dev, "hbm: start: failed to send stop request\n");
1137 return -EIO;
1138 }
1139 break;
1140 }
1141
1142 mei_hbm_config_features(dev);
1143
1144 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
1145 dev->hbm_state != MEI_HBM_STARTING) {
1146 dev_err(dev->dev, "hbm: start: state mismatch, [%d, %d]\n",
1147 dev->dev_state, dev->hbm_state);
1148 return -EPROTO;
1149 }
1150
1151 if (dev->hbm_f_dr_supported) {
1152 if (mei_dmam_ring_alloc(dev))
1153 dev_info(dev->dev, "running w/o dma ring\n");
1154 if (mei_dma_ring_is_allocated(dev)) {
1155 if (mei_hbm_dma_setup_req(dev))
1156 return -EIO;
1157
1158 wake_up(&dev->wait_hbm_start);
1159 break;
1160 }
1161 }
1162
1163 dev->hbm_f_dr_supported = 0;
1164 mei_dmam_ring_free(dev);
1165
1166 if (mei_hbm_enum_clients_req(dev))
1167 return -EIO;
1168
1169 wake_up(&dev->wait_hbm_start);
1170 break;
1171
1172 case MEI_HBM_DMA_SETUP_RES_CMD:
1173 dev_dbg(dev->dev, "hbm: dma setup response: message received.\n");
1174
1175 dev->init_clients_timer = 0;
1176
1177 if (dev->hbm_state != MEI_HBM_DR_SETUP) {
1178 dev_err(dev->dev, "hbm: dma setup response: state mismatch, [%d, %d]\n",
1179 dev->dev_state, dev->hbm_state);
1180 return -EPROTO;
1181 }
1182
1183 dma_setup_res = (struct hbm_dma_setup_response *)mei_msg;
1184
1185 if (dma_setup_res->status) {
1186 u8 status = dma_setup_res->status;
1187
1188 if (status == MEI_HBMS_NOT_ALLOWED) {
1189 dev_dbg(dev->dev, "hbm: dma setup not allowed\n");
1190 } else {
1191 dev_info(dev->dev, "hbm: dma setup response: failure = %d %s\n",
1192 status,
1193 mei_hbm_status_str(status));
1194 }
1195 dev->hbm_f_dr_supported = 0;
1196 mei_dmam_ring_free(dev);
1197 }
1198
1199 if (mei_hbm_enum_clients_req(dev))
1200 return -EIO;
1201 break;
1202
1203 case CLIENT_CONNECT_RES_CMD:
1204 dev_dbg(dev->dev, "hbm: client connect response: message received.\n");
1205 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_CONNECT);
1206 break;
1207
1208 case CLIENT_DISCONNECT_RES_CMD:
1209 dev_dbg(dev->dev, "hbm: client disconnect response: message received.\n");
1210 mei_hbm_cl_res(dev, cl_cmd, MEI_FOP_DISCONNECT);
1211 break;
1212
1213 case MEI_FLOW_CONTROL_CMD:
1214 dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
1215
1216 fctrl = (struct hbm_flow_control *)mei_msg;
1217 mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);
1218 break;
1219
1220 case MEI_PG_ISOLATION_ENTRY_RES_CMD:
1221 dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n");
1222 ret = mei_hbm_pg_enter_res(dev);
1223 if (ret)
1224 return ret;
1225 break;
1226
1227 case MEI_PG_ISOLATION_EXIT_REQ_CMD:
1228 dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n");
1229 ret = mei_hbm_pg_exit_res(dev);
1230 if (ret)
1231 return ret;
1232 break;
1233
1234 case HOST_CLIENT_PROPERTIES_RES_CMD:
1235 dev_dbg(dev->dev, "hbm: properties response: message received.\n");
1236
1237 dev->init_clients_timer = 0;
1238
1239 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
1240 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
1241 dev_err(dev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
1242 dev->dev_state, dev->hbm_state);
1243 return -EPROTO;
1244 }
1245
1246 props_res = (struct hbm_props_response *)mei_msg;
1247
1248 if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) {
1249 dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n",
1250 props_res->me_addr);
1251 } else if (props_res->status) {
1252 dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n",
1253 props_res->status,
1254 mei_hbm_status_str(props_res->status));
1255 return -EPROTO;
1256 } else {
1257 mei_hbm_me_cl_add(dev, props_res);
1258 }
1259
1260
1261 if (mei_hbm_prop_req(dev, props_res->me_addr + 1))
1262 return -EIO;
1263
1264 break;
1265
1266 case HOST_ENUM_RES_CMD:
1267 dev_dbg(dev->dev, "hbm: enumeration response: message received\n");
1268
1269 dev->init_clients_timer = 0;
1270
1271 enum_res = (struct hbm_host_enum_response *) mei_msg;
1272 BUILD_BUG_ON(sizeof(dev->me_clients_map)
1273 < sizeof(enum_res->valid_addresses));
1274 memcpy(dev->me_clients_map, enum_res->valid_addresses,
1275 sizeof(enum_res->valid_addresses));
1276
1277 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
1278 dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
1279 dev_err(dev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
1280 dev->dev_state, dev->hbm_state);
1281 return -EPROTO;
1282 }
1283
1284 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
1285
1286
1287 if (mei_hbm_prop_req(dev, 0))
1288 return -EIO;
1289
1290 break;
1291
1292 case HOST_STOP_RES_CMD:
1293 dev_dbg(dev->dev, "hbm: stop response: message received\n");
1294
1295 dev->init_clients_timer = 0;
1296
1297 if (dev->hbm_state != MEI_HBM_STOPPED) {
1298 dev_err(dev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
1299 dev->dev_state, dev->hbm_state);
1300 return -EPROTO;
1301 }
1302
1303 dev->dev_state = MEI_DEV_POWER_DOWN;
1304 dev_info(dev->dev, "hbm: stop response: resetting.\n");
1305
1306 return -EPROTO;
1307 break;
1308
1309 case CLIENT_DISCONNECT_REQ_CMD:
1310 dev_dbg(dev->dev, "hbm: disconnect request: message received\n");
1311
1312 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
1313 mei_hbm_fw_disconnect_req(dev, disconnect_req);
1314 break;
1315
1316 case ME_STOP_REQ_CMD:
1317 dev_dbg(dev->dev, "hbm: stop request: message received\n");
1318 dev->hbm_state = MEI_HBM_STOPPED;
1319 if (mei_hbm_stop_req(dev)) {
1320 dev_err(dev->dev, "hbm: stop request: failed to send stop request\n");
1321 return -EIO;
1322 }
1323 break;
1324
1325 case MEI_HBM_ADD_CLIENT_REQ_CMD:
1326 dev_dbg(dev->dev, "hbm: add client request received\n");
1327
1328
1329
1330
1331 if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS ||
1332 dev->hbm_state >= MEI_HBM_STOPPED) {
1333 dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n",
1334 dev->dev_state, dev->hbm_state);
1335 return -EPROTO;
1336 }
1337 add_cl_req = (struct hbm_add_client_request *)mei_msg;
1338 ret = mei_hbm_fw_add_cl_req(dev, add_cl_req);
1339 if (ret) {
1340 dev_err(dev->dev, "hbm: add client: failed to send response %d\n",
1341 ret);
1342 return -EIO;
1343 }
1344 dev_dbg(dev->dev, "hbm: add client request processed\n");
1345 break;
1346
1347 case MEI_HBM_NOTIFY_RES_CMD:
1348 dev_dbg(dev->dev, "hbm: notify response received\n");
1349 mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd));
1350 break;
1351
1352 case MEI_HBM_NOTIFICATION_CMD:
1353 dev_dbg(dev->dev, "hbm: notification\n");
1354 mei_hbm_cl_notify(dev, cl_cmd);
1355 break;
1356
1357 default:
1358 WARN(1, "hbm: wrong command %d\n", mei_msg->hbm_cmd);
1359 return -EPROTO;
1360
1361 }
1362 return 0;
1363}
1364
1365