diff options
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/amthif.c | 6 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 27 | ||||
-rw-r--r-- | drivers/misc/mei/debugfs.c | 4 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 239 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.h | 7 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 40 | ||||
-rw-r--r-- | drivers/misc/mei/hw.h | 3 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 278 | ||||
-rw-r--r-- | drivers/misc/mei/interrupt.c | 122 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 33 | ||||
-rw-r--r-- | drivers/misc/mei/nfc.c | 20 | ||||
-rw-r--r-- | drivers/misc/mei/pci-me.c | 27 | ||||
-rw-r--r-- | drivers/misc/mei/wd.c | 1 |
14 files changed, 506 insertions, 303 deletions
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index d22c6864508b..2fad84432829 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -177,7 +177,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, | |||
177 | unsigned long timeout; | 177 | unsigned long timeout; |
178 | int i; | 178 | int i; |
179 | 179 | ||
180 | /* Only Posible if we are in timeout */ | 180 | /* Only possible if we are in timeout */ |
181 | if (!cl || cl != &dev->iamthif_cl) { | 181 | if (!cl || cl != &dev->iamthif_cl) { |
182 | dev_dbg(&dev->pdev->dev, "bad file ext.\n"); | 182 | dev_dbg(&dev->pdev->dev, "bad file ext.\n"); |
183 | return -ETIMEDOUT; | 183 | return -ETIMEDOUT; |
@@ -249,7 +249,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, | |||
249 | cb->response_buffer.size); | 249 | cb->response_buffer.size); |
250 | dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); | 250 | dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); |
251 | 251 | ||
252 | /* length is being turncated to PAGE_SIZE, however, | 252 | /* length is being truncated to PAGE_SIZE, however, |
253 | * the buf_idx may point beyond */ | 253 | * the buf_idx may point beyond */ |
254 | length = min_t(size_t, length, (cb->buf_idx - *offset)); | 254 | length = min_t(size_t, length, (cb->buf_idx - *offset)); |
255 | 255 | ||
@@ -316,6 +316,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) | |||
316 | mei_hdr.host_addr = dev->iamthif_cl.host_client_id; | 316 | mei_hdr.host_addr = dev->iamthif_cl.host_client_id; |
317 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; | 317 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; |
318 | mei_hdr.reserved = 0; | 318 | mei_hdr.reserved = 0; |
319 | mei_hdr.internal = 0; | ||
319 | dev->iamthif_msg_buf_index += mei_hdr.length; | 320 | dev->iamthif_msg_buf_index += mei_hdr.length; |
320 | ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); | 321 | ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); |
321 | if (ret) | 322 | if (ret) |
@@ -477,6 +478,7 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
477 | mei_hdr.host_addr = cl->host_client_id; | 478 | mei_hdr.host_addr = cl->host_client_id; |
478 | mei_hdr.me_addr = cl->me_client_id; | 479 | mei_hdr.me_addr = cl->me_client_id; |
479 | mei_hdr.reserved = 0; | 480 | mei_hdr.reserved = 0; |
481 | mei_hdr.internal = 0; | ||
480 | 482 | ||
481 | if (*slots >= msg_slots) { | 483 | if (*slots >= msg_slots) { |
482 | mei_hdr.length = len; | 484 | mei_hdr.length = len; |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 87c96e4669e2..1ee2b9492a82 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -154,7 +154,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) | |||
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | /** | 156 | /** |
157 | * mei_io_cb_alloc_resp_buf - allocate respose buffer | 157 | * mei_io_cb_alloc_resp_buf - allocate response buffer |
158 | * | 158 | * |
159 | * @cb: io callback structure | 159 | * @cb: io callback structure |
160 | * @length: size of the buffer | 160 | * @length: size of the buffer |
@@ -207,7 +207,7 @@ int mei_cl_flush_queues(struct mei_cl *cl) | |||
207 | 207 | ||
208 | 208 | ||
209 | /** | 209 | /** |
210 | * mei_cl_init - initializes intialize cl. | 210 | * mei_cl_init - initializes cl. |
211 | * | 211 | * |
212 | * @cl: host client to be initialized | 212 | * @cl: host client to be initialized |
213 | * @dev: mei device | 213 | * @dev: mei device |
@@ -263,10 +263,10 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) | |||
263 | return NULL; | 263 | return NULL; |
264 | } | 264 | } |
265 | 265 | ||
266 | /** mei_cl_link: allocte host id in the host map | 266 | /** mei_cl_link: allocate host id in the host map |
267 | * | 267 | * |
268 | * @cl - host client | 268 | * @cl - host client |
269 | * @id - fixed host id or -1 for genereting one | 269 | * @id - fixed host id or -1 for generic one |
270 | * | 270 | * |
271 | * returns 0 on success | 271 | * returns 0 on success |
272 | * -EINVAL on incorrect values | 272 | * -EINVAL on incorrect values |
@@ -282,19 +282,19 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
282 | 282 | ||
283 | dev = cl->dev; | 283 | dev = cl->dev; |
284 | 284 | ||
285 | /* If Id is not asigned get one*/ | 285 | /* If Id is not assigned get one*/ |
286 | if (id == MEI_HOST_CLIENT_ID_ANY) | 286 | if (id == MEI_HOST_CLIENT_ID_ANY) |
287 | id = find_first_zero_bit(dev->host_clients_map, | 287 | id = find_first_zero_bit(dev->host_clients_map, |
288 | MEI_CLIENTS_MAX); | 288 | MEI_CLIENTS_MAX); |
289 | 289 | ||
290 | if (id >= MEI_CLIENTS_MAX) { | 290 | if (id >= MEI_CLIENTS_MAX) { |
291 | dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; | 291 | dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX); |
292 | return -EMFILE; | 292 | return -EMFILE; |
293 | } | 293 | } |
294 | 294 | ||
295 | open_handle_count = dev->open_handle_count + dev->iamthif_open_count; | 295 | open_handle_count = dev->open_handle_count + dev->iamthif_open_count; |
296 | if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | 296 | if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { |
297 | dev_err(&dev->pdev->dev, "open_handle_count exceded %d", | 297 | dev_err(&dev->pdev->dev, "open_handle_count exceeded %d", |
298 | MEI_MAX_OPEN_HANDLE_COUNT); | 298 | MEI_MAX_OPEN_HANDLE_COUNT); |
299 | return -EMFILE; | 299 | return -EMFILE; |
300 | } | 300 | } |
@@ -344,8 +344,6 @@ int mei_cl_unlink(struct mei_cl *cl) | |||
344 | 344 | ||
345 | cl->state = MEI_FILE_INITIALIZING; | 345 | cl->state = MEI_FILE_INITIALIZING; |
346 | 346 | ||
347 | list_del_init(&cl->link); | ||
348 | |||
349 | return 0; | 347 | return 0; |
350 | } | 348 | } |
351 | 349 | ||
@@ -372,13 +370,14 @@ void mei_host_client_init(struct work_struct *work) | |||
372 | } | 370 | } |
373 | 371 | ||
374 | dev->dev_state = MEI_DEV_ENABLED; | 372 | dev->dev_state = MEI_DEV_ENABLED; |
373 | dev->reset_count = 0; | ||
375 | 374 | ||
376 | mutex_unlock(&dev->device_lock); | 375 | mutex_unlock(&dev->device_lock); |
377 | } | 376 | } |
378 | 377 | ||
379 | 378 | ||
380 | /** | 379 | /** |
381 | * mei_cl_disconnect - disconnect host clinet form the me one | 380 | * mei_cl_disconnect - disconnect host client from the me one |
382 | * | 381 | * |
383 | * @cl: host client | 382 | * @cl: host client |
384 | * | 383 | * |
@@ -457,7 +456,7 @@ free: | |||
457 | * | 456 | * |
458 | * @cl: private data of the file object | 457 | * @cl: private data of the file object |
459 | * | 458 | * |
460 | * returns ture if other client is connected, 0 - otherwise. | 459 | * returns true if other client is connected, false - otherwise. |
461 | */ | 460 | */ |
462 | bool mei_cl_is_other_connecting(struct mei_cl *cl) | 461 | bool mei_cl_is_other_connecting(struct mei_cl *cl) |
463 | { | 462 | { |
@@ -481,7 +480,7 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl) | |||
481 | } | 480 | } |
482 | 481 | ||
483 | /** | 482 | /** |
484 | * mei_cl_connect - connect host clinet to the me one | 483 | * mei_cl_connect - connect host client to the me one |
485 | * | 484 | * |
486 | * @cl: host client | 485 | * @cl: host client |
487 | * | 486 | * |
@@ -729,6 +728,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
729 | mei_hdr.host_addr = cl->host_client_id; | 728 | mei_hdr.host_addr = cl->host_client_id; |
730 | mei_hdr.me_addr = cl->me_client_id; | 729 | mei_hdr.me_addr = cl->me_client_id; |
731 | mei_hdr.reserved = 0; | 730 | mei_hdr.reserved = 0; |
731 | mei_hdr.internal = cb->internal; | ||
732 | 732 | ||
733 | if (*slots >= msg_slots) { | 733 | if (*slots >= msg_slots) { |
734 | mei_hdr.length = len; | 734 | mei_hdr.length = len; |
@@ -775,7 +775,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
775 | * @cl: host client | 775 | * @cl: host client |
776 | * @cl: write callback with filled data | 776 | * @cl: write callback with filled data |
777 | * | 777 | * |
778 | * returns numbe of bytes sent on success, <0 on failure. | 778 | * returns number of bytes sent on success, <0 on failure. |
779 | */ | 779 | */ |
780 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | 780 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) |
781 | { | 781 | { |
@@ -828,6 +828,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
828 | mei_hdr.host_addr = cl->host_client_id; | 828 | mei_hdr.host_addr = cl->host_client_id; |
829 | mei_hdr.me_addr = cl->me_client_id; | 829 | mei_hdr.me_addr = cl->me_client_id; |
830 | mei_hdr.reserved = 0; | 830 | mei_hdr.reserved = 0; |
831 | mei_hdr.internal = cb->internal; | ||
831 | 832 | ||
832 | 833 | ||
833 | rets = mei_write_message(dev, &mei_hdr, buf->data); | 834 | rets = mei_write_message(dev, &mei_hdr, buf->data); |
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index e3870f22d238..a3ae154444b2 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c | |||
@@ -43,7 +43,7 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, | |||
43 | 43 | ||
44 | mutex_lock(&dev->device_lock); | 44 | mutex_lock(&dev->device_lock); |
45 | 45 | ||
46 | /* if the driver is not enabled the list won't b consitent */ | 46 | /* if the driver is not enabled the list won't be consistent */ |
47 | if (dev->dev_state != MEI_DEV_ENABLED) | 47 | if (dev->dev_state != MEI_DEV_ENABLED) |
48 | goto out; | 48 | goto out; |
49 | 49 | ||
@@ -101,7 +101,7 @@ static const struct file_operations mei_dbgfs_fops_devstate = { | |||
101 | 101 | ||
102 | /** | 102 | /** |
103 | * mei_dbgfs_deregister - Remove the debugfs files and directories | 103 | * mei_dbgfs_deregister - Remove the debugfs files and directories |
104 | * @mei - pointer to mei device private dat | 104 | * @mei - pointer to mei device private data |
105 | */ | 105 | */ |
106 | void mei_dbgfs_deregister(struct mei_device *dev) | 106 | void mei_dbgfs_deregister(struct mei_device *dev) |
107 | { | 107 | { |
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 9b3a0fb7f265..28cd74c073b9 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 | /** |
@@ -85,12 +83,12 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len) | |||
85 | } | 83 | } |
86 | 84 | ||
87 | /** | 85 | /** |
88 | * same_disconn_addr - tells if they have the same address | 86 | * mei_hbm_cl_addr_equal - tells if they have the same address |
89 | * | 87 | * |
90 | * @file: private data of the file object. | 88 | * @cl: - client |
91 | * @disconn: disconnection request. | 89 | * @buf: buffer with cl header |
92 | * | 90 | * |
93 | * returns true if addres are same | 91 | * returns true if addresses are the same |
94 | */ | 92 | */ |
95 | static inline | 93 | static inline |
96 | bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) | 94 | bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) |
@@ -128,6 +126,17 @@ static bool is_treat_specially_client(struct mei_cl *cl, | |||
128 | return false; | 126 | return false; |
129 | } | 127 | } |
130 | 128 | ||
129 | /** | ||
130 | * mei_hbm_idle - set hbm to idle state | ||
131 | * | ||
132 | * @dev: the device structure | ||
133 | */ | ||
134 | void mei_hbm_idle(struct mei_device *dev) | ||
135 | { | ||
136 | dev->init_clients_timer = 0; | ||
137 | dev->hbm_state = MEI_HBM_IDLE; | ||
138 | } | ||
139 | |||
131 | int mei_hbm_start_wait(struct mei_device *dev) | 140 | int mei_hbm_start_wait(struct mei_device *dev) |
132 | { | 141 | { |
133 | int ret; | 142 | int ret; |
@@ -137,7 +146,7 @@ int mei_hbm_start_wait(struct mei_device *dev) | |||
137 | mutex_unlock(&dev->device_lock); | 146 | mutex_unlock(&dev->device_lock); |
138 | ret = wait_event_interruptible_timeout(dev->wait_recvd_msg, | 147 | ret = wait_event_interruptible_timeout(dev->wait_recvd_msg, |
139 | dev->hbm_state == MEI_HBM_IDLE || | 148 | dev->hbm_state == MEI_HBM_IDLE || |
140 | dev->hbm_state > MEI_HBM_START, | 149 | dev->hbm_state >= MEI_HBM_STARTED, |
141 | mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); | 150 | mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); |
142 | mutex_lock(&dev->device_lock); | 151 | mutex_lock(&dev->device_lock); |
143 | 152 | ||
@@ -153,12 +162,15 @@ int mei_hbm_start_wait(struct mei_device *dev) | |||
153 | * mei_hbm_start_req - sends start request message. | 162 | * mei_hbm_start_req - sends start request message. |
154 | * | 163 | * |
155 | * @dev: the device structure | 164 | * @dev: the device structure |
165 | * | ||
166 | * returns 0 on success and < 0 on failure | ||
156 | */ | 167 | */ |
157 | int mei_hbm_start_req(struct mei_device *dev) | 168 | int mei_hbm_start_req(struct mei_device *dev) |
158 | { | 169 | { |
159 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; | 170 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
160 | struct hbm_host_version_request *start_req; | 171 | struct hbm_host_version_request *start_req; |
161 | const size_t len = sizeof(struct hbm_host_version_request); | 172 | const size_t len = sizeof(struct hbm_host_version_request); |
173 | int ret; | ||
162 | 174 | ||
163 | mei_hbm_hdr(mei_hdr, len); | 175 | mei_hbm_hdr(mei_hdr, len); |
164 | 176 | ||
@@ -170,12 +182,13 @@ int mei_hbm_start_req(struct mei_device *dev) | |||
170 | start_req->host_version.minor_version = HBM_MINOR_VERSION; | 182 | start_req->host_version.minor_version = HBM_MINOR_VERSION; |
171 | 183 | ||
172 | dev->hbm_state = MEI_HBM_IDLE; | 184 | dev->hbm_state = MEI_HBM_IDLE; |
173 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { | 185 | ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
174 | dev_err(&dev->pdev->dev, "version message write failed\n"); | 186 | if (ret) { |
175 | dev->dev_state = MEI_DEV_RESETTING; | 187 | dev_err(&dev->pdev->dev, "version message write failed: ret = %d\n", |
176 | mei_reset(dev, 1); | 188 | ret); |
177 | return -EIO; | 189 | return ret; |
178 | } | 190 | } |
191 | |||
179 | dev->hbm_state = MEI_HBM_START; | 192 | dev->hbm_state = MEI_HBM_START; |
180 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 193 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
181 | return 0; | 194 | return 0; |
@@ -186,13 +199,15 @@ int mei_hbm_start_req(struct mei_device *dev) | |||
186 | * | 199 | * |
187 | * @dev: the device structure | 200 | * @dev: the device structure |
188 | * | 201 | * |
189 | * returns none. | 202 | * returns 0 on success and < 0 on failure |
190 | */ | 203 | */ |
191 | static void mei_hbm_enum_clients_req(struct mei_device *dev) | 204 | static int mei_hbm_enum_clients_req(struct mei_device *dev) |
192 | { | 205 | { |
193 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; | 206 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; |
194 | struct hbm_host_enum_request *enum_req; | 207 | struct hbm_host_enum_request *enum_req; |
195 | const size_t len = sizeof(struct hbm_host_enum_request); | 208 | const size_t len = sizeof(struct hbm_host_enum_request); |
209 | int ret; | ||
210 | |||
196 | /* enumerate clients */ | 211 | /* enumerate clients */ |
197 | mei_hbm_hdr(mei_hdr, len); | 212 | mei_hbm_hdr(mei_hdr, len); |
198 | 213 | ||
@@ -200,14 +215,15 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev) | |||
200 | memset(enum_req, 0, len); | 215 | memset(enum_req, 0, len); |
201 | enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; | 216 | enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; |
202 | 217 | ||
203 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { | 218 | ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
204 | dev->dev_state = MEI_DEV_RESETTING; | 219 | if (ret) { |
205 | dev_err(&dev->pdev->dev, "enumeration request write failed.\n"); | 220 | dev_err(&dev->pdev->dev, "enumeration request write failed: ret = %d.\n", |
206 | mei_reset(dev, 1); | 221 | ret); |
222 | return ret; | ||
207 | } | 223 | } |
208 | dev->hbm_state = MEI_HBM_ENUM_CLIENTS; | 224 | dev->hbm_state = MEI_HBM_ENUM_CLIENTS; |
209 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 225 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
210 | return; | 226 | return 0; |
211 | } | 227 | } |
212 | 228 | ||
213 | /** | 229 | /** |
@@ -215,7 +231,7 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev) | |||
215 | * | 231 | * |
216 | * @dev: the device structure | 232 | * @dev: the device structure |
217 | * | 233 | * |
218 | * returns none. | 234 | * returns 0 on success and < 0 on failure |
219 | */ | 235 | */ |
220 | 236 | ||
221 | static int mei_hbm_prop_req(struct mei_device *dev) | 237 | static int mei_hbm_prop_req(struct mei_device *dev) |
@@ -226,7 +242,7 @@ static int mei_hbm_prop_req(struct mei_device *dev) | |||
226 | const size_t len = sizeof(struct hbm_props_request); | 242 | const size_t len = sizeof(struct hbm_props_request); |
227 | unsigned long next_client_index; | 243 | unsigned long next_client_index; |
228 | unsigned long client_num; | 244 | unsigned long client_num; |
229 | 245 | int ret; | |
230 | 246 | ||
231 | client_num = dev->me_client_presentation_num; | 247 | client_num = dev->me_client_presentation_num; |
232 | 248 | ||
@@ -253,12 +269,11 @@ static int mei_hbm_prop_req(struct mei_device *dev) | |||
253 | prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; | 269 | prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; |
254 | prop_req->address = next_client_index; | 270 | prop_req->address = next_client_index; |
255 | 271 | ||
256 | if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) { | 272 | ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); |
257 | dev->dev_state = MEI_DEV_RESETTING; | 273 | if (ret) { |
258 | dev_err(&dev->pdev->dev, "properties request write failed\n"); | 274 | dev_err(&dev->pdev->dev, "properties request write failed: ret = %d\n", |
259 | mei_reset(dev, 1); | 275 | ret); |
260 | 276 | return ret; | |
261 | return -EIO; | ||
262 | } | 277 | } |
263 | 278 | ||
264 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 279 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
@@ -268,7 +283,7 @@ static int mei_hbm_prop_req(struct mei_device *dev) | |||
268 | } | 283 | } |
269 | 284 | ||
270 | /** | 285 | /** |
271 | * mei_hbm_stop_req_prepare - perpare stop request message | 286 | * mei_hbm_stop_req_prepare - prepare stop request message |
272 | * | 287 | * |
273 | * @dev - mei device | 288 | * @dev - mei device |
274 | * @mei_hdr - mei message header | 289 | * @mei_hdr - mei message header |
@@ -289,7 +304,7 @@ static void mei_hbm_stop_req_prepare(struct mei_device *dev, | |||
289 | } | 304 | } |
290 | 305 | ||
291 | /** | 306 | /** |
292 | * mei_hbm_cl_flow_control_req - sends flow control requst. | 307 | * mei_hbm_cl_flow_control_req - sends flow control request. |
293 | * | 308 | * |
294 | * @dev: the device structure | 309 | * @dev: the device structure |
295 | * @cl: client info | 310 | * @cl: client info |
@@ -451,7 +466,7 @@ int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl) | |||
451 | } | 466 | } |
452 | 467 | ||
453 | /** | 468 | /** |
454 | * mei_hbm_cl_connect_res - connect resposne from the ME | 469 | * mei_hbm_cl_connect_res - connect response from the ME |
455 | * | 470 | * |
456 | * @dev: the device structure | 471 | * @dev: the device structure |
457 | * @rs: connect response bus message | 472 | * @rs: connect response bus message |
@@ -505,8 +520,8 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, | |||
505 | 520 | ||
506 | 521 | ||
507 | /** | 522 | /** |
508 | * mei_hbm_fw_disconnect_req - disconnect request initiated by me | 523 | * mei_hbm_fw_disconnect_req - disconnect request initiated by ME firmware |
509 | * host sends disoconnect response | 524 | * host sends disconnect response |
510 | * | 525 | * |
511 | * @dev: the device structure. | 526 | * @dev: the device structure. |
512 | * @disconnect_req: disconnect request bus message from the me | 527 | * @disconnect_req: disconnect request bus message from the me |
@@ -559,8 +574,10 @@ bool mei_hbm_version_is_supported(struct mei_device *dev) | |||
559 | * | 574 | * |
560 | * @dev: the device structure | 575 | * @dev: the device structure |
561 | * @mei_hdr: header of bus message | 576 | * @mei_hdr: header of bus message |
577 | * | ||
578 | * returns 0 on success and < 0 on failure | ||
562 | */ | 579 | */ |
563 | void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | 580 | int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) |
564 | { | 581 | { |
565 | struct mei_bus_message *mei_msg; | 582 | struct mei_bus_message *mei_msg; |
566 | struct mei_me_client *me_client; | 583 | struct mei_me_client *me_client; |
@@ -577,8 +594,20 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
577 | mei_read_slots(dev, dev->rd_msg_buf, hdr->length); | 594 | mei_read_slots(dev, dev->rd_msg_buf, hdr->length); |
578 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; | 595 | mei_msg = (struct mei_bus_message *)dev->rd_msg_buf; |
579 | 596 | ||
597 | /* ignore spurious message and prevent reset nesting | ||
598 | * hbm is put to idle during system reset | ||
599 | */ | ||
600 | if (dev->hbm_state == MEI_HBM_IDLE) { | ||
601 | dev_dbg(&dev->pdev->dev, "hbm: state is idle ignore spurious messages\n"); | ||
602 | return 0; | ||
603 | } | ||
604 | |||
580 | switch (mei_msg->hbm_cmd) { | 605 | switch (mei_msg->hbm_cmd) { |
581 | case HOST_START_RES_CMD: | 606 | case HOST_START_RES_CMD: |
607 | dev_dbg(&dev->pdev->dev, "hbm: start: response message received.\n"); | ||
608 | |||
609 | dev->init_clients_timer = 0; | ||
610 | |||
582 | version_res = (struct hbm_host_version_response *)mei_msg; | 611 | version_res = (struct hbm_host_version_response *)mei_msg; |
583 | 612 | ||
584 | dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", | 613 | dev_dbg(&dev->pdev->dev, "HBM VERSION: DRIVER=%02d:%02d DEVICE=%02d:%02d\n", |
@@ -597,73 +626,89 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
597 | } | 626 | } |
598 | 627 | ||
599 | if (!mei_hbm_version_is_supported(dev)) { | 628 | if (!mei_hbm_version_is_supported(dev)) { |
600 | dev_warn(&dev->pdev->dev, "hbm version mismatch: stopping the driver.\n"); | 629 | dev_warn(&dev->pdev->dev, "hbm: start: version mismatch - stopping the driver.\n"); |
601 | 630 | ||
602 | dev->hbm_state = MEI_HBM_STOP; | 631 | dev->hbm_state = MEI_HBM_STOPPED; |
603 | mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, | 632 | mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr, |
604 | dev->wr_msg.data); | 633 | dev->wr_msg.data); |
605 | mei_write_message(dev, &dev->wr_msg.hdr, | 634 | if (mei_write_message(dev, &dev->wr_msg.hdr, |
606 | dev->wr_msg.data); | 635 | dev->wr_msg.data)) { |
636 | dev_err(&dev->pdev->dev, "hbm: start: failed to send stop request\n"); | ||
637 | return -EIO; | ||
638 | } | ||
639 | break; | ||
640 | } | ||
607 | 641 | ||
608 | return; | 642 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || |
643 | dev->hbm_state != MEI_HBM_START) { | ||
644 | dev_err(&dev->pdev->dev, "hbm: start: state mismatch, [%d, %d]\n", | ||
645 | dev->dev_state, dev->hbm_state); | ||
646 | return -EPROTO; | ||
609 | } | 647 | } |
610 | 648 | ||
611 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | 649 | dev->hbm_state = MEI_HBM_STARTED; |
612 | dev->hbm_state == MEI_HBM_START) { | 650 | |
613 | dev->init_clients_timer = 0; | 651 | if (mei_hbm_enum_clients_req(dev)) { |
614 | mei_hbm_enum_clients_req(dev); | 652 | dev_err(&dev->pdev->dev, "hbm: start: failed to send enumeration request\n"); |
615 | } else { | 653 | return -EIO; |
616 | dev_err(&dev->pdev->dev, "reset: wrong host start response\n"); | ||
617 | mei_reset(dev, 1); | ||
618 | return; | ||
619 | } | 654 | } |
620 | 655 | ||
621 | wake_up_interruptible(&dev->wait_recvd_msg); | 656 | wake_up_interruptible(&dev->wait_recvd_msg); |
622 | dev_dbg(&dev->pdev->dev, "host start response message received.\n"); | ||
623 | break; | 657 | break; |
624 | 658 | ||
625 | case CLIENT_CONNECT_RES_CMD: | 659 | case CLIENT_CONNECT_RES_CMD: |
660 | dev_dbg(&dev->pdev->dev, "hbm: client connect response: message received.\n"); | ||
661 | |||
626 | connect_res = (struct hbm_client_connect_response *) mei_msg; | 662 | connect_res = (struct hbm_client_connect_response *) mei_msg; |
627 | mei_hbm_cl_connect_res(dev, connect_res); | 663 | 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); | 664 | wake_up(&dev->wait_recvd_msg); |
630 | break; | 665 | break; |
631 | 666 | ||
632 | case CLIENT_DISCONNECT_RES_CMD: | 667 | case CLIENT_DISCONNECT_RES_CMD: |
668 | dev_dbg(&dev->pdev->dev, "hbm: client disconnect response: message received.\n"); | ||
669 | |||
633 | disconnect_res = (struct hbm_client_connect_response *) mei_msg; | 670 | disconnect_res = (struct hbm_client_connect_response *) mei_msg; |
634 | mei_hbm_cl_disconnect_res(dev, disconnect_res); | 671 | 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); | 672 | wake_up(&dev->wait_recvd_msg); |
637 | break; | 673 | break; |
638 | 674 | ||
639 | case MEI_FLOW_CONTROL_CMD: | 675 | case MEI_FLOW_CONTROL_CMD: |
676 | dev_dbg(&dev->pdev->dev, "hbm: client flow control response: message received.\n"); | ||
677 | |||
640 | flow_control = (struct hbm_flow_control *) mei_msg; | 678 | flow_control = (struct hbm_flow_control *) mei_msg; |
641 | mei_hbm_cl_flow_control_res(dev, flow_control); | 679 | mei_hbm_cl_flow_control_res(dev, flow_control); |
642 | dev_dbg(&dev->pdev->dev, "client flow control response message received.\n"); | ||
643 | break; | 680 | break; |
644 | 681 | ||
645 | case HOST_CLIENT_PROPERTIES_RES_CMD: | 682 | case HOST_CLIENT_PROPERTIES_RES_CMD: |
683 | dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n"); | ||
684 | |||
685 | dev->init_clients_timer = 0; | ||
686 | |||
687 | if (dev->me_clients == NULL) { | ||
688 | dev_err(&dev->pdev->dev, "hbm: properties response: mei_clients not allocated\n"); | ||
689 | return -EPROTO; | ||
690 | } | ||
691 | |||
646 | props_res = (struct hbm_props_response *)mei_msg; | 692 | props_res = (struct hbm_props_response *)mei_msg; |
647 | me_client = &dev->me_clients[dev->me_client_presentation_num]; | 693 | me_client = &dev->me_clients[dev->me_client_presentation_num]; |
648 | 694 | ||
649 | if (props_res->status || !dev->me_clients) { | 695 | if (props_res->status) { |
650 | dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n"); | 696 | dev_err(&dev->pdev->dev, "hbm: properties response: wrong status = %d\n", |
651 | mei_reset(dev, 1); | 697 | props_res->status); |
652 | return; | 698 | return -EPROTO; |
653 | } | 699 | } |
654 | 700 | ||
655 | if (me_client->client_id != props_res->address) { | 701 | if (me_client->client_id != props_res->address) { |
656 | dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n"); | 702 | dev_err(&dev->pdev->dev, "hbm: properties response: address mismatch %d ?= %d\n", |
657 | mei_reset(dev, 1); | 703 | me_client->client_id, props_res->address); |
658 | return; | 704 | return -EPROTO; |
659 | } | 705 | } |
660 | 706 | ||
661 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || | 707 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || |
662 | dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { | 708 | dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) { |
663 | dev_err(&dev->pdev->dev, "reset: unexpected properties response\n"); | 709 | dev_err(&dev->pdev->dev, "hbm: properties response: state mismatch, [%d, %d]\n", |
664 | mei_reset(dev, 1); | 710 | dev->dev_state, dev->hbm_state); |
665 | 711 | return -EPROTO; | |
666 | return; | ||
667 | } | 712 | } |
668 | 713 | ||
669 | me_client->props = props_res->client_properties; | 714 | me_client->props = props_res->client_properties; |
@@ -671,49 +716,70 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
671 | dev->me_client_presentation_num++; | 716 | dev->me_client_presentation_num++; |
672 | 717 | ||
673 | /* request property for the next client */ | 718 | /* request property for the next client */ |
674 | mei_hbm_prop_req(dev); | 719 | if (mei_hbm_prop_req(dev)) |
720 | return -EIO; | ||
675 | 721 | ||
676 | break; | 722 | break; |
677 | 723 | ||
678 | case HOST_ENUM_RES_CMD: | 724 | case HOST_ENUM_RES_CMD: |
725 | dev_dbg(&dev->pdev->dev, "hbm: enumeration response: message received\n"); | ||
726 | |||
727 | dev->init_clients_timer = 0; | ||
728 | |||
679 | enum_res = (struct hbm_host_enum_response *) mei_msg; | 729 | enum_res = (struct hbm_host_enum_response *) mei_msg; |
680 | BUILD_BUG_ON(sizeof(dev->me_clients_map) | 730 | BUILD_BUG_ON(sizeof(dev->me_clients_map) |
681 | < sizeof(enum_res->valid_addresses)); | 731 | < sizeof(enum_res->valid_addresses)); |
682 | memcpy(dev->me_clients_map, enum_res->valid_addresses, | 732 | memcpy(dev->me_clients_map, enum_res->valid_addresses, |
683 | sizeof(enum_res->valid_addresses)); | 733 | sizeof(enum_res->valid_addresses)); |
684 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | 734 | |
685 | dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { | 735 | if (dev->dev_state != MEI_DEV_INIT_CLIENTS || |
686 | dev->init_clients_timer = 0; | 736 | dev->hbm_state != MEI_HBM_ENUM_CLIENTS) { |
687 | mei_hbm_me_cl_allocate(dev); | 737 | dev_err(&dev->pdev->dev, "hbm: enumeration response: state mismatch, [%d, %d]\n", |
688 | dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; | 738 | dev->dev_state, dev->hbm_state); |
689 | 739 | return -EPROTO; | |
690 | /* first property reqeust */ | 740 | } |
691 | mei_hbm_prop_req(dev); | 741 | |
692 | } else { | 742 | if (mei_hbm_me_cl_allocate(dev)) { |
693 | dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n"); | 743 | dev_err(&dev->pdev->dev, "hbm: enumeration response: cannot allocate clients array\n"); |
694 | mei_reset(dev, 1); | 744 | return -ENOMEM; |
695 | return; | ||
696 | } | 745 | } |
746 | |||
747 | dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES; | ||
748 | |||
749 | /* first property request */ | ||
750 | if (mei_hbm_prop_req(dev)) | ||
751 | return -EIO; | ||
752 | |||
697 | break; | 753 | break; |
698 | 754 | ||
699 | case HOST_STOP_RES_CMD: | 755 | case HOST_STOP_RES_CMD: |
756 | dev_dbg(&dev->pdev->dev, "hbm: stop response: message received\n"); | ||
757 | |||
758 | dev->init_clients_timer = 0; | ||
700 | 759 | ||
701 | if (dev->hbm_state != MEI_HBM_STOP) | 760 | if (dev->hbm_state != MEI_HBM_STOPPED) { |
702 | dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n"); | 761 | dev_err(&dev->pdev->dev, "hbm: stop response: state mismatch, [%d, %d]\n", |
703 | dev->dev_state = MEI_DEV_DISABLED; | 762 | dev->dev_state, dev->hbm_state); |
704 | dev_info(&dev->pdev->dev, "reset: FW stop response.\n"); | 763 | return -EPROTO; |
705 | mei_reset(dev, 1); | 764 | } |
765 | |||
766 | dev->dev_state = MEI_DEV_POWER_DOWN; | ||
767 | dev_info(&dev->pdev->dev, "hbm: stop response: resetting.\n"); | ||
768 | /* force the reset */ | ||
769 | return -EPROTO; | ||
706 | break; | 770 | break; |
707 | 771 | ||
708 | case CLIENT_DISCONNECT_REQ_CMD: | 772 | case CLIENT_DISCONNECT_REQ_CMD: |
709 | /* search for client */ | 773 | dev_dbg(&dev->pdev->dev, "hbm: disconnect request: message received\n"); |
774 | |||
710 | disconnect_req = (struct hbm_client_connect_request *)mei_msg; | 775 | disconnect_req = (struct hbm_client_connect_request *)mei_msg; |
711 | mei_hbm_fw_disconnect_req(dev, disconnect_req); | 776 | mei_hbm_fw_disconnect_req(dev, disconnect_req); |
712 | break; | 777 | break; |
713 | 778 | ||
714 | case ME_STOP_REQ_CMD: | 779 | case ME_STOP_REQ_CMD: |
780 | dev_dbg(&dev->pdev->dev, "hbm: stop request: message received\n"); | ||
715 | 781 | ||
716 | dev->hbm_state = MEI_HBM_STOP; | 782 | dev->hbm_state = MEI_HBM_STOPPED; |
717 | mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, | 783 | mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr, |
718 | dev->wr_ext_msg.data); | 784 | dev->wr_ext_msg.data); |
719 | break; | 785 | break; |
@@ -722,5 +788,6 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
722 | break; | 788 | break; |
723 | 789 | ||
724 | } | 790 | } |
791 | return 0; | ||
725 | } | 792 | } |
726 | 793 | ||
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index 4ae2e56e404f..5f92188a5cd7 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 | { |
@@ -49,6 +49,7 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) | |||
49 | hdr->reserved = 0; | 49 | hdr->reserved = 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | void mei_hbm_idle(struct mei_device *dev); | ||
52 | int mei_hbm_start_req(struct mei_device *dev); | 53 | int mei_hbm_start_req(struct mei_device *dev); |
53 | int mei_hbm_start_wait(struct mei_device *dev); | 54 | int mei_hbm_start_wait(struct mei_device *dev); |
54 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); | 55 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); |
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 3412adcdaeb0..6f656c053b14 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
@@ -185,7 +185,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) | |||
185 | 185 | ||
186 | mei_me_reg_write(hw, H_CSR, hcsr); | 186 | mei_me_reg_write(hw, H_CSR, hcsr); |
187 | 187 | ||
188 | if (dev->dev_state == MEI_DEV_POWER_DOWN) | 188 | if (intr_enable == false) |
189 | mei_me_hw_reset_release(dev); | 189 | mei_me_hw_reset_release(dev); |
190 | 190 | ||
191 | return 0; | 191 | return 0; |
@@ -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 */ |
@@ -482,15 +482,10 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
482 | mei_clear_interrupts(dev); | 482 | mei_clear_interrupts(dev); |
483 | 483 | ||
484 | /* check if ME wants a reset */ | 484 | /* check if ME wants a reset */ |
485 | if (!mei_hw_is_ready(dev) && | 485 | if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { |
486 | dev->dev_state != MEI_DEV_RESETTING && | 486 | dev_warn(&dev->pdev->dev, "FW not ready: resetting.\n"); |
487 | dev->dev_state != MEI_DEV_INITIALIZING && | 487 | schedule_work(&dev->reset_work); |
488 | dev->dev_state != MEI_DEV_POWER_DOWN && | 488 | goto end; |
489 | dev->dev_state != MEI_DEV_POWER_UP) { | ||
490 | dev_dbg(&dev->pdev->dev, "FW not ready.\n"); | ||
491 | mei_reset(dev, 1); | ||
492 | mutex_unlock(&dev->device_lock); | ||
493 | return IRQ_HANDLED; | ||
494 | } | 489 | } |
495 | 490 | ||
496 | /* check if we need to start the dev */ | 491 | /* check if we need to start the dev */ |
@@ -500,15 +495,12 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
500 | 495 | ||
501 | dev->recvd_hw_ready = true; | 496 | dev->recvd_hw_ready = true; |
502 | wake_up_interruptible(&dev->wait_hw_ready); | 497 | wake_up_interruptible(&dev->wait_hw_ready); |
503 | |||
504 | mutex_unlock(&dev->device_lock); | ||
505 | return IRQ_HANDLED; | ||
506 | } else { | 498 | } else { |
499 | |||
507 | dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); | 500 | dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); |
508 | mei_me_hw_reset_release(dev); | 501 | mei_me_hw_reset_release(dev); |
509 | mutex_unlock(&dev->device_lock); | ||
510 | return IRQ_HANDLED; | ||
511 | } | 502 | } |
503 | goto end; | ||
512 | } | 504 | } |
513 | /* check slots available for reading */ | 505 | /* check slots available for reading */ |
514 | slots = mei_count_full_read_slots(dev); | 506 | slots = mei_count_full_read_slots(dev); |
@@ -516,21 +508,23 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
516 | /* we have urgent data to send so break the read */ | 508 | /* we have urgent data to send so break the read */ |
517 | if (dev->wr_ext_msg.hdr.length) | 509 | if (dev->wr_ext_msg.hdr.length) |
518 | break; | 510 | break; |
519 | dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); | 511 | 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); | 512 | rets = mei_irq_read_handler(dev, &complete_list, &slots); |
522 | if (rets) | 513 | if (rets && dev->dev_state != MEI_DEV_RESETTING) { |
514 | schedule_work(&dev->reset_work); | ||
523 | goto end; | 515 | goto end; |
516 | } | ||
524 | } | 517 | } |
518 | |||
525 | rets = mei_irq_write_handler(dev, &complete_list); | 519 | 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 | 520 | ||
530 | mutex_unlock(&dev->device_lock); | 521 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
531 | 522 | ||
532 | mei_irq_compl_handler(dev, &complete_list); | 523 | mei_irq_compl_handler(dev, &complete_list); |
533 | 524 | ||
525 | end: | ||
526 | dev_dbg(&dev->pdev->dev, "interrupt thread end ret = %d\n", rets); | ||
527 | mutex_unlock(&dev->device_lock); | ||
534 | return IRQ_HANDLED; | 528 | return IRQ_HANDLED; |
535 | } | 529 | } |
536 | static const struct mei_hw_ops mei_me_hw_ops = { | 530 | static const struct mei_hw_ops mei_me_hw_ops = { |
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index cb2f556b4252..dd44e33ad2b6 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h | |||
@@ -111,7 +111,8 @@ struct mei_msg_hdr { | |||
111 | u32 me_addr:8; | 111 | u32 me_addr:8; |
112 | u32 host_addr:8; | 112 | u32 host_addr:8; |
113 | u32 length:9; | 113 | u32 length:9; |
114 | u32 reserved:6; | 114 | u32 reserved:5; |
115 | u32 internal:1; | ||
115 | u32 msg_complete:1; | 116 | u32 msg_complete:1; |
116 | } __packed; | 117 | } __packed; |
117 | 118 | ||
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index f7f3abbe12b6..cdd31c2a2a2b 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -43,41 +43,119 @@ 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 | 46 | ||
57 | mei_io_list_init(&dev->read_list); | 47 | /** |
58 | mei_io_list_init(&dev->write_list); | 48 | * mei_cancel_work. Cancel mei background jobs |
59 | mei_io_list_init(&dev->write_waiting_list); | 49 | * |
60 | mei_io_list_init(&dev->ctrl_wr_list); | 50 | * @dev: the device structure |
61 | mei_io_list_init(&dev->ctrl_rd_list); | 51 | * |
52 | * returns 0 on success or < 0 if the reset hasn't succeeded | ||
53 | */ | ||
54 | void mei_cancel_work(struct mei_device *dev) | ||
55 | { | ||
56 | cancel_work_sync(&dev->init_work); | ||
57 | cancel_work_sync(&dev->reset_work); | ||
62 | 58 | ||
63 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | 59 | cancel_delayed_work(&dev->timer_work); |
64 | INIT_WORK(&dev->init_work, mei_host_client_init); | 60 | } |
61 | EXPORT_SYMBOL_GPL(mei_cancel_work); | ||
65 | 62 | ||
66 | INIT_LIST_HEAD(&dev->wd_cl.link); | 63 | /** |
67 | INIT_LIST_HEAD(&dev->iamthif_cl.link); | 64 | * mei_reset - resets host and fw. |
68 | mei_io_list_init(&dev->amthif_cmd_list); | 65 | * |
69 | mei_io_list_init(&dev->amthif_rd_complete_list); | 66 | * @dev: the device structure |
67 | */ | ||
68 | int mei_reset(struct mei_device *dev) | ||
69 | { | ||
70 | enum mei_dev_state state = dev->dev_state; | ||
71 | bool interrupts_enabled; | ||
72 | int ret; | ||
70 | 73 | ||
71 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | 74 | if (state != MEI_DEV_INITIALIZING && |
72 | dev->open_handle_count = 0; | 75 | state != MEI_DEV_DISABLED && |
76 | state != MEI_DEV_POWER_DOWN && | ||
77 | state != MEI_DEV_POWER_UP) | ||
78 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | ||
79 | mei_dev_state_str(state)); | ||
73 | 80 | ||
74 | /* | 81 | /* we're already in reset, cancel the init timer |
75 | * Reserving the first client ID | 82 | * if the reset was called due the hbm protocol error |
76 | * 0: Reserved for MEI Bus Message communications | 83 | * we need to call it before hw start |
84 | * so the hbm watchdog won't kick in | ||
77 | */ | 85 | */ |
78 | bitmap_set(dev->host_clients_map, 0, 1); | 86 | mei_hbm_idle(dev); |
87 | |||
88 | /* enter reset flow */ | ||
89 | interrupts_enabled = state != MEI_DEV_POWER_DOWN; | ||
90 | dev->dev_state = MEI_DEV_RESETTING; | ||
91 | |||
92 | dev->reset_count++; | ||
93 | if (dev->reset_count > MEI_MAX_CONSEC_RESET) { | ||
94 | dev_err(&dev->pdev->dev, "reset: reached maximal consecutive resets: disabling the device\n"); | ||
95 | dev->dev_state = MEI_DEV_DISABLED; | ||
96 | return -ENODEV; | ||
97 | } | ||
98 | |||
99 | ret = mei_hw_reset(dev, interrupts_enabled); | ||
100 | /* fall through and remove the sw state even if hw reset has failed */ | ||
101 | |||
102 | /* no need to clean up software state in case of power up */ | ||
103 | if (state != MEI_DEV_INITIALIZING && | ||
104 | state != MEI_DEV_POWER_UP) { | ||
105 | |||
106 | /* remove all waiting requests */ | ||
107 | mei_cl_all_write_clear(dev); | ||
108 | |||
109 | mei_cl_all_disconnect(dev); | ||
110 | |||
111 | /* wake up all readers and writers so they can be interrupted */ | ||
112 | mei_cl_all_wakeup(dev); | ||
113 | |||
114 | /* remove entry if already in list */ | ||
115 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); | ||
116 | mei_cl_unlink(&dev->wd_cl); | ||
117 | mei_cl_unlink(&dev->iamthif_cl); | ||
118 | mei_amthif_reset_params(dev); | ||
119 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); | ||
120 | } | ||
121 | |||
122 | |||
123 | dev->me_clients_num = 0; | ||
124 | dev->rd_msg_hdr = 0; | ||
125 | dev->wd_pending = false; | ||
126 | |||
127 | if (ret) { | ||
128 | dev_err(&dev->pdev->dev, "hw_reset failed ret = %d\n", ret); | ||
129 | dev->dev_state = MEI_DEV_DISABLED; | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | if (state == MEI_DEV_POWER_DOWN) { | ||
134 | dev_dbg(&dev->pdev->dev, "powering down: end of reset\n"); | ||
135 | dev->dev_state = MEI_DEV_DISABLED; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | ret = mei_hw_start(dev); | ||
140 | if (ret) { | ||
141 | dev_err(&dev->pdev->dev, "hw_start failed ret = %d\n", ret); | ||
142 | dev->dev_state = MEI_DEV_DISABLED; | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); | ||
147 | |||
148 | dev->dev_state = MEI_DEV_INIT_CLIENTS; | ||
149 | ret = mei_hbm_start_req(dev); | ||
150 | if (ret) { | ||
151 | dev_err(&dev->pdev->dev, "hbm_start failed ret = %d\n", ret); | ||
152 | dev->dev_state = MEI_DEV_DISABLED; | ||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | return 0; | ||
79 | } | 157 | } |
80 | EXPORT_SYMBOL_GPL(mei_device_init); | 158 | EXPORT_SYMBOL_GPL(mei_reset); |
81 | 159 | ||
82 | /** | 160 | /** |
83 | * mei_start - initializes host and fw to start work. | 161 | * mei_start - initializes host and fw to start work. |
@@ -90,14 +168,21 @@ int mei_start(struct mei_device *dev) | |||
90 | { | 168 | { |
91 | mutex_lock(&dev->device_lock); | 169 | mutex_lock(&dev->device_lock); |
92 | 170 | ||
93 | /* acknowledge interrupt and stop interupts */ | 171 | /* acknowledge interrupt and stop interrupts */ |
94 | mei_clear_interrupts(dev); | 172 | mei_clear_interrupts(dev); |
95 | 173 | ||
96 | mei_hw_config(dev); | 174 | mei_hw_config(dev); |
97 | 175 | ||
98 | dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); | 176 | dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); |
99 | 177 | ||
100 | mei_reset(dev, 1); | 178 | dev->dev_state = MEI_DEV_INITIALIZING; |
179 | dev->reset_count = 0; | ||
180 | mei_reset(dev); | ||
181 | |||
182 | if (dev->dev_state == MEI_DEV_DISABLED) { | ||
183 | dev_err(&dev->pdev->dev, "reset failed"); | ||
184 | goto err; | ||
185 | } | ||
101 | 186 | ||
102 | if (mei_hbm_start_wait(dev)) { | 187 | if (mei_hbm_start_wait(dev)) { |
103 | dev_err(&dev->pdev->dev, "HBM haven't started"); | 188 | dev_err(&dev->pdev->dev, "HBM haven't started"); |
@@ -132,101 +217,64 @@ err: | |||
132 | EXPORT_SYMBOL_GPL(mei_start); | 217 | EXPORT_SYMBOL_GPL(mei_start); |
133 | 218 | ||
134 | /** | 219 | /** |
135 | * mei_reset - resets host and fw. | 220 | * mei_restart - restart device after suspend |
136 | * | 221 | * |
137 | * @dev: the device structure | 222 | * @dev: the device structure |
138 | * @interrupts_enabled: if interrupt should be enabled after reset. | 223 | * |
224 | * returns 0 on success or -ENODEV if the restart hasn't succeeded | ||
139 | */ | 225 | */ |
140 | void mei_reset(struct mei_device *dev, int interrupts_enabled) | 226 | int mei_restart(struct mei_device *dev) |
141 | { | 227 | { |
142 | bool unexpected; | 228 | int err; |
143 | int ret; | ||
144 | |||
145 | unexpected = (dev->dev_state != MEI_DEV_INITIALIZING && | ||
146 | dev->dev_state != MEI_DEV_DISABLED && | ||
147 | dev->dev_state != MEI_DEV_POWER_DOWN && | ||
148 | dev->dev_state != MEI_DEV_POWER_UP); | ||
149 | 229 | ||
150 | if (unexpected) | 230 | mutex_lock(&dev->device_lock); |
151 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | ||
152 | mei_dev_state_str(dev->dev_state)); | ||
153 | |||
154 | ret = mei_hw_reset(dev, interrupts_enabled); | ||
155 | if (ret) { | ||
156 | dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); | ||
157 | interrupts_enabled = false; | ||
158 | dev->dev_state = MEI_DEV_DISABLED; | ||
159 | } | ||
160 | |||
161 | dev->hbm_state = MEI_HBM_IDLE; | ||
162 | 231 | ||
163 | if (dev->dev_state != MEI_DEV_INITIALIZING && | 232 | mei_clear_interrupts(dev); |
164 | dev->dev_state != MEI_DEV_POWER_UP) { | ||
165 | if (dev->dev_state != MEI_DEV_DISABLED && | ||
166 | dev->dev_state != MEI_DEV_POWER_DOWN) | ||
167 | dev->dev_state = MEI_DEV_RESETTING; | ||
168 | 233 | ||
169 | /* remove all waiting requests */ | 234 | dev->dev_state = MEI_DEV_POWER_UP; |
170 | mei_cl_all_write_clear(dev); | 235 | dev->reset_count = 0; |
171 | 236 | ||
172 | mei_cl_all_disconnect(dev); | 237 | err = mei_reset(dev); |
173 | 238 | ||
174 | /* wake up all readings so they can be interrupted */ | 239 | mutex_unlock(&dev->device_lock); |
175 | mei_cl_all_wakeup(dev); | ||
176 | |||
177 | /* remove entry if already in list */ | ||
178 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); | ||
179 | mei_cl_unlink(&dev->wd_cl); | ||
180 | mei_cl_unlink(&dev->iamthif_cl); | ||
181 | mei_amthif_reset_params(dev); | ||
182 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); | ||
183 | } | ||
184 | 240 | ||
185 | /* we're already in reset, cancel the init timer */ | 241 | if (err || dev->dev_state == MEI_DEV_DISABLED) |
186 | dev->init_clients_timer = 0; | 242 | return -ENODEV; |
187 | 243 | ||
188 | dev->me_clients_num = 0; | 244 | return 0; |
189 | dev->rd_msg_hdr = 0; | 245 | } |
190 | dev->wd_pending = false; | 246 | EXPORT_SYMBOL_GPL(mei_restart); |
191 | 247 | ||
192 | if (!interrupts_enabled) { | ||
193 | dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); | ||
194 | return; | ||
195 | } | ||
196 | 248 | ||
197 | ret = mei_hw_start(dev); | 249 | static void mei_reset_work(struct work_struct *work) |
198 | if (ret) { | 250 | { |
199 | dev_err(&dev->pdev->dev, "hw_start failed disabling the device\n"); | 251 | struct mei_device *dev = |
200 | dev->dev_state = MEI_DEV_DISABLED; | 252 | container_of(work, struct mei_device, reset_work); |
201 | return; | ||
202 | } | ||
203 | 253 | ||
204 | dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); | 254 | mutex_lock(&dev->device_lock); |
205 | /* link is established * start sending messages. */ | ||
206 | 255 | ||
207 | dev->dev_state = MEI_DEV_INIT_CLIENTS; | 256 | mei_reset(dev); |
208 | 257 | ||
209 | mei_hbm_start_req(dev); | 258 | mutex_unlock(&dev->device_lock); |
210 | 259 | ||
260 | if (dev->dev_state == MEI_DEV_DISABLED) | ||
261 | dev_err(&dev->pdev->dev, "reset failed"); | ||
211 | } | 262 | } |
212 | EXPORT_SYMBOL_GPL(mei_reset); | ||
213 | 263 | ||
214 | void mei_stop(struct mei_device *dev) | 264 | void mei_stop(struct mei_device *dev) |
215 | { | 265 | { |
216 | dev_dbg(&dev->pdev->dev, "stopping the device.\n"); | 266 | dev_dbg(&dev->pdev->dev, "stopping the device.\n"); |
217 | 267 | ||
218 | flush_scheduled_work(); | 268 | mei_cancel_work(dev); |
219 | 269 | ||
220 | mutex_lock(&dev->device_lock); | 270 | mei_nfc_host_exit(dev); |
221 | 271 | ||
222 | cancel_delayed_work(&dev->timer_work); | 272 | mutex_lock(&dev->device_lock); |
223 | 273 | ||
224 | mei_wd_stop(dev); | 274 | mei_wd_stop(dev); |
225 | 275 | ||
226 | mei_nfc_host_exit(); | ||
227 | |||
228 | dev->dev_state = MEI_DEV_POWER_DOWN; | 276 | dev->dev_state = MEI_DEV_POWER_DOWN; |
229 | mei_reset(dev, 0); | 277 | mei_reset(dev); |
230 | 278 | ||
231 | mutex_unlock(&dev->device_lock); | 279 | mutex_unlock(&dev->device_lock); |
232 | 280 | ||
@@ -236,3 +284,41 @@ EXPORT_SYMBOL_GPL(mei_stop); | |||
236 | 284 | ||
237 | 285 | ||
238 | 286 | ||
287 | void mei_device_init(struct mei_device *dev) | ||
288 | { | ||
289 | /* setup our list array */ | ||
290 | INIT_LIST_HEAD(&dev->file_list); | ||
291 | INIT_LIST_HEAD(&dev->device_list); | ||
292 | mutex_init(&dev->device_lock); | ||
293 | init_waitqueue_head(&dev->wait_hw_ready); | ||
294 | init_waitqueue_head(&dev->wait_recvd_msg); | ||
295 | init_waitqueue_head(&dev->wait_stop_wd); | ||
296 | dev->dev_state = MEI_DEV_INITIALIZING; | ||
297 | dev->reset_count = 0; | ||
298 | |||
299 | mei_io_list_init(&dev->read_list); | ||
300 | mei_io_list_init(&dev->write_list); | ||
301 | mei_io_list_init(&dev->write_waiting_list); | ||
302 | mei_io_list_init(&dev->ctrl_wr_list); | ||
303 | mei_io_list_init(&dev->ctrl_rd_list); | ||
304 | |||
305 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | ||
306 | INIT_WORK(&dev->init_work, mei_host_client_init); | ||
307 | INIT_WORK(&dev->reset_work, mei_reset_work); | ||
308 | |||
309 | INIT_LIST_HEAD(&dev->wd_cl.link); | ||
310 | INIT_LIST_HEAD(&dev->iamthif_cl.link); | ||
311 | mei_io_list_init(&dev->amthif_cmd_list); | ||
312 | mei_io_list_init(&dev->amthif_rd_complete_list); | ||
313 | |||
314 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
315 | dev->open_handle_count = 0; | ||
316 | |||
317 | /* | ||
318 | * Reserving the first client ID | ||
319 | * 0: Reserved for MEI Bus Message communications | ||
320 | */ | ||
321 | bitmap_set(dev->host_clients_map, 0, 1); | ||
322 | } | ||
323 | EXPORT_SYMBOL_GPL(mei_device_init); | ||
324 | |||
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 7a95c07e59a6..f0fbb5179f80 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -31,7 +31,7 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | /** | 33 | /** |
34 | * mei_irq_compl_handler - dispatch complete handelers | 34 | * mei_irq_compl_handler - dispatch complete handlers |
35 | * for the completed callbacks | 35 | * for the completed callbacks |
36 | * | 36 | * |
37 | * @dev - mei device | 37 | * @dev - mei device |
@@ -301,13 +301,11 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
301 | struct mei_cl_cb *cmpl_list, s32 *slots) | 301 | struct mei_cl_cb *cmpl_list, s32 *slots) |
302 | { | 302 | { |
303 | struct mei_msg_hdr *mei_hdr; | 303 | struct mei_msg_hdr *mei_hdr; |
304 | struct mei_cl *cl_pos = NULL; | 304 | struct mei_cl *cl; |
305 | struct mei_cl *cl_next = NULL; | 305 | int ret; |
306 | int ret = 0; | ||
307 | 306 | ||
308 | if (!dev->rd_msg_hdr) { | 307 | if (!dev->rd_msg_hdr) { |
309 | dev->rd_msg_hdr = mei_read_hdr(dev); | 308 | dev->rd_msg_hdr = mei_read_hdr(dev); |
310 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | ||
311 | (*slots)--; | 309 | (*slots)--; |
312 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); | 310 | dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); |
313 | } | 311 | } |
@@ -315,61 +313,67 @@ int mei_irq_read_handler(struct mei_device *dev, | |||
315 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | 313 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); |
316 | 314 | ||
317 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { | 315 | if (mei_hdr->reserved || !dev->rd_msg_hdr) { |
318 | dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); | 316 | dev_err(&dev->pdev->dev, "corrupted message header 0x%08X\n", |
317 | dev->rd_msg_hdr); | ||
319 | ret = -EBADMSG; | 318 | ret = -EBADMSG; |
320 | goto end; | 319 | goto end; |
321 | } | 320 | } |
322 | 321 | ||
323 | if (mei_hdr->host_addr || mei_hdr->me_addr) { | 322 | if (mei_slots2data(*slots) < mei_hdr->length) { |
324 | list_for_each_entry_safe(cl_pos, cl_next, | 323 | dev_err(&dev->pdev->dev, "less data available than length=%08x.\n", |
325 | &dev->file_list, link) { | ||
326 | dev_dbg(&dev->pdev->dev, | ||
327 | "list_for_each_entry_safe read host" | ||
328 | " client = %d, ME client = %d\n", | ||
329 | cl_pos->host_client_id, | ||
330 | cl_pos->me_client_id); | ||
331 | if (mei_cl_hbm_equal(cl_pos, mei_hdr)) | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | if (&cl_pos->link == &dev->file_list) { | ||
336 | dev_dbg(&dev->pdev->dev, "corrupted message header\n"); | ||
337 | ret = -EBADMSG; | ||
338 | goto end; | ||
339 | } | ||
340 | } | ||
341 | if (((*slots) * sizeof(u32)) < mei_hdr->length) { | ||
342 | dev_err(&dev->pdev->dev, | ||
343 | "we can't read the message slots =%08x.\n", | ||
344 | *slots); | 324 | *slots); |
345 | /* we can't read the message */ | 325 | /* we can't read the message */ |
346 | ret = -ERANGE; | 326 | ret = -ERANGE; |
347 | goto end; | 327 | goto end; |
348 | } | 328 | } |
349 | 329 | ||
350 | /* decide where to read the message too */ | 330 | /* HBM message */ |
351 | if (!mei_hdr->host_addr) { | 331 | if (mei_hdr->host_addr == 0 && mei_hdr->me_addr == 0) { |
352 | dev_dbg(&dev->pdev->dev, "call mei_hbm_dispatch.\n"); | 332 | ret = mei_hbm_dispatch(dev, mei_hdr); |
353 | mei_hbm_dispatch(dev, mei_hdr); | 333 | if (ret) { |
354 | dev_dbg(&dev->pdev->dev, "end mei_hbm_dispatch.\n"); | 334 | dev_dbg(&dev->pdev->dev, "mei_hbm_dispatch failed ret = %d\n", |
355 | } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && | 335 | ret); |
356 | (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && | 336 | goto end; |
357 | (dev->iamthif_state == MEI_IAMTHIF_READING)) { | 337 | } |
338 | goto reset_slots; | ||
339 | } | ||
340 | |||
341 | /* find recipient cl */ | ||
342 | list_for_each_entry(cl, &dev->file_list, link) { | ||
343 | if (mei_cl_hbm_equal(cl, mei_hdr)) { | ||
344 | cl_dbg(dev, cl, "got a message\n"); | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* if no recipient cl was found we assume corrupted header */ | ||
350 | if (&cl->link == &dev->file_list) { | ||
351 | dev_err(&dev->pdev->dev, "no destination client found 0x%08X\n", | ||
352 | dev->rd_msg_hdr); | ||
353 | ret = -EBADMSG; | ||
354 | goto end; | ||
355 | } | ||
358 | 356 | ||
359 | dev_dbg(&dev->pdev->dev, "call mei_amthif_irq_read_msg.\n"); | 357 | if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && |
360 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | 358 | MEI_FILE_CONNECTED == dev->iamthif_cl.state && |
359 | dev->iamthif_state == MEI_IAMTHIF_READING) { | ||
361 | 360 | ||
362 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); | 361 | ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); |
363 | if (ret) | 362 | if (ret) { |
363 | dev_err(&dev->pdev->dev, "mei_amthif_irq_read_msg failed = %d\n", | ||
364 | ret); | ||
364 | goto end; | 365 | goto end; |
366 | } | ||
365 | } else { | 367 | } else { |
366 | dev_dbg(&dev->pdev->dev, "call mei_cl_irq_read_msg.\n"); | ||
367 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr)); | ||
368 | ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); | 368 | ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); |
369 | if (ret) | 369 | if (ret) { |
370 | dev_err(&dev->pdev->dev, "mei_cl_irq_read_msg failed = %d\n", | ||
371 | ret); | ||
370 | goto end; | 372 | goto end; |
373 | } | ||
371 | } | 374 | } |
372 | 375 | ||
376 | reset_slots: | ||
373 | /* reset the number of slots and header */ | 377 | /* reset the number of slots and header */ |
374 | *slots = mei_count_full_read_slots(dev); | 378 | *slots = mei_count_full_read_slots(dev); |
375 | dev->rd_msg_hdr = 0; | 379 | dev->rd_msg_hdr = 0; |
@@ -533,7 +537,6 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler); | |||
533 | * | 537 | * |
534 | * @work: pointer to the work_struct structure | 538 | * @work: pointer to the work_struct structure |
535 | * | 539 | * |
536 | * NOTE: This function is called by timer interrupt work | ||
537 | */ | 540 | */ |
538 | void mei_timer(struct work_struct *work) | 541 | void mei_timer(struct work_struct *work) |
539 | { | 542 | { |
@@ -548,24 +551,30 @@ void mei_timer(struct work_struct *work) | |||
548 | 551 | ||
549 | 552 | ||
550 | mutex_lock(&dev->device_lock); | 553 | mutex_lock(&dev->device_lock); |
551 | if (dev->dev_state != MEI_DEV_ENABLED) { | 554 | |
552 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS) { | 555 | /* Catch interrupt stalls during HBM init handshake */ |
553 | if (dev->init_clients_timer) { | 556 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && |
554 | if (--dev->init_clients_timer == 0) { | 557 | dev->hbm_state != MEI_HBM_IDLE) { |
555 | dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n", | 558 | |
556 | dev->hbm_state); | 559 | if (dev->init_clients_timer) { |
557 | mei_reset(dev, 1); | 560 | if (--dev->init_clients_timer == 0) { |
558 | } | 561 | dev_err(&dev->pdev->dev, "timer: init clients timeout hbm_state = %d.\n", |
562 | dev->hbm_state); | ||
563 | mei_reset(dev); | ||
564 | goto out; | ||
559 | } | 565 | } |
560 | } | 566 | } |
561 | goto out; | ||
562 | } | 567 | } |
568 | |||
569 | if (dev->dev_state != MEI_DEV_ENABLED) | ||
570 | goto out; | ||
571 | |||
563 | /*** connect/disconnect timeouts ***/ | 572 | /*** connect/disconnect timeouts ***/ |
564 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { | 573 | list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { |
565 | if (cl_pos->timer_count) { | 574 | if (cl_pos->timer_count) { |
566 | if (--cl_pos->timer_count == 0) { | 575 | if (--cl_pos->timer_count == 0) { |
567 | dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n"); | 576 | dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n"); |
568 | mei_reset(dev, 1); | 577 | mei_reset(dev); |
569 | goto out; | 578 | goto out; |
570 | } | 579 | } |
571 | } | 580 | } |
@@ -573,8 +582,8 @@ void mei_timer(struct work_struct *work) | |||
573 | 582 | ||
574 | if (dev->iamthif_stall_timer) { | 583 | if (dev->iamthif_stall_timer) { |
575 | if (--dev->iamthif_stall_timer == 0) { | 584 | if (--dev->iamthif_stall_timer == 0) { |
576 | dev_err(&dev->pdev->dev, "reset: amthif hanged.\n"); | 585 | dev_err(&dev->pdev->dev, "timer: amthif hanged.\n"); |
577 | mei_reset(dev, 1); | 586 | mei_reset(dev); |
578 | dev->iamthif_msg_buf_size = 0; | 587 | dev->iamthif_msg_buf_size = 0; |
579 | dev->iamthif_msg_buf_index = 0; | 588 | dev->iamthif_msg_buf_index = 0; |
580 | dev->iamthif_canceled = false; | 589 | dev->iamthif_canceled = false; |
@@ -627,7 +636,8 @@ void mei_timer(struct work_struct *work) | |||
627 | } | 636 | } |
628 | } | 637 | } |
629 | out: | 638 | out: |
630 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | 639 | if (dev->dev_state != MEI_DEV_DISABLED) |
640 | schedule_delayed_work(&dev->timer_work, 2 * HZ); | ||
631 | mutex_unlock(&dev->device_lock); | 641 | mutex_unlock(&dev->device_lock); |
632 | } | 642 | } |
633 | 643 | ||
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 9661a812f550..5424f8ff3f7f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -48,7 +48,7 @@ | |||
48 | * | 48 | * |
49 | * @inode: pointer to inode structure | 49 | * @inode: pointer to inode structure |
50 | * @file: pointer to file structure | 50 | * @file: pointer to file structure |
51 | e | 51 | * |
52 | * returns 0 on success, <0 on error | 52 | * returns 0 on success, <0 on error |
53 | */ | 53 | */ |
54 | static int mei_open(struct inode *inode, struct file *file) | 54 | static int mei_open(struct inode *inode, struct file *file) |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 406f68e05b4e..f7de95b4cdd9 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -61,11 +61,16 @@ extern const uuid_le mei_wd_guid; | |||
61 | #define MEI_CLIENTS_MAX 256 | 61 | #define MEI_CLIENTS_MAX 256 |
62 | 62 | ||
63 | /* | 63 | /* |
64 | * maximum number of consecutive resets | ||
65 | */ | ||
66 | #define MEI_MAX_CONSEC_RESET 3 | ||
67 | |||
68 | /* | ||
64 | * Number of File descriptors/handles | 69 | * Number of File descriptors/handles |
65 | * that can be opened to the driver. | 70 | * that can be opened to the driver. |
66 | * | 71 | * |
67 | * Limit to 255: 256 Total Clients | 72 | * Limit to 255: 256 Total Clients |
68 | * minus internal client for MEI Bus Messags | 73 | * minus internal client for MEI Bus Messages |
69 | */ | 74 | */ |
70 | #define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) | 75 | #define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 1) |
71 | 76 | ||
@@ -178,9 +183,10 @@ struct mei_cl_cb { | |||
178 | unsigned long buf_idx; | 183 | unsigned long buf_idx; |
179 | unsigned long read_time; | 184 | unsigned long read_time; |
180 | struct file *file_object; | 185 | struct file *file_object; |
186 | u32 internal:1; | ||
181 | }; | 187 | }; |
182 | 188 | ||
183 | /* MEI client instance carried as file->pirvate_data*/ | 189 | /* MEI client instance carried as file->private_data*/ |
184 | struct mei_cl { | 190 | struct mei_cl { |
185 | struct list_head link; | 191 | struct list_head link; |
186 | struct mei_device *dev; | 192 | struct mei_device *dev; |
@@ -326,6 +332,7 @@ struct mei_cl_device { | |||
326 | /** | 332 | /** |
327 | * struct mei_device - MEI private device struct | 333 | * struct mei_device - MEI private device struct |
328 | 334 | ||
335 | * @reset_count - limits the number of consecutive resets | ||
329 | * @hbm_state - state of host bus message protocol | 336 | * @hbm_state - state of host bus message protocol |
330 | * @mem_addr - mem mapped base register address | 337 | * @mem_addr - mem mapped base register address |
331 | 338 | ||
@@ -369,6 +376,7 @@ struct mei_device { | |||
369 | /* | 376 | /* |
370 | * mei device states | 377 | * mei device states |
371 | */ | 378 | */ |
379 | unsigned long reset_count; | ||
372 | enum mei_dev_state dev_state; | 380 | enum mei_dev_state dev_state; |
373 | enum mei_hbm_state hbm_state; | 381 | enum mei_hbm_state hbm_state; |
374 | u16 init_clients_timer; | 382 | u16 init_clients_timer; |
@@ -427,6 +435,7 @@ struct mei_device { | |||
427 | bool iamthif_canceled; | 435 | bool iamthif_canceled; |
428 | 436 | ||
429 | struct work_struct init_work; | 437 | struct work_struct init_work; |
438 | struct work_struct reset_work; | ||
430 | 439 | ||
431 | /* List of bus devices */ | 440 | /* List of bus devices */ |
432 | struct list_head device_list; | 441 | struct list_head device_list; |
@@ -456,13 +465,25 @@ static inline u32 mei_data2slots(size_t length) | |||
456 | return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4); | 465 | return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4); |
457 | } | 466 | } |
458 | 467 | ||
468 | /** | ||
469 | * mei_slots2data- get data in slots - bytes from slots | ||
470 | * @slots - number of available slots | ||
471 | * returns - number of bytes in slots | ||
472 | */ | ||
473 | static inline u32 mei_slots2data(int slots) | ||
474 | { | ||
475 | return slots * 4; | ||
476 | } | ||
477 | |||
459 | /* | 478 | /* |
460 | * mei init function prototypes | 479 | * mei init function prototypes |
461 | */ | 480 | */ |
462 | void mei_device_init(struct mei_device *dev); | 481 | void mei_device_init(struct mei_device *dev); |
463 | void mei_reset(struct mei_device *dev, int interrupts); | 482 | int mei_reset(struct mei_device *dev); |
464 | int mei_start(struct mei_device *dev); | 483 | int mei_start(struct mei_device *dev); |
484 | int mei_restart(struct mei_device *dev); | ||
465 | void mei_stop(struct mei_device *dev); | 485 | void mei_stop(struct mei_device *dev); |
486 | void mei_cancel_work(struct mei_device *dev); | ||
466 | 487 | ||
467 | /* | 488 | /* |
468 | * MEI interrupt functions prototype | 489 | * MEI interrupt functions prototype |
@@ -510,7 +531,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); | |||
510 | * NFC functions | 531 | * NFC functions |
511 | */ | 532 | */ |
512 | int mei_nfc_host_init(struct mei_device *dev); | 533 | int mei_nfc_host_init(struct mei_device *dev); |
513 | void mei_nfc_host_exit(void); | 534 | void mei_nfc_host_exit(struct mei_device *dev); |
514 | 535 | ||
515 | /* | 536 | /* |
516 | * NFC Client UUID | 537 | * NFC Client UUID |
@@ -626,9 +647,9 @@ static inline void mei_dbgfs_deregister(struct mei_device *dev) {} | |||
626 | int mei_register(struct mei_device *dev); | 647 | int mei_register(struct mei_device *dev); |
627 | void mei_deregister(struct mei_device *dev); | 648 | void mei_deregister(struct mei_device *dev); |
628 | 649 | ||
629 | #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d" | 650 | #define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d" |
630 | #define MEI_HDR_PRM(hdr) \ | 651 | #define MEI_HDR_PRM(hdr) \ |
631 | (hdr)->host_addr, (hdr)->me_addr, \ | 652 | (hdr)->host_addr, (hdr)->me_addr, \ |
632 | (hdr)->length, (hdr)->msg_complete | 653 | (hdr)->length, (hdr)->internal, (hdr)->msg_complete |
633 | 654 | ||
634 | #endif | 655 | #endif |
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 994ca4aff1a3..a58320c0c049 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c | |||
@@ -92,7 +92,7 @@ struct mei_nfc_hci_hdr { | |||
92 | * @cl: NFC host client | 92 | * @cl: NFC host client |
93 | * @cl_info: NFC info host client | 93 | * @cl_info: NFC info host client |
94 | * @init_work: perform connection to the info client | 94 | * @init_work: perform connection to the info client |
95 | * @fw_ivn: NFC Intervace Version Number | 95 | * @fw_ivn: NFC Interface Version Number |
96 | * @vendor_id: NFC manufacturer ID | 96 | * @vendor_id: NFC manufacturer ID |
97 | * @radio_type: NFC radio type | 97 | * @radio_type: NFC radio type |
98 | */ | 98 | */ |
@@ -163,7 +163,7 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) | |||
163 | return 0; | 163 | return 0; |
164 | 164 | ||
165 | default: | 165 | default: |
166 | dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n", | 166 | dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n", |
167 | ndev->radio_type); | 167 | ndev->radio_type); |
168 | 168 | ||
169 | return -EINVAL; | 169 | return -EINVAL; |
@@ -175,14 +175,14 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) | |||
175 | ndev->bus_name = "pn544"; | 175 | ndev->bus_name = "pn544"; |
176 | return 0; | 176 | return 0; |
177 | default: | 177 | default: |
178 | dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n", | 178 | dev_err(&dev->pdev->dev, "Unknown radio type 0x%x\n", |
179 | ndev->radio_type); | 179 | ndev->radio_type); |
180 | 180 | ||
181 | return -EINVAL; | 181 | return -EINVAL; |
182 | } | 182 | } |
183 | 183 | ||
184 | default: | 184 | default: |
185 | dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n", | 185 | dev_err(&dev->pdev->dev, "Unknown vendor ID 0x%x\n", |
186 | ndev->vendor_id); | 186 | ndev->vendor_id); |
187 | 187 | ||
188 | return -EINVAL; | 188 | return -EINVAL; |
@@ -428,7 +428,7 @@ static void mei_nfc_init(struct work_struct *work) | |||
428 | mutex_unlock(&dev->device_lock); | 428 | mutex_unlock(&dev->device_lock); |
429 | 429 | ||
430 | if (mei_nfc_if_version(ndev) < 0) { | 430 | if (mei_nfc_if_version(ndev) < 0) { |
431 | dev_err(&dev->pdev->dev, "Could not get the NFC interfave version"); | 431 | dev_err(&dev->pdev->dev, "Could not get the NFC interface version"); |
432 | 432 | ||
433 | goto err; | 433 | goto err; |
434 | } | 434 | } |
@@ -469,7 +469,9 @@ static void mei_nfc_init(struct work_struct *work) | |||
469 | return; | 469 | return; |
470 | 470 | ||
471 | err: | 471 | err: |
472 | mutex_lock(&dev->device_lock); | ||
472 | mei_nfc_free(ndev); | 473 | mei_nfc_free(ndev); |
474 | mutex_unlock(&dev->device_lock); | ||
473 | 475 | ||
474 | return; | 476 | return; |
475 | } | 477 | } |
@@ -481,7 +483,7 @@ int mei_nfc_host_init(struct mei_device *dev) | |||
481 | struct mei_cl *cl_info, *cl = NULL; | 483 | struct mei_cl *cl_info, *cl = NULL; |
482 | int i, ret; | 484 | int i, ret; |
483 | 485 | ||
484 | /* already initialzed */ | 486 | /* already initialized */ |
485 | if (ndev->cl_info) | 487 | if (ndev->cl_info) |
486 | return 0; | 488 | return 0; |
487 | 489 | ||
@@ -547,12 +549,16 @@ err: | |||
547 | return ret; | 549 | return ret; |
548 | } | 550 | } |
549 | 551 | ||
550 | void mei_nfc_host_exit(void) | 552 | void mei_nfc_host_exit(struct mei_device *dev) |
551 | { | 553 | { |
552 | struct mei_nfc_dev *ndev = &nfc_dev; | 554 | struct mei_nfc_dev *ndev = &nfc_dev; |
553 | 555 | ||
556 | cancel_work_sync(&ndev->init_work); | ||
557 | |||
558 | mutex_lock(&dev->device_lock); | ||
554 | if (ndev->cl && ndev->cl->device) | 559 | if (ndev->cl && ndev->cl->device) |
555 | mei_cl_remove_device(ndev->cl->device); | 560 | mei_cl_remove_device(ndev->cl->device); |
556 | 561 | ||
557 | mei_nfc_free(ndev); | 562 | mei_nfc_free(ndev); |
563 | mutex_unlock(&dev->device_lock); | ||
558 | } | 564 | } |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 2cab3c0a6805..ddadd08956f4 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -144,6 +144,21 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
144 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | 144 | dev_err(&pdev->dev, "failed to get pci regions.\n"); |
145 | goto disable_device; | 145 | goto disable_device; |
146 | } | 146 | } |
147 | |||
148 | if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || | ||
149 | dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { | ||
150 | |||
151 | err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); | ||
152 | if (err) | ||
153 | err = dma_set_coherent_mask(&pdev->dev, | ||
154 | DMA_BIT_MASK(32)); | ||
155 | } | ||
156 | if (err) { | ||
157 | dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); | ||
158 | goto release_regions; | ||
159 | } | ||
160 | |||
161 | |||
147 | /* allocates and initializes the mei dev structure */ | 162 | /* allocates and initializes the mei dev structure */ |
148 | dev = mei_me_dev_init(pdev); | 163 | dev = mei_me_dev_init(pdev); |
149 | if (!dev) { | 164 | if (!dev) { |
@@ -197,8 +212,8 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
197 | return 0; | 212 | return 0; |
198 | 213 | ||
199 | release_irq: | 214 | release_irq: |
215 | mei_cancel_work(dev); | ||
200 | mei_disable_interrupts(dev); | 216 | mei_disable_interrupts(dev); |
201 | flush_scheduled_work(); | ||
202 | free_irq(pdev->irq, dev); | 217 | free_irq(pdev->irq, dev); |
203 | disable_msi: | 218 | disable_msi: |
204 | pci_disable_msi(pdev); | 219 | pci_disable_msi(pdev); |
@@ -306,16 +321,14 @@ static int mei_me_pci_resume(struct device *device) | |||
306 | return err; | 321 | return err; |
307 | } | 322 | } |
308 | 323 | ||
309 | mutex_lock(&dev->device_lock); | 324 | err = mei_restart(dev); |
310 | dev->dev_state = MEI_DEV_POWER_UP; | 325 | if (err) |
311 | mei_clear_interrupts(dev); | 326 | return err; |
312 | mei_reset(dev, 1); | ||
313 | mutex_unlock(&dev->device_lock); | ||
314 | 327 | ||
315 | /* Start timer if stopped in suspend */ | 328 | /* Start timer if stopped in suspend */ |
316 | schedule_delayed_work(&dev->timer_work, HZ); | 329 | schedule_delayed_work(&dev->timer_work, HZ); |
317 | 330 | ||
318 | return err; | 331 | return 0; |
319 | } | 332 | } |
320 | static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); | 333 | static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); |
321 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) | 334 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) |
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 9e354216c163..f70945ed96f6 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c | |||
@@ -115,6 +115,7 @@ int mei_wd_send(struct mei_device *dev) | |||
115 | hdr.me_addr = dev->wd_cl.me_client_id; | 115 | hdr.me_addr = dev->wd_cl.me_client_id; |
116 | hdr.msg_complete = 1; | 116 | hdr.msg_complete = 1; |
117 | hdr.reserved = 0; | 117 | hdr.reserved = 0; |
118 | hdr.internal = 0; | ||
118 | 119 | ||
119 | if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) | 120 | if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE)) |
120 | hdr.length = MEI_WD_START_MSG_SIZE; | 121 | hdr.length = MEI_WD_START_MSG_SIZE; |