]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/misc/mei/init.c
mei: do not run reset flow from the interrupt thread
[mirror_ubuntu-zesty-kernel.git] / drivers / misc / mei / init.c
CommitLineData
91f01c6d
OW
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
733ba91c 4 * Copyright (c) 2003-2012, Intel Corporation.
91f01c6d
OW
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
40e0b67b 17#include <linux/export.h>
91f01c6d
OW
18#include <linux/pci.h>
19#include <linux/sched.h>
20#include <linux/wait.h>
21#include <linux/delay.h>
22
47a73801
TW
23#include <linux/mei.h>
24
91f01c6d 25#include "mei_dev.h"
aafae7ec 26#include "hbm.h"
90e0b5f1 27#include "client.h"
91f01c6d 28
b210d750
TW
29const char *mei_dev_state_str(int state)
30{
31#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
32 switch (state) {
33 MEI_DEV_STATE(INITIALIZING);
34 MEI_DEV_STATE(INIT_CLIENTS);
35 MEI_DEV_STATE(ENABLED);
0cfee51c 36 MEI_DEV_STATE(RESETTING);
b210d750 37 MEI_DEV_STATE(DISABLED);
b210d750
TW
38 MEI_DEV_STATE(POWER_DOWN);
39 MEI_DEV_STATE(POWER_UP);
40 default:
8b513d0c 41 return "unknown";
b210d750
TW
42 }
43#undef MEI_DEV_STATE
44}
45
91f01c6d 46/**
c4d589be 47 * mei_start - initializes host and fw to start work.
91f01c6d
OW
48 *
49 * @dev: the device structure
50 *
51 * returns 0 on success, <0 on failure.
52 */
c4d589be 53int mei_start(struct mei_device *dev)
91f01c6d 54{
91f01c6d
OW
55 mutex_lock(&dev->device_lock);
56
91f01c6d 57 /* acknowledge interrupt and stop interupts */
3a65dd4e 58 mei_clear_interrupts(dev);
91f01c6d 59
e7e0c231 60 mei_hw_config(dev);
24aadc80 61
91f01c6d
OW
62 dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
63
64 mei_reset(dev, 1);
65
9b0d5efc
TW
66 if (mei_hbm_start_wait(dev)) {
67 dev_err(&dev->pdev->dev, "HBM haven't started");
e7e0c231 68 goto err;
91f01c6d
OW
69 }
70
e7e0c231
TW
71 if (!mei_host_is_ready(dev)) {
72 dev_err(&dev->pdev->dev, "host is not ready.\n");
73 goto err;
74 }
91f01c6d 75
827eef51 76 if (!mei_hw_is_ready(dev)) {
e7e0c231
TW
77 dev_err(&dev->pdev->dev, "ME is not ready.\n");
78 goto err;
91f01c6d
OW
79 }
80
2c9b48ac 81 if (!mei_hbm_version_is_supported(dev)) {
91f01c6d 82 dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
e7e0c231 83 goto err;
91f01c6d
OW
84 }
85
91f01c6d 86 dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
91f01c6d 87
91f01c6d 88 mutex_unlock(&dev->device_lock);
e7e0c231
TW
89 return 0;
90err:
91 dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
92 dev->dev_state = MEI_DEV_DISABLED;
93 mutex_unlock(&dev->device_lock);
94 return -ENODEV;
91f01c6d 95}
40e0b67b 96EXPORT_SYMBOL_GPL(mei_start);
91f01c6d 97
544f9460
TW
98/**
99 * mei_cancel_work. Cancel mei background jobs
100 *
101 * @dev: the device structure
102 */
dc844b0d
TW
103void mei_cancel_work(struct mei_device *dev)
104{
105 cancel_work_sync(&dev->init_work);
544f9460 106 cancel_work_sync(&dev->reset_work);
dc844b0d
TW
107
108 cancel_delayed_work(&dev->timer_work);
109}
110EXPORT_SYMBOL_GPL(mei_cancel_work);
111
91f01c6d
OW
112/**
113 * mei_reset - resets host and fw.
114 *
115 * @dev: the device structure
116 * @interrupts_enabled: if interrupt should be enabled after reset.
117 */
118void mei_reset(struct mei_device *dev, int interrupts_enabled)
119{
91f01c6d 120 bool unexpected;
c20c68d5 121 int ret;
91f01c6d 122
b210d750
TW
123 unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
124 dev->dev_state != MEI_DEV_DISABLED &&
125 dev->dev_state != MEI_DEV_POWER_DOWN &&
126 dev->dev_state != MEI_DEV_POWER_UP);
91f01c6d 127
f931f4f3
AU
128 if (unexpected)
129 dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
130 mei_dev_state_str(dev->dev_state));
131
c20c68d5
TW
132 ret = mei_hw_reset(dev, interrupts_enabled);
133 if (ret) {
134 dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n");
135 interrupts_enabled = false;
136 dev->dev_state = MEI_DEV_DISABLED;
137 }
91f01c6d 138
9b0d5efc 139 dev->hbm_state = MEI_HBM_IDLE;
91f01c6d 140
99f22c4e
TW
141 if (dev->dev_state != MEI_DEV_INITIALIZING &&
142 dev->dev_state != MEI_DEV_POWER_UP) {
b210d750
TW
143 if (dev->dev_state != MEI_DEV_DISABLED &&
144 dev->dev_state != MEI_DEV_POWER_DOWN)
0cfee51c 145 dev->dev_state = MEI_DEV_RESETTING;
91f01c6d 146
b950ac1d
TW
147 /* remove all waiting requests */
148 mei_cl_all_write_clear(dev);
149
074b4c01
TW
150 mei_cl_all_disconnect(dev);
151
b950ac1d
TW
152 /* wake up all readings so they can be interrupted */
153 mei_cl_all_wakeup(dev);
154
91f01c6d 155 /* remove entry if already in list */
ff8b2f4e 156 dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
90e0b5f1
TW
157 mei_cl_unlink(&dev->wd_cl);
158 mei_cl_unlink(&dev->iamthif_cl);
19838fb8 159 mei_amthif_reset_params(dev);
5fb54fb4 160 memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg));
91f01c6d
OW
161 }
162
4a704575
AU
163 /* we're already in reset, cancel the init timer */
164 dev->init_clients_timer = 0;
165
cf9673da 166 dev->me_clients_num = 0;
91f01c6d 167 dev->rd_msg_hdr = 0;
eb9af0ac 168 dev->wd_pending = false;
91f01c6d 169
aafae7ec
TW
170 if (!interrupts_enabled) {
171 dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
172 return;
173 }
174
9049f793
TW
175 ret = mei_hw_start(dev);
176 if (ret) {
177 dev_err(&dev->pdev->dev, "hw_start failed disabling the device\n");
178 dev->dev_state = MEI_DEV_DISABLED;
179 return;
180 }
aafae7ec
TW
181
182 dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
183 /* link is established * start sending messages. */
184
185 dev->dev_state = MEI_DEV_INIT_CLIENTS;
186
544f9460
TW
187 ret = mei_hbm_start_req(dev);
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 }
91f01c6d 193}
40e0b67b 194EXPORT_SYMBOL_GPL(mei_reset);
91f01c6d 195
544f9460
TW
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
7cb035d9
TW
208void mei_stop(struct mei_device *dev)
209{
210 dev_dbg(&dev->pdev->dev, "stopping the device.\n");
211
dc844b0d 212 mei_cancel_work(dev);
5e85b364 213
dc844b0d 214 mei_nfc_host_exit(dev);
7cb035d9 215
dc844b0d 216 mutex_lock(&dev->device_lock);
7cb035d9
TW
217
218 mei_wd_stop(dev);
219
220 dev->dev_state = MEI_DEV_POWER_DOWN;
221 mei_reset(dev, 0);
222
223 mutex_unlock(&dev->device_lock);
224
2e647124 225 mei_watchdog_unregister(dev);
7cb035d9 226}
40e0b67b 227EXPORT_SYMBOL_GPL(mei_stop);
91f01c6d 228
c1174c0e 229
91f01c6d 230
544f9460
TW
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