diff options
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/hbm.c | 200 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.h | 6 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 32 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 100 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 9 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 1 |
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 | */ |
33 | static void mei_hbm_me_cl_allocate(struct mei_device *dev) | 33 | static 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 | */ |
157 | int mei_hbm_start_req(struct mei_device *dev) | 157 | int 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 | */ |
191 | static void mei_hbm_enum_clients_req(struct mei_device *dev) | 193 | static 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 | ||
221 | static int mei_hbm_prop_req(struct mei_device *dev) | 226 | static 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 | */ |
563 | void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | 569 | int 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; | |||
32 | enum mei_hbm_state { | 32 | enum 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 | ||
41 | void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); | 41 | int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr); |
42 | 42 | ||
43 | static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) | 43 | static 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); |
526 | end: | ||
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 | ||
529 | end: | ||
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 | } |
536 | static const struct mei_hw_ops mei_me_hw_ops = { | 534 | static 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 | ||
46 | void 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 | } | ||
80 | EXPORT_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 | } |
132 | EXPORT_SYMBOL_GPL(mei_start); | 96 | EXPORT_SYMBOL_GPL(mei_start); |
133 | 97 | ||
134 | 98 | /** | |
99 | * mei_cancel_work. Cancel mei background jobs | ||
100 | * | ||
101 | * @dev: the device structure | ||
102 | */ | ||
135 | void mei_cancel_work(struct mei_device *dev) | 103 | void 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 | } |
221 | EXPORT_SYMBOL_GPL(mei_reset); | 194 | EXPORT_SYMBOL_GPL(mei_reset); |
222 | 195 | ||
196 | static 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 | |||
223 | void mei_stop(struct mei_device *dev) | 208 | void 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 | ||
231 | void 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 | } | ||
266 | EXPORT_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; |