aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/hbm.c
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/mei/hbm.c
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/mei/hbm.c')
-rw-r--r--drivers/misc/mei/hbm.c200
1 files changed, 124 insertions, 76 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