aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2014-01-08 13:19:21 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-08 18:25:15 -0500
commit544f94601409653f07ae6e22d4a39e3a90dceead (patch)
tree0939fcf8facae8633eebe3fd40b4f4f00788d76e /drivers/misc
parent634608f27acd098b245ca6fe60e06701185eb170 (diff)
mei: do not run reset flow from the interrupt thread
This fixes a potential deadlock in case of a firmware initiated reset mei_reset has a dialog with the interrupt thread hence it has to be run from an another work item Most of the mei_resets were called from mei_hbm_dispatch which is called in interrupt thread context so this function underwent major revamp. The error code is propagated to the interrupt thread and if needed the reset is scheduled from there. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-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;