diff options
Diffstat (limited to 'drivers/misc/mei/interrupt.c')
-rw-r--r-- | drivers/misc/mei/interrupt.c | 205 |
1 files changed, 58 insertions, 147 deletions
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 2ad736989410..4b59cb742dee 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -31,32 +31,6 @@ | |||
31 | 31 | ||
32 | 32 | ||
33 | /** | 33 | /** |
34 | * mei_cl_complete_handler - processes completed operation for a client | ||
35 | * | ||
36 | * @cl: private data of the file object. | ||
37 | * @cb: callback block. | ||
38 | */ | ||
39 | static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb) | ||
40 | { | ||
41 | if (cb->fop_type == MEI_FOP_WRITE) { | ||
42 | mei_io_cb_free(cb); | ||
43 | cb = NULL; | ||
44 | cl->writing_state = MEI_WRITE_COMPLETE; | ||
45 | if (waitqueue_active(&cl->tx_wait)) | ||
46 | wake_up_interruptible(&cl->tx_wait); | ||
47 | |||
48 | } else if (cb->fop_type == MEI_FOP_READ && | ||
49 | MEI_READING == cl->reading_state) { | ||
50 | cl->reading_state = MEI_READ_COMPLETE; | ||
51 | if (waitqueue_active(&cl->rx_wait)) | ||
52 | wake_up_interruptible(&cl->rx_wait); | ||
53 | else | ||
54 | mei_cl_bus_rx_event(cl); | ||
55 | |||
56 | } | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * mei_irq_compl_handler - dispatch complete handelers | 34 | * mei_irq_compl_handler - dispatch complete handelers |
61 | * for the completed callbacks | 35 | * for the completed callbacks |
62 | * | 36 | * |
@@ -78,7 +52,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list) | |||
78 | if (cl == &dev->iamthif_cl) | 52 | if (cl == &dev->iamthif_cl) |
79 | mei_amthif_complete(dev, cb); | 53 | mei_amthif_complete(dev, cb); |
80 | else | 54 | else |
81 | mei_cl_complete_handler(cl, cb); | 55 | mei_cl_complete(cl, cb); |
82 | } | 56 | } |
83 | } | 57 | } |
84 | EXPORT_SYMBOL_GPL(mei_irq_compl_handler); | 58 | EXPORT_SYMBOL_GPL(mei_irq_compl_handler); |
@@ -189,21 +163,21 @@ static int mei_cl_irq_read_msg(struct mei_device *dev, | |||
189 | } | 163 | } |
190 | 164 | ||
191 | /** | 165 | /** |
192 | * _mei_irq_thread_close - processes close related operation. | 166 | * mei_cl_irq_close - processes close related operation from |
167 | * interrupt thread context - send disconnect request | ||
193 | * | 168 | * |
194 | * @dev: the device structure. | 169 | * @cl: client |
170 | * @cb: callback block. | ||
195 | * @slots: free slots. | 171 | * @slots: free slots. |
196 | * @cb_pos: callback block. | ||
197 | * @cl: private data of the file object. | ||
198 | * @cmpl_list: complete list. | 172 | * @cmpl_list: complete list. |
199 | * | 173 | * |
200 | * returns 0, OK; otherwise, error. | 174 | * returns 0, OK; otherwise, error. |
201 | */ | 175 | */ |
202 | static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | 176 | static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb, |
203 | struct mei_cl_cb *cb_pos, | 177 | s32 *slots, struct mei_cl_cb *cmpl_list) |
204 | struct mei_cl *cl, | ||
205 | struct mei_cl_cb *cmpl_list) | ||
206 | { | 178 | { |
179 | struct mei_device *dev = cl->dev; | ||
180 | |||
207 | u32 msg_slots = | 181 | u32 msg_slots = |
208 | mei_data2slots(sizeof(struct hbm_client_connect_request)); | 182 | mei_data2slots(sizeof(struct hbm_client_connect_request)); |
209 | 183 | ||
@@ -214,15 +188,15 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | |||
214 | 188 | ||
215 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | 189 | if (mei_hbm_cl_disconnect_req(dev, cl)) { |
216 | cl->status = 0; | 190 | cl->status = 0; |
217 | cb_pos->buf_idx = 0; | 191 | cb->buf_idx = 0; |
218 | list_move_tail(&cb_pos->list, &cmpl_list->list); | 192 | list_move_tail(&cb->list, &cmpl_list->list); |
219 | return -EIO; | 193 | return -EIO; |
220 | } | 194 | } |
221 | 195 | ||
222 | cl->state = MEI_FILE_DISCONNECTING; | 196 | cl->state = MEI_FILE_DISCONNECTING; |
223 | cl->status = 0; | 197 | cl->status = 0; |
224 | cb_pos->buf_idx = 0; | 198 | cb->buf_idx = 0; |
225 | list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); | 199 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); |
226 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 200 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
227 | 201 | ||
228 | return 0; | 202 | return 0; |
@@ -230,26 +204,26 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, | |||
230 | 204 | ||
231 | 205 | ||
232 | /** | 206 | /** |
233 | * _mei_irq_thread_read - processes read related operation. | 207 | * mei_cl_irq_close - processes client read related operation from the |
208 | * interrupt thread context - request for flow control credits | ||
234 | * | 209 | * |
235 | * @dev: the device structure. | 210 | * @cl: client |
211 | * @cb: callback block. | ||
236 | * @slots: free slots. | 212 | * @slots: free slots. |
237 | * @cb_pos: callback block. | ||
238 | * @cl: private data of the file object. | ||
239 | * @cmpl_list: complete list. | 213 | * @cmpl_list: complete list. |
240 | * | 214 | * |
241 | * returns 0, OK; otherwise, error. | 215 | * returns 0, OK; otherwise, error. |
242 | */ | 216 | */ |
243 | static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | 217 | static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, |
244 | struct mei_cl_cb *cb_pos, | 218 | s32 *slots, struct mei_cl_cb *cmpl_list) |
245 | struct mei_cl *cl, | ||
246 | struct mei_cl_cb *cmpl_list) | ||
247 | { | 219 | { |
220 | struct mei_device *dev = cl->dev; | ||
221 | |||
248 | u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); | 222 | u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); |
249 | 223 | ||
250 | if (*slots < msg_slots) { | 224 | if (*slots < msg_slots) { |
251 | /* return the cancel routine */ | 225 | /* return the cancel routine */ |
252 | list_del(&cb_pos->list); | 226 | list_del(&cb->list); |
253 | return -EMSGSIZE; | 227 | return -EMSGSIZE; |
254 | } | 228 | } |
255 | 229 | ||
@@ -257,38 +231,38 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, | |||
257 | 231 | ||
258 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 232 | if (mei_hbm_cl_flow_control_req(dev, cl)) { |
259 | cl->status = -ENODEV; | 233 | cl->status = -ENODEV; |
260 | cb_pos->buf_idx = 0; | 234 | cb->buf_idx = 0; |
261 | list_move_tail(&cb_pos->list, &cmpl_list->list); | 235 | list_move_tail(&cb->list, &cmpl_list->list); |
262 | return -ENODEV; | 236 | return -ENODEV; |
263 | } | 237 | } |
264 | list_move_tail(&cb_pos->list, &dev->read_list.list); | 238 | list_move_tail(&cb->list, &dev->read_list.list); |
265 | 239 | ||
266 | return 0; | 240 | return 0; |
267 | } | 241 | } |
268 | 242 | ||
269 | 243 | ||
270 | /** | 244 | /** |
271 | * _mei_irq_thread_ioctl - processes ioctl related operation. | 245 | * mei_cl_irq_ioctl - processes client ioctl related operation from the |
246 | * interrupt thread context - send connection request | ||
272 | * | 247 | * |
273 | * @dev: the device structure. | 248 | * @cl: client |
249 | * @cb: callback block. | ||
274 | * @slots: free slots. | 250 | * @slots: free slots. |
275 | * @cb_pos: callback block. | ||
276 | * @cl: private data of the file object. | ||
277 | * @cmpl_list: complete list. | 251 | * @cmpl_list: complete list. |
278 | * | 252 | * |
279 | * returns 0, OK; otherwise, error. | 253 | * returns 0, OK; otherwise, error. |
280 | */ | 254 | */ |
281 | static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | 255 | static int mei_cl_irq_ioctl(struct mei_cl *cl, struct mei_cl_cb *cb, |
282 | struct mei_cl_cb *cb_pos, | 256 | s32 *slots, struct mei_cl_cb *cmpl_list) |
283 | struct mei_cl *cl, | ||
284 | struct mei_cl_cb *cmpl_list) | ||
285 | { | 257 | { |
258 | struct mei_device *dev = cl->dev; | ||
259 | |||
286 | u32 msg_slots = | 260 | u32 msg_slots = |
287 | mei_data2slots(sizeof(struct hbm_client_connect_request)); | 261 | mei_data2slots(sizeof(struct hbm_client_connect_request)); |
288 | 262 | ||
289 | if (*slots < msg_slots) { | 263 | if (*slots < msg_slots) { |
290 | /* return the cancel routine */ | 264 | /* return the cancel routine */ |
291 | list_del(&cb_pos->list); | 265 | list_del(&cb->list); |
292 | return -EMSGSIZE; | 266 | return -EMSGSIZE; |
293 | } | 267 | } |
294 | 268 | ||
@@ -298,76 +272,17 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, | |||
298 | 272 | ||
299 | if (mei_hbm_cl_connect_req(dev, cl)) { | 273 | if (mei_hbm_cl_connect_req(dev, cl)) { |
300 | cl->status = -ENODEV; | 274 | cl->status = -ENODEV; |
301 | cb_pos->buf_idx = 0; | 275 | cb->buf_idx = 0; |
302 | list_del(&cb_pos->list); | 276 | list_del(&cb->list); |
303 | return -ENODEV; | ||
304 | } else { | ||
305 | list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); | ||
306 | cl->timer_count = MEI_CONNECT_TIMEOUT; | ||
307 | } | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * mei_irq_thread_write_complete - write messages to device. | ||
313 | * | ||
314 | * @dev: the device structure. | ||
315 | * @slots: free slots. | ||
316 | * @cb: callback block. | ||
317 | * @cmpl_list: complete list. | ||
318 | * | ||
319 | * returns 0, OK; otherwise, error. | ||
320 | */ | ||
321 | static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, | ||
322 | struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) | ||
323 | { | ||
324 | struct mei_msg_hdr mei_hdr; | ||
325 | struct mei_cl *cl = cb->cl; | ||
326 | size_t len = cb->request_buffer.size - cb->buf_idx; | ||
327 | u32 msg_slots = mei_data2slots(len); | ||
328 | |||
329 | mei_hdr.host_addr = cl->host_client_id; | ||
330 | mei_hdr.me_addr = cl->me_client_id; | ||
331 | mei_hdr.reserved = 0; | ||
332 | |||
333 | if (*slots >= msg_slots) { | ||
334 | mei_hdr.length = len; | ||
335 | mei_hdr.msg_complete = 1; | ||
336 | /* Split the message only if we can write the whole host buffer */ | ||
337 | } else if (*slots == dev->hbuf_depth) { | ||
338 | msg_slots = *slots; | ||
339 | len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); | ||
340 | mei_hdr.length = len; | ||
341 | mei_hdr.msg_complete = 0; | ||
342 | } else { | ||
343 | /* wait for next time the host buffer is empty */ | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", | ||
348 | cb->request_buffer.size, cb->buf_idx); | ||
349 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | ||
350 | |||
351 | *slots -= msg_slots; | ||
352 | if (mei_write_message(dev, &mei_hdr, | ||
353 | cb->request_buffer.data + cb->buf_idx)) { | ||
354 | cl->status = -ENODEV; | ||
355 | list_move_tail(&cb->list, &cmpl_list->list); | ||
356 | return -ENODEV; | 277 | return -ENODEV; |
357 | } | 278 | } |
358 | 279 | ||
359 | 280 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | |
360 | cl->status = 0; | 281 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
361 | cb->buf_idx += mei_hdr.length; | ||
362 | if (mei_hdr.msg_complete) { | ||
363 | if (mei_cl_flow_ctrl_reduce(cl)) | ||
364 | return -ENODEV; | ||
365 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | ||
366 | } | ||
367 | |||
368 | return 0; | 282 | return 0; |
369 | } | 283 | } |
370 | 284 | ||
285 | |||
371 | /** | 286 | /** |
372 | * mei_irq_read_handler - bottom half read routine after ISR to | 287 | * mei_irq_read_handler - bottom half read routine after ISR to |
373 | * handle the read processing. | 288 | * handle the read processing. |
@@ -481,7 +396,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
481 | { | 396 | { |
482 | 397 | ||
483 | struct mei_cl *cl; | 398 | struct mei_cl *cl; |
484 | struct mei_cl_cb *pos = NULL, *next = NULL; | 399 | struct mei_cl_cb *cb, *next; |
485 | struct mei_cl_cb *list; | 400 | struct mei_cl_cb *list; |
486 | s32 slots; | 401 | s32 slots; |
487 | int ret; | 402 | int ret; |
@@ -498,19 +413,19 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
498 | dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); | 413 | dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); |
499 | 414 | ||
500 | list = &dev->write_waiting_list; | 415 | list = &dev->write_waiting_list; |
501 | list_for_each_entry_safe(pos, next, &list->list, list) { | 416 | list_for_each_entry_safe(cb, next, &list->list, list) { |
502 | cl = pos->cl; | 417 | cl = cb->cl; |
503 | if (cl == NULL) | 418 | if (cl == NULL) |
504 | continue; | 419 | continue; |
505 | 420 | ||
506 | cl->status = 0; | 421 | cl->status = 0; |
507 | list_del(&pos->list); | 422 | list_del(&cb->list); |
508 | if (MEI_WRITING == cl->writing_state && | 423 | if (MEI_WRITING == cl->writing_state && |
509 | pos->fop_type == MEI_FOP_WRITE && | 424 | cb->fop_type == MEI_FOP_WRITE && |
510 | cl != &dev->iamthif_cl) { | 425 | cl != &dev->iamthif_cl) { |
511 | dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); | 426 | dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); |
512 | cl->writing_state = MEI_WRITE_COMPLETE; | 427 | cl->writing_state = MEI_WRITE_COMPLETE; |
513 | list_add_tail(&pos->list, &cmpl_list->list); | 428 | list_add_tail(&cb->list, &cmpl_list->list); |
514 | } | 429 | } |
515 | if (cl == &dev->iamthif_cl) { | 430 | if (cl == &dev->iamthif_cl) { |
516 | dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); | 431 | dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); |
@@ -552,25 +467,23 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
552 | 467 | ||
553 | /* complete control write list CB */ | 468 | /* complete control write list CB */ |
554 | dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); | 469 | dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); |
555 | list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { | 470 | list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) { |
556 | cl = pos->cl; | 471 | cl = cb->cl; |
557 | if (!cl) { | 472 | if (!cl) { |
558 | list_del(&pos->list); | 473 | list_del(&cb->list); |
559 | return -ENODEV; | 474 | return -ENODEV; |
560 | } | 475 | } |
561 | switch (pos->fop_type) { | 476 | switch (cb->fop_type) { |
562 | case MEI_FOP_CLOSE: | 477 | case MEI_FOP_CLOSE: |
563 | /* send disconnect message */ | 478 | /* send disconnect message */ |
564 | ret = _mei_irq_thread_close(dev, &slots, pos, | 479 | ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list); |
565 | cl, cmpl_list); | ||
566 | if (ret) | 480 | if (ret) |
567 | return ret; | 481 | return ret; |
568 | 482 | ||
569 | break; | 483 | break; |
570 | case MEI_FOP_READ: | 484 | case MEI_FOP_READ: |
571 | /* send flow control message */ | 485 | /* send flow control message */ |
572 | ret = _mei_irq_thread_read(dev, &slots, pos, | 486 | ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list); |
573 | cl, cmpl_list); | ||
574 | if (ret) | 487 | if (ret) |
575 | return ret; | 488 | return ret; |
576 | 489 | ||
@@ -579,8 +492,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
579 | /* connect message */ | 492 | /* connect message */ |
580 | if (mei_cl_is_other_connecting(cl)) | 493 | if (mei_cl_is_other_connecting(cl)) |
581 | continue; | 494 | continue; |
582 | ret = _mei_irq_thread_ioctl(dev, &slots, pos, | 495 | ret = mei_cl_irq_ioctl(cl, cb, &slots, cmpl_list); |
583 | cl, cmpl_list); | ||
584 | if (ret) | 496 | if (ret) |
585 | return ret; | 497 | return ret; |
586 | 498 | ||
@@ -593,8 +505,8 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
593 | } | 505 | } |
594 | /* complete write list CB */ | 506 | /* complete write list CB */ |
595 | dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); | 507 | dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); |
596 | list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { | 508 | list_for_each_entry_safe(cb, next, &dev->write_list.list, list) { |
597 | cl = pos->cl; | 509 | cl = cb->cl; |
598 | if (cl == NULL) | 510 | if (cl == NULL) |
599 | continue; | 511 | continue; |
600 | if (mei_cl_flow_ctrl_creds(cl) <= 0) { | 512 | if (mei_cl_flow_ctrl_creds(cl) <= 0) { |
@@ -605,14 +517,13 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
605 | } | 517 | } |
606 | 518 | ||
607 | if (cl == &dev->iamthif_cl) | 519 | if (cl == &dev->iamthif_cl) |
608 | ret = mei_amthif_irq_write_complete(dev, &slots, | 520 | ret = mei_amthif_irq_write_complete(cl, cb, |
609 | pos, cmpl_list); | 521 | &slots, cmpl_list); |
610 | else | 522 | else |
611 | ret = mei_irq_thread_write_complete(dev, &slots, pos, | 523 | ret = mei_cl_irq_write_complete(cl, cb, |
612 | cmpl_list); | 524 | &slots, cmpl_list); |
613 | if (ret) | 525 | if (ret) |
614 | return ret; | 526 | return ret; |
615 | |||
616 | } | 527 | } |
617 | return 0; | 528 | return 0; |
618 | } | 529 | } |