aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/mei/hbm.c200
-rw-r--r--drivers/misc/mei/hbm.h6
-rw-r--r--drivers/misc/mei/hw-me.c32
-rw-r--r--drivers/misc/mei/init.c100
-rw-r--r--drivers/misc/mei/interrupt.c9
-rw-r--r--drivers/misc/mei/mei_dev.h1
6 files changed, 210 insertions, 138 deletions
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 9b3a0fb7f265..8109b9a98cc3 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -28,9 +28,9 @@
28 * 28 *
29 * @dev: the device structure 29 * @dev: the device structure
30 * 30 *
31 * returns none. 31 * returns 0 on success -ENOMEM on allocation failure
32 */ 32 */
33static void mei_hbm_me_cl_allocate(struct mei_device *dev) 33static int mei_hbm_me_cl_allocate(struct mei_device *dev)
34{ 34{
35 struct mei_me_client *clients; 35 struct mei_me_client *clients;
36 int b; 36 int b;
@@ -44,7 +44,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
44 dev->me_clients_num++; 44 dev->me_clients_num++;
45 45
46 if (dev->me_clients_num == 0) 46 if (dev->me_clients_num == 0)
47 return; 47 return 0;
48 48
49 kfree(dev->me_clients); 49 kfree(dev->me_clients);
50 dev->me_clients = NULL; 50 dev->me_clients = NULL;
@@ -56,12 +56,10 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
56 sizeof(struct mei_me_client), GFP_KERNEL); 56 sizeof(struct mei_me_client), GFP_KERNEL);
57 if (!clients) { 57 if (!clients) {
58 dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); 58 dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
59 dev->dev_state = MEI_DEV_RESETTING; 59 return -ENOMEM;
60 mei_reset(dev, 1);
61 return;
62 } 60 }
63 dev->me_clients = clients; 61 dev->me_clients = clients;
64 return; 62 return 0;
65} 63}
66 64
67/** 65/**
@@ -137,7 +135,7 @@ int mei_hbm_start_wait(struct mei_device *dev)
137 mutex_unlock(&dev->device_lock); 135 mutex_unlock(&dev->device_lock);
138 ret = wait_event_interruptible_timeout(dev->wait_recvd_msg, 136 ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
139 dev->hbm_state == MEI_HBM_IDLE || 137 dev->hbm_state == MEI_HBM_IDLE ||
140 dev->hbm_state > MEI_HBM_START, 138 dev->hbm_state >= MEI_HBM_STARTED,
141 mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); 139 mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
142 mutex_lock(&dev->device_lock); 140 mutex_lock(&dev->device_lock);
143 141
@@ -153,12 +151,15 @@ int mei_hbm_start_wait(struct mei_device *dev)
153 * mei_hbm_start_req - sends start request message. 151 * mei_hbm_start_req - sends start request message.
154 * 152 *
155 * @dev: the device structure 153 * @dev: the device structure
154 *
155 * returns 0 on success and < 0 on failure
156 */ 156 */
157int mei_hbm_start_req(struct mei_device *dev) 157int mei_hbm_start_req(struct mei_device *dev)
158{ 158{
159 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; 159 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
160 struct hbm_host_version_request *start_req; 160 struct hbm_host_version_request *start_req;
161 const size_t len = sizeof(struct hbm_host_version_request); 161 const size_t len = sizeof(struct hbm_host_version_request);
162 int ret;
162 163
163 mei_hbm_hdr(mei_hdr, len); 164 mei_hbm_hdr(mei_hdr, len);
164 165
@@ -170,12 +171,13 @@ int mei_hbm_start_req(struct mei_device *dev)
170 start_req->host_version.minor_version = HBM_MINOR_VERSION; 171 start_req->host_version.minor_version = HBM_MINOR_VERSION;
171 172
172 dev->hbm_state = MEI_HBM_IDLE; 173 dev->hbm_state = MEI_HBM_IDLE;
173 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { 174 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
174 dev_err(&dev->pdev->dev, "version message write failed\n"); 175 if (ret) {
175 dev->dev_state = MEI_DEV_RESETTING; 176 dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n",
176 mei_reset(dev, 1); 177 ret);
177 return -EIO; 178 return ret;
178 } 179 }
180
179 dev->hbm_state = MEI_HBM_START; 181 dev->hbm_state = MEI_HBM_START;
180 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 182 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
181 return 0; 183 return 0;
@@ -186,13 +188,15 @@ int mei_hbm_start_req(struct mei_device *dev)
186 * 188 *
187 * @dev: the device structure 189 * @dev: the device structure
188 * 190 *
189 * returns none. 191 * returns 0 on success and < 0 on failure
190 */ 192 */
191static void mei_hbm_enum_clients_req(struct mei_device *dev) 193static int mei_hbm_enum_clients_req(struct mei_device *dev)
192{ 194{
193 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; 195 struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
194 struct hbm_host_enum_request *enum_req; 196 struct hbm_host_enum_request *enum_req;
195 const size_t len = sizeof(struct hbm_host_enum_request); 197 const size_t len = sizeof(struct hbm_host_enum_request);
198 int ret;
199
196 /* enumerate clients */ 200 /* enumerate clients */
197 mei_hbm_hdr(mei_hdr, len); 201 mei_hbm_hdr(mei_hdr, len);
198 202
@@ -200,14 +204,15 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
200 memset(enum_req, 0, len); 204 memset(enum_req, 0, len);
201 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; 205 enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
202 206
203 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { 207 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
204 dev->dev_state = MEI_DEV_RESETTING; 208 if (ret) {
205 dev_err(&dev->pdev->dev, "enumeration request write failed.\n"); 209 dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n",
206 mei_reset(dev, 1); 210 ret);
211 return ret;
207 } 212 }
208 dev->hbm_state = MEI_HBM_ENUM_CLIENTS; 213 dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
209 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 214 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
210 return; 215 return 0;
211} 216}
212 217
213/** 218/**
@@ -215,7 +220,7 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
215 * 220 *
216 * @dev: the device structure 221 * @dev: the device structure
217 * 222 *
218 * returns none. 223 * returns 0 on success and < 0 on failure
219 */ 224 */
220 225
221static int mei_hbm_prop_req(struct mei_device *dev) 226static int mei_hbm_prop_req(struct mei_device *dev)
@@ -226,7 +231,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
226 const size_t len = sizeof(struct hbm_props_request); 231 const size_t len = sizeof(struct hbm_props_request);
227 unsigned long next_client_index; 232 unsigned long next_client_index;
228 unsigned long client_num; 233 unsigned long client_num;
229 234 int ret;
230 235
231 client_num = dev->me_client_presentation_num; 236 client_num = dev->me_client_presentation_num;
232 237
@@ -253,12 +258,11 @@ static int mei_hbm_prop_req(struct mei_device *dev)
253 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; 258 prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
254 prop_req->address = next_client_index; 259 prop_req->address = next_client_index;
255 260
256 if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { 261 ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data);
257 dev->dev_state = MEI_DEV_RESETTING; 262 if (ret) {
258 dev_err(&dev->pdev->dev, "properties request write failed\n"); 263 dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n",
259 mei_reset(dev, 1); 264 ret);
260 265 return ret;
261 return -EIO;
262 } 266 }
263 267
264 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; 268 dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
@@ -559,8 +563,10 @@ bool mei_hbm_version_is_supported(struct mei_device *dev)
559 * 563 *
560 * @dev: the device structure 564 * @dev: the device structure
561 * @mei_hdr: header of bus message 565 * @mei_hdr: header of bus message
566 *
567 * returns 0 on success and < 0 on failure
562 */ 568 */
563void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) 569int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
564{ 570{
565 struct mei_bus_message *mei_msg; 571 struct mei_bus_message *mei_msg;
566 struct mei_me_client *me_client; 572 struct mei_me_client *me_client;
@@ -579,6 +585,10 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
579 585
580 switch (mei_msg->hbm_cmd) { 586 switch (mei_msg->hbm_cmd) {
581 case HOST_START_RES_CMD: 587 case HOST_START_RES_CMD:
588 dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n");
589
590 dev->init_clients_timer = 0;
591
582 version_res = (struct hbm_host_version_response *)mei_msg; 592 version_res = (struct hbm_host_version_response *)mei_msg;
583 593
584 dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", 594 dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n",
@@ -597,73 +607,89 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
597 } 607 }
598 608
599 if (!mei_hbm_version_is_supported(dev)) { 609 if (!mei_hbm_version_is_supported(dev)) {
600 dev_warn(&dev->pdev->dev, "hbm version mismatch: stopping the driver.\n"); 610 dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n");
601 611
602 dev->hbm_state = MEI_HBM_STOP; 612 dev->hbm_state = MEI_HBM_STOPPED;
603 mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, 613 mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
604 dev->wr_msg.data); 614 dev->wr_msg.data);
605 mei_write_message(dev, &dev->wr_msg.hdr, 615 if (mei_write_message(dev, &dev->wr_msg.hdr,
606 dev->wr_msg.data); 616 dev->wr_msg.data)) {
617 dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n");
618 return -EIO;
619 }
620 break;
621 }
607 622
608 return; 623 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
624 dev->hbm_state != MEI_HBM_START) {
625 dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n",
626 dev->dev_state, dev->hbm_state);
627 return -EPROTO;
609 } 628 }
610 629
611 if (dev->dev_state == MEI_DEV_INIT_CLIENTS && 630 dev->hbm_state = MEI_HBM_STARTED;
612 dev->hbm_state == MEI_HBM_START) { 631
613 dev->init_clients_timer = 0; 632 if (mei_hbm_enum_clients_req(dev)) {
614 mei_hbm_enum_clients_req(dev); 633 dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n");
615 } else { 634 return -EIO;
616 dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
617 mei_reset(dev, 1);
618 return;
619 } 635 }
620 636
621 wake_up_interruptible(&dev->wait_recvd_msg); 637 wake_up_interruptible(&dev->wait_recvd_msg);
622 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
623 break; 638 break;
624 639
625 case CLIENT_CONNECT_RES_CMD: 640 case CLIENT_CONNECT_RES_CMD:
641 dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n");
642
626 connect_res = (struct hbm_client_connect_response *) mei_msg; 643 connect_res = (struct hbm_client_connect_response *) mei_msg;
627 mei_hbm_cl_connect_res(dev, connect_res); 644 mei_hbm_cl_connect_res(dev, connect_res);
628 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
629 wake_up(&dev->wait_recvd_msg); 645 wake_up(&dev->wait_recvd_msg);
630 break; 646 break;
631 647
632 case CLIENT_DISCONNECT_RES_CMD: 648 case CLIENT_DISCONNECT_RES_CMD:
649 dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n");
650
633 disconnect_res = (struct hbm_client_connect_response *) mei_msg; 651 disconnect_res = (struct hbm_client_connect_response *) mei_msg;
634 mei_hbm_cl_disconnect_res(dev, disconnect_res); 652 mei_hbm_cl_disconnect_res(dev, disconnect_res);
635 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
636 wake_up(&dev->wait_recvd_msg); 653 wake_up(&dev->wait_recvd_msg);
637 break; 654 break;
638 655
639 case MEI_FLOW_CONTROL_CMD: 656 case MEI_FLOW_CONTROL_CMD:
657 dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n");
658
640 flow_control = (struct hbm_flow_control *) mei_msg; 659 flow_control = (struct hbm_flow_control *) mei_msg;
641 mei_hbm_cl_flow_control_res(dev, flow_control); 660 mei_hbm_cl_flow_control_res(dev, flow_control);
642 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
643 break; 661 break;
644 662
645 case HOST_CLIENT_PROPERTIES_RES_CMD: 663 case HOST_CLIENT_PROPERTIES_RES_CMD:
664 dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n");
665
666 dev->init_clients_timer = 0;
667
668 if (dev->me_clients == NULL) {
669 dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n");
670 return -EPROTO;
671 }
672
646 props_res = (struct hbm_props_response *)mei_msg; 673 props_res = (struct hbm_props_response *)mei_msg;
647 me_client = &dev->me_clients[dev->me_client_presentation_num]; 674 me_client = &dev->me_clients[dev->me_client_presentation_num];
648 675
649 if (props_res->status || !dev->me_clients) { 676 if (props_res->status) {
650 dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n"); 677 dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n",
651 mei_reset(dev, 1); 678 props_res->status);
652 return; 679 return -EPROTO;
653 } 680 }
654 681
655 if (me_client->client_id != props_res->address) { 682 if (me_client->client_id != props_res->address) {
656 dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n"); 683 dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n",
657 mei_reset(dev, 1); 684 me_client->client_id, props_res->address);
658 return; 685 return -EPROTO;
659 } 686 }
660 687
661 if (dev->dev_state != MEI_DEV_INIT_CLIENTS || 688 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
662 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { 689 dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
663 dev_err(&dev->pdev->dev, "reset: unexpected properties response\n"); 690 dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n",
664 mei_reset(dev, 1); 691 dev->dev_state, dev->hbm_state);
665 692 return -EPROTO;
666 return;
667 } 693 }
668 694
669 me_client->props = props_res->client_properties; 695 me_client->props = props_res->client_properties;
@@ -671,49 +697,70 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
671 dev->me_client_presentation_num++; 697 dev->me_client_presentation_num++;
672 698
673 /* request property for the next client */ 699 /* request property for the next client */
674 mei_hbm_prop_req(dev); 700 if (mei_hbm_prop_req(dev))
701 return -EIO;
675 702
676 break; 703 break;
677 704
678 case HOST_ENUM_RES_CMD: 705 case HOST_ENUM_RES_CMD:
706 dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n");
707
708 dev->init_clients_timer = 0;
709
679 enum_res = (struct hbm_host_enum_response *) mei_msg; 710 enum_res = (struct hbm_host_enum_response *) mei_msg;
680 BUILD_BUG_ON(sizeof(dev->me_clients_map) 711 BUILD_BUG_ON(sizeof(dev->me_clients_map)
681 < sizeof(enum_res->valid_addresses)); 712 < sizeof(enum_res->valid_addresses));
682 memcpy(dev->me_clients_map, enum_res->valid_addresses, 713 memcpy(dev->me_clients_map, enum_res->valid_addresses,
683 sizeof(enum_res->valid_addresses)); 714 sizeof(enum_res->valid_addresses));
684 if (dev->dev_state == MEI_DEV_INIT_CLIENTS && 715
685 dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { 716 if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
686 dev->init_clients_timer = 0; 717 dev->hbm_state != MEI_HBM_ENUM_CLIENTS) {
687 mei_hbm_me_cl_allocate(dev); 718 dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n",
688 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; 719 dev->dev_state, dev->hbm_state);
689 720 return -EPROTO;
690 /* first property reqeust */
691 mei_hbm_prop_req(dev);
692 } else {
693 dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
694 mei_reset(dev, 1);
695 return;
696 } 721 }
722
723 if (mei_hbm_me_cl_allocate(dev)) {
724 dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n");
725 return -ENOMEM;
726 }
727
728 dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
729
730 /* first property request */
731 if (mei_hbm_prop_req(dev))
732 return -EIO;
733
697 break; 734 break;
698 735
699 case HOST_STOP_RES_CMD: 736 case HOST_STOP_RES_CMD:
737 dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n");
738
739 dev->init_clients_timer = 0;
740
741 if (dev->hbm_state != MEI_HBM_STOPPED) {
742 dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n",
743 dev->dev_state, dev->hbm_state);
744 return -EPROTO;
745 }
700 746
701 if (dev->hbm_state != MEI_HBM_STOP)
702 dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
703 dev->dev_state = MEI_DEV_DISABLED; 747 dev->dev_state = MEI_DEV_DISABLED;
704 dev_info(&dev->pdev->dev, "reset: FW stop response.\n"); 748 dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n");
705 mei_reset(dev, 1); 749 /* force the reset */
750 return -EPROTO;
706 break; 751 break;
707 752
708 case CLIENT_DISCONNECT_REQ_CMD: 753 case CLIENT_DISCONNECT_REQ_CMD:
709 /* search for client */ 754 dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n");
755
710 disconnect_req = (struct hbm_client_connect_request *)mei_msg; 756 disconnect_req = (struct hbm_client_connect_request *)mei_msg;
711 mei_hbm_fw_disconnect_req(dev, disconnect_req); 757 mei_hbm_fw_disconnect_req(dev, disconnect_req);
712 break; 758 break;
713 759
714 case ME_STOP_REQ_CMD: 760 case ME_STOP_REQ_CMD:
761 dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n");
715 762
716 dev->hbm_state = MEI_HBM_STOP; 763 dev->hbm_state = MEI_HBM_STOPPED;
717 mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, 764 mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
718 dev->wr_ext_msg.data); 765 dev->wr_ext_msg.data);
719 break; 766 break;
@@ -722,5 +769,6 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
722 break; 769 break;
723 770
724 } 771 }
772 return 0;
725} 773}
726 774
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index 4ae2e56e404f..f2540fff7080 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -32,13 +32,13 @@ struct mei_cl;
32enum mei_hbm_state { 32enum mei_hbm_state {
33 MEI_HBM_IDLE = 0, 33 MEI_HBM_IDLE = 0,
34 MEI_HBM_START, 34 MEI_HBM_START,
35 MEI_HBM_STARTED,
35 MEI_HBM_ENUM_CLIENTS, 36 MEI_HBM_ENUM_CLIENTS,
36 MEI_HBM_CLIENT_PROPERTIES, 37 MEI_HBM_CLIENT_PROPERTIES,
37 MEI_HBM_STARTED, 38 MEI_HBM_STOPPED,
38 MEI_HBM_STOP,
39}; 39};
40 40
41void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); 41int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
42 42
43static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) 43static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
44{ 44{
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 3412adcdaeb0..6c07623704c2 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -469,7 +469,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
469 struct mei_device *dev = (struct mei_device *) dev_id; 469 struct mei_device *dev = (struct mei_device *) dev_id;
470 struct mei_cl_cb complete_list; 470 struct mei_cl_cb complete_list;
471 s32 slots; 471 s32 slots;
472 int rets; 472 int rets = 0;
473 473
474 dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n"); 474 dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
475 /* initialize our complete list */ 475 /* initialize our complete list */
@@ -487,10 +487,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
487 dev->dev_state != MEI_DEV_INITIALIZING && 487 dev->dev_state != MEI_DEV_INITIALIZING &&
488 dev->dev_state != MEI_DEV_POWER_DOWN && 488 dev->dev_state != MEI_DEV_POWER_DOWN &&
489 dev->dev_state != MEI_DEV_POWER_UP) { 489 dev->dev_state != MEI_DEV_POWER_UP) {
490 dev_dbg(&dev->pdev->dev, "FW not ready.\n"); 490 dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n");
491 mei_reset(dev, 1); 491 schedule_work(&dev->reset_work);
492 mutex_unlock(&dev->device_lock); 492 goto end;
493 return IRQ_HANDLED;
494 } 493 }
495 494
496 /* check if we need to start the dev */ 495 /* check if we need to start the dev */
@@ -500,15 +499,12 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
500 499
501 dev->recvd_hw_ready = true; 500 dev->recvd_hw_ready = true;
502 wake_up_interruptible(&dev->wait_hw_ready); 501 wake_up_interruptible(&dev->wait_hw_ready);
503
504 mutex_unlock(&dev->device_lock);
505 return IRQ_HANDLED;
506 } else { 502 } else {
503
507 dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); 504 dev_dbg(&dev->pdev->dev, "Reset Completed.\n");
508 mei_me_hw_reset_release(dev); 505 mei_me_hw_reset_release(dev);
509 mutex_unlock(&dev->device_lock);
510 return IRQ_HANDLED;
511 } 506 }
507 goto end;
512 } 508 }
513 /* check slots available for reading */ 509 /* check slots available for reading */
514 slots = mei_count_full_read_slots(dev); 510 slots = mei_count_full_read_slots(dev);
@@ -516,21 +512,23 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
516 /* we have urgent data to send so break the read */ 512 /* we have urgent data to send so break the read */
517 if (dev->wr_ext_msg.hdr.length) 513 if (dev->wr_ext_msg.hdr.length)
518 break; 514 break;
519 dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); 515 dev_dbg(&dev->pdev->dev, "slots to read = %08x\n", slots);
520 dev_dbg(&dev->pdev->dev, "call mei_irq_read_handler.\n");
521 rets = mei_irq_read_handler(dev, &complete_list, &slots); 516 rets = mei_irq_read_handler(dev, &complete_list, &slots);
522 if (rets) 517 if (rets) {
518 schedule_work(&dev->reset_work);
523 goto end; 519 goto end;
520 }
524 } 521 }
522
525 rets = mei_irq_write_handler(dev, &complete_list); 523 rets = mei_irq_write_handler(dev, &complete_list);
526end:
527 dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
528 dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
529 524
530 mutex_unlock(&dev->device_lock); 525 dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
531 526
532 mei_irq_compl_handler(dev, &complete_list); 527 mei_irq_compl_handler(dev, &complete_list);
533 528
529end:
530 dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets);
531 mutex_unlock(&dev->device_lock);
534 return IRQ_HANDLED; 532 return IRQ_HANDLED;
535} 533}
536static const struct mei_hw_ops mei_me_hw_ops = { 534static const struct mei_hw_ops mei_me_hw_ops = {
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 83c879bf9967..87c077bae5d8 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -43,42 +43,6 @@ const char *mei_dev_state_str(int state)
43#undef MEI_DEV_STATE 43#undef MEI_DEV_STATE
44} 44}
45 45
46void mei_device_init(struct mei_device *dev)
47{
48 /* setup our list array */
49 INIT_LIST_HEAD(&dev->file_list);
50 INIT_LIST_HEAD(&dev->device_list);
51 mutex_init(&dev->device_lock);
52 init_waitqueue_head(&dev->wait_hw_ready);
53 init_waitqueue_head(&dev->wait_recvd_msg);
54 init_waitqueue_head(&dev->wait_stop_wd);
55 dev->dev_state = MEI_DEV_INITIALIZING;
56
57 mei_io_list_init(&dev->read_list);
58 mei_io_list_init(&dev->write_list);
59 mei_io_list_init(&dev->write_waiting_list);
60 mei_io_list_init(&dev->ctrl_wr_list);
61 mei_io_list_init(&dev->ctrl_rd_list);
62
63 INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
64 INIT_WORK(&dev->init_work, mei_host_client_init);
65
66 INIT_LIST_HEAD(&dev->wd_cl.link);
67 INIT_LIST_HEAD(&dev->iamthif_cl.link);
68 mei_io_list_init(&dev->amthif_cmd_list);
69 mei_io_list_init(&dev->amthif_rd_complete_list);
70
71 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
72 dev->open_handle_count = 0;
73
74 /*
75 * Reserving the first client ID
76 * 0: Reserved for MEI Bus Message communications
77 */
78 bitmap_set(dev->host_clients_map, 0, 1);
79}
80EXPORT_SYMBOL_GPL(mei_device_init);
81
82/** 46/**
83 * mei_start - initializes host and fw to start work. 47 * mei_start - initializes host and fw to start work.
84 * 48 *
@@ -131,10 +95,15 @@ err:
131} 95}
132EXPORT_SYMBOL_GPL(mei_start); 96EXPORT_SYMBOL_GPL(mei_start);
133 97
134 98/**
99 * mei_cancel_work. Cancel mei background jobs
100 *
101 * @dev: the device structure
102 */
135void mei_cancel_work(struct mei_device *dev) 103void mei_cancel_work(struct mei_device *dev)
136{ 104{
137 cancel_work_sync(&dev->init_work); 105 cancel_work_sync(&dev->init_work);
106 cancel_work_sync(&dev->reset_work);
138 107
139 cancel_delayed_work(&dev->timer_work); 108 cancel_delayed_work(&dev->timer_work);
140} 109}
@@ -215,11 +184,27 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
215 184
216 dev->dev_state = MEI_DEV_INIT_CLIENTS; 185 dev->dev_state = MEI_DEV_INIT_CLIENTS;
217 186
218 mei_hbm_start_req(dev); 187 ret = mei_hbm_start_req(dev);
219 188 if (ret) {
189 dev_err(&dev->pdev->dev, "hbm_start failed disabling the device\n");
190 dev->dev_state = MEI_DEV_DISABLED;
191 return;
192 }
220} 193}
221EXPORT_SYMBOL_GPL(mei_reset); 194EXPORT_SYMBOL_GPL(mei_reset);
222 195
196static void mei_reset_work(struct work_struct *work)
197{
198 struct mei_device *dev =
199 container_of(work, struct mei_device, reset_work);
200
201 mutex_lock(&dev->device_lock);
202
203 mei_reset(dev, true);
204
205 mutex_unlock(&dev->device_lock);
206}
207
223void mei_stop(struct mei_device *dev) 208void mei_stop(struct mei_device *dev)
224{ 209{
225 dev_dbg(&dev->pdev->dev, "stopping the device.\n"); 210 dev_dbg(&dev->pdev->dev, "stopping the device.\n");
@@ -243,3 +228,40 @@ EXPORT_SYMBOL_GPL(mei_stop);
243 228
244 229
245 230
231void mei_device_init(struct mei_device *dev)
232{
233 /* setup our list array */
234 INIT_LIST_HEAD(&dev->file_list);
235 INIT_LIST_HEAD(&dev->device_list);
236 mutex_init(&dev->device_lock);
237 init_waitqueue_head(&dev->wait_hw_ready);
238 init_waitqueue_head(&dev->wait_recvd_msg);
239 init_waitqueue_head(&dev->wait_stop_wd);
240 dev->dev_state = MEI_DEV_INITIALIZING;
241
242 mei_io_list_init(&dev->read_list);
243 mei_io_list_init(&dev->write_list);
244 mei_io_list_init(&dev->write_waiting_list);
245 mei_io_list_init(&dev->ctrl_wr_list);
246 mei_io_list_init(&dev->ctrl_rd_list);
247
248 INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
249 INIT_WORK(&dev->init_work, mei_host_client_init);
250 INIT_WORK(&dev->reset_work, mei_reset_work);
251
252 INIT_LIST_HEAD(&dev->wd_cl.link);
253 INIT_LIST_HEAD(&dev->iamthif_cl.link);
254 mei_io_list_init(&dev->amthif_cmd_list);
255 mei_io_list_init(&dev->amthif_rd_complete_list);
256
257 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
258 dev->open_handle_count = 0;
259
260 /*
261 * Reserving the first client ID
262 * 0: Reserved for MEI Bus Message communications
263 */
264 bitmap_set(dev->host_clients_map, 0, 1);
265}
266EXPORT_SYMBOL_GPL(mei_device_init);
267
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 9c8225b945c3..bbb61bec863b 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -329,9 +329,12 @@ int mei_irq_read_handler(struct mei_device *dev,
329 329
330 /* HBM message */ 330 /* HBM message */
331 if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) { 331 if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) {
332 mei_hbm_dispatch(dev, mei_hdr); 332 ret = mei_hbm_dispatch(dev, mei_hdr);
333 ret = 0; 333 if (ret) {
334 dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch.\n"); 334 dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n",
335 ret);
336 goto end;
337 }
335 goto reset_slots; 338 goto reset_slots;
336 } 339 }
337 340
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d92ca0c93f7f..3f242e15f8f1 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -428,6 +428,7 @@ struct mei_device {
428 bool iamthif_canceled; 428 bool iamthif_canceled;
429 429
430 struct work_struct init_work; 430 struct work_struct init_work;
431 struct work_struct reset_work;
431 432
432 /* List of bus devices */ 433 /* List of bus devices */
433 struct list_head device_list; 434 struct list_head device_list;