diff options
| -rw-r--r-- | drivers/misc/mei/bus.c | 36 | ||||
| -rw-r--r-- | drivers/misc/mei/client.c | 84 | ||||
| -rw-r--r-- | drivers/misc/mei/client.h | 7 | ||||
| -rw-r--r-- | drivers/misc/mei/debugfs.c | 2 | ||||
| -rw-r--r-- | drivers/misc/mei/init.c | 1 | ||||
| -rw-r--r-- | drivers/misc/mei/interrupt.c | 35 | ||||
| -rw-r--r-- | drivers/misc/mei/main.c | 42 | ||||
| -rw-r--r-- | drivers/misc/mei/mei_dev.h | 10 |
8 files changed, 98 insertions, 119 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index b5385372693d..17ca7e20fb6a 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
| @@ -288,19 +288,20 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
| 288 | 288 | ||
| 289 | mutex_lock(&dev->device_lock); | 289 | mutex_lock(&dev->device_lock); |
| 290 | 290 | ||
| 291 | if (!cl->read_cb) { | 291 | cb = mei_cl_read_cb(cl, NULL); |
| 292 | rets = mei_cl_read_start(cl, length, NULL); | 292 | if (cb) |
| 293 | if (rets < 0) | 293 | goto copy; |
| 294 | goto out; | 294 | |
| 295 | } | 295 | rets = mei_cl_read_start(cl, length, NULL); |
| 296 | if (rets && rets != -EBUSY) | ||
| 297 | goto out; | ||
| 296 | 298 | ||
| 297 | if (cl->reading_state != MEI_READ_COMPLETE && | 299 | if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { |
| 298 | !waitqueue_active(&cl->rx_wait)) { | ||
| 299 | 300 | ||
| 300 | mutex_unlock(&dev->device_lock); | 301 | mutex_unlock(&dev->device_lock); |
| 301 | 302 | ||
| 302 | if (wait_event_interruptible(cl->rx_wait, | 303 | if (wait_event_interruptible(cl->rx_wait, |
| 303 | cl->reading_state == MEI_READ_COMPLETE || | 304 | (!list_empty(&cl->rd_completed)) || |
| 304 | mei_cl_is_transitioning(cl))) { | 305 | mei_cl_is_transitioning(cl))) { |
| 305 | 306 | ||
| 306 | if (signal_pending(current)) | 307 | if (signal_pending(current)) |
| @@ -309,15 +310,20 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
| 309 | } | 310 | } |
| 310 | 311 | ||
| 311 | mutex_lock(&dev->device_lock); | 312 | mutex_lock(&dev->device_lock); |
| 312 | } | ||
| 313 | 313 | ||
| 314 | if (mei_cl_is_transitioning(cl)) { | ||
| 315 | rets = -EBUSY; | ||
| 316 | goto out; | ||
| 317 | } | ||
| 318 | } | ||
| 314 | 319 | ||
| 315 | if (cl->reading_state != MEI_READ_COMPLETE) { | 320 | cb = mei_cl_read_cb(cl, NULL); |
| 321 | if (!cb) { | ||
| 316 | rets = 0; | 322 | rets = 0; |
| 317 | goto out; | 323 | goto out; |
| 318 | } | 324 | } |
| 319 | 325 | ||
| 320 | cb = cl->read_cb; | 326 | copy: |
| 321 | if (cb->status) { | 327 | if (cb->status) { |
| 322 | rets = cb->status; | 328 | rets = cb->status; |
| 323 | goto free; | 329 | goto free; |
| @@ -329,9 +335,6 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) | |||
| 329 | 335 | ||
| 330 | free: | 336 | free: |
| 331 | mei_io_cb_free(cb); | 337 | mei_io_cb_free(cb); |
| 332 | cl->read_cb = NULL; | ||
| 333 | cl->reading_state = MEI_IDLE; | ||
| 334 | |||
| 335 | out: | 338 | out: |
| 336 | mutex_unlock(&dev->device_lock); | 339 | mutex_unlock(&dev->device_lock); |
| 337 | 340 | ||
| @@ -443,7 +446,7 @@ int mei_cl_enable_device(struct mei_cl_device *device) | |||
| 443 | 446 | ||
| 444 | mutex_unlock(&dev->device_lock); | 447 | mutex_unlock(&dev->device_lock); |
| 445 | 448 | ||
| 446 | if (device->event_cb && !cl->read_cb) | 449 | if (device->event_cb) |
| 447 | mei_cl_read_start(device->cl, 0, NULL); | 450 | mei_cl_read_start(device->cl, 0, NULL); |
| 448 | 451 | ||
| 449 | if (!device->ops || !device->ops->enable) | 452 | if (!device->ops || !device->ops->enable) |
| @@ -485,8 +488,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) | |||
| 485 | } | 488 | } |
| 486 | 489 | ||
| 487 | /* Flush queues and remove any pending read */ | 490 | /* Flush queues and remove any pending read */ |
| 488 | mei_cl_flush_queues(cl); | 491 | mei_cl_flush_queues(cl, NULL); |
| 489 | mei_io_cb_free(cl->read_cb); | ||
| 490 | 492 | ||
| 491 | device->event_cb = NULL; | 493 | device->event_cb = NULL; |
| 492 | 494 | ||
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 624bf0182a50..98a5363e1e8a 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
| @@ -458,13 +458,55 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, | |||
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | /** | 460 | /** |
| 461 | * mei_cl_read_cb - find this cl's callback in the read list | ||
| 462 | * for a specific file | ||
| 463 | * | ||
| 464 | * @cl: host client | ||
| 465 | * @fp: file pointer (matching cb file object), may be NULL | ||
| 466 | * | ||
| 467 | * Return: cb on success, NULL if cb is not found | ||
| 468 | */ | ||
| 469 | struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp) | ||
| 470 | { | ||
| 471 | struct mei_cl_cb *cb; | ||
| 472 | |||
| 473 | list_for_each_entry(cb, &cl->rd_completed, list) | ||
| 474 | if (!fp || fp == cb->file_object) | ||
| 475 | return cb; | ||
| 476 | |||
| 477 | return NULL; | ||
| 478 | } | ||
| 479 | |||
| 480 | /** | ||
| 481 | * mei_cl_read_cb_flush - free client's read pending and completed cbs | ||
| 482 | * for a specific file | ||
| 483 | * | ||
| 484 | * @cl: host client | ||
| 485 | * @fp: file pointer (matching cb file object), may be NULL | ||
| 486 | */ | ||
| 487 | void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp) | ||
| 488 | { | ||
| 489 | struct mei_cl_cb *cb, *next; | ||
| 490 | |||
| 491 | list_for_each_entry_safe(cb, next, &cl->rd_completed, list) | ||
| 492 | if (!fp || fp == cb->file_object) | ||
| 493 | mei_io_cb_free(cb); | ||
| 494 | |||
| 495 | |||
| 496 | list_for_each_entry_safe(cb, next, &cl->rd_pending, list) | ||
| 497 | if (!fp || fp == cb->file_object) | ||
| 498 | mei_io_cb_free(cb); | ||
| 499 | } | ||
| 500 | |||
| 501 | /** | ||
| 461 | * mei_cl_flush_queues - flushes queue lists belonging to cl. | 502 | * mei_cl_flush_queues - flushes queue lists belonging to cl. |
| 462 | * | 503 | * |
| 463 | * @cl: host client | 504 | * @cl: host client |
| 505 | * @fp: file pointer (matching cb file object), may be NULL | ||
| 464 | * | 506 | * |
| 465 | * Return: 0 on success, -EINVAL if cl or cl->dev is NULL. | 507 | * Return: 0 on success, -EINVAL if cl or cl->dev is NULL. |
| 466 | */ | 508 | */ |
| 467 | int mei_cl_flush_queues(struct mei_cl *cl) | 509 | int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) |
| 468 | { | 510 | { |
| 469 | struct mei_device *dev; | 511 | struct mei_device *dev; |
| 470 | 512 | ||
| @@ -474,13 +516,15 @@ int mei_cl_flush_queues(struct mei_cl *cl) | |||
| 474 | dev = cl->dev; | 516 | dev = cl->dev; |
| 475 | 517 | ||
| 476 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | 518 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); |
| 477 | mei_io_list_flush(&cl->dev->read_list, cl); | ||
| 478 | mei_io_list_free(&cl->dev->write_list, cl); | 519 | mei_io_list_free(&cl->dev->write_list, cl); |
| 479 | mei_io_list_free(&cl->dev->write_waiting_list, cl); | 520 | mei_io_list_free(&cl->dev->write_waiting_list, cl); |
| 480 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | 521 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); |
| 481 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | 522 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); |
| 482 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); | 523 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); |
| 483 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); | 524 | mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); |
| 525 | |||
| 526 | mei_cl_read_cb_flush(cl, fp); | ||
| 527 | |||
| 484 | return 0; | 528 | return 0; |
| 485 | } | 529 | } |
| 486 | 530 | ||
| @@ -497,9 +541,10 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) | |||
| 497 | init_waitqueue_head(&cl->wait); | 541 | init_waitqueue_head(&cl->wait); |
| 498 | init_waitqueue_head(&cl->rx_wait); | 542 | init_waitqueue_head(&cl->rx_wait); |
| 499 | init_waitqueue_head(&cl->tx_wait); | 543 | init_waitqueue_head(&cl->tx_wait); |
| 544 | INIT_LIST_HEAD(&cl->rd_completed); | ||
| 545 | INIT_LIST_HEAD(&cl->rd_pending); | ||
| 500 | INIT_LIST_HEAD(&cl->link); | 546 | INIT_LIST_HEAD(&cl->link); |
| 501 | INIT_LIST_HEAD(&cl->device_link); | 547 | INIT_LIST_HEAD(&cl->device_link); |
| 502 | cl->reading_state = MEI_IDLE; | ||
| 503 | cl->writing_state = MEI_IDLE; | 548 | cl->writing_state = MEI_IDLE; |
| 504 | cl->dev = dev; | 549 | cl->dev = dev; |
| 505 | } | 550 | } |
| @@ -524,24 +569,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) | |||
| 524 | } | 569 | } |
| 525 | 570 | ||
| 526 | /** | 571 | /** |
| 527 | * mei_cl_find_read_cb - find this cl's callback in the read list | ||
| 528 | * | ||
| 529 | * @cl: host client | ||
| 530 | * | ||
| 531 | * Return: cb on success, NULL on error | ||
| 532 | */ | ||
| 533 | struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) | ||
| 534 | { | ||
| 535 | struct mei_device *dev = cl->dev; | ||
| 536 | struct mei_cl_cb *cb; | ||
| 537 | |||
| 538 | list_for_each_entry(cb, &dev->read_list.list, list) | ||
| 539 | if (mei_cl_cmp_id(cl, cb->cl)) | ||
| 540 | return cb; | ||
| 541 | return NULL; | ||
| 542 | } | ||
| 543 | |||
| 544 | /** | ||
| 545 | * mei_cl_link - allocate host id in the host map | 572 | * mei_cl_link - allocate host id in the host map |
| 546 | * | 573 | * |
| 547 | * @cl: host client | 574 | * @cl: host client |
| @@ -1006,10 +1033,10 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp) | |||
| 1006 | if (!mei_cl_is_connected(cl)) | 1033 | if (!mei_cl_is_connected(cl)) |
| 1007 | return -ENODEV; | 1034 | return -ENODEV; |
| 1008 | 1035 | ||
| 1009 | if (cl->read_cb) { | 1036 | /* HW currently supports only one pending read */ |
| 1010 | cl_dbg(dev, cl, "read is pending.\n"); | 1037 | if (!list_empty(&cl->rd_pending)) |
| 1011 | return -EBUSY; | 1038 | return -EBUSY; |
| 1012 | } | 1039 | |
| 1013 | me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); | 1040 | me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); |
| 1014 | if (!me_cl) { | 1041 | if (!me_cl) { |
| 1015 | cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); | 1042 | cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); |
| @@ -1036,13 +1063,11 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp) | |||
| 1036 | if (rets < 0) | 1063 | if (rets < 0) |
| 1037 | goto out; | 1064 | goto out; |
| 1038 | 1065 | ||
| 1039 | list_add_tail(&cb->list, &dev->read_list.list); | 1066 | list_add_tail(&cb->list, &cl->rd_pending); |
| 1040 | } else { | 1067 | } else { |
| 1041 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 1068 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
| 1042 | } | 1069 | } |
| 1043 | 1070 | ||
| 1044 | cl->read_cb = cb; | ||
| 1045 | |||
| 1046 | out: | 1071 | out: |
| 1047 | cl_dbg(dev, cl, "rpm: autosuspend\n"); | 1072 | cl_dbg(dev, cl, "rpm: autosuspend\n"); |
| 1048 | pm_runtime_mark_last_busy(dev->dev); | 1073 | pm_runtime_mark_last_busy(dev->dev); |
| @@ -1268,9 +1293,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
| 1268 | if (waitqueue_active(&cl->tx_wait)) | 1293 | if (waitqueue_active(&cl->tx_wait)) |
| 1269 | wake_up_interruptible(&cl->tx_wait); | 1294 | wake_up_interruptible(&cl->tx_wait); |
| 1270 | 1295 | ||
| 1271 | } else if (cb->fop_type == MEI_FOP_READ && | 1296 | } else if (cb->fop_type == MEI_FOP_READ) { |
| 1272 | MEI_READING == cl->reading_state) { | 1297 | list_add_tail(&cb->list, &cl->rd_completed); |
| 1273 | cl->reading_state = MEI_READ_COMPLETE; | ||
| 1274 | if (waitqueue_active(&cl->rx_wait)) | 1298 | if (waitqueue_active(&cl->rx_wait)) |
| 1275 | wake_up_interruptible(&cl->rx_wait); | 1299 | wake_up_interruptible(&cl->rx_wait); |
| 1276 | else | 1300 | else |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index c3d0e200a642..eb02f34b2fe0 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
| @@ -77,11 +77,12 @@ int mei_cl_unlink(struct mei_cl *cl); | |||
| 77 | 77 | ||
| 78 | struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id); | 78 | struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id); |
| 79 | 79 | ||
| 80 | int mei_cl_flush_queues(struct mei_cl *cl); | 80 | struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, |
| 81 | struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl); | 81 | const struct file *fp); |
| 82 | 82 | void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp); | |
| 83 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, | 83 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, |
| 84 | enum mei_cb_file_ops type, struct file *fp); | 84 | enum mei_cb_file_ops type, struct file *fp); |
| 85 | int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp); | ||
| 85 | 86 | ||
| 86 | int mei_cl_flow_ctrl_creds(struct mei_cl *cl); | 87 | int mei_cl_flow_ctrl_creds(struct mei_cl *cl); |
| 87 | 88 | ||
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index 50fc6635fab1..d9cd7e6ee484 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c | |||
| @@ -117,7 +117,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf, | |||
| 117 | pos += scnprintf(buf + pos, bufsz - pos, | 117 | pos += scnprintf(buf + pos, bufsz - pos, |
| 118 | "%2d|%2d|%4d|%5d|%2d|%2d|\n", | 118 | "%2d|%2d|%4d|%5d|%2d|%2d|\n", |
| 119 | i, cl->me_client_id, cl->host_client_id, cl->state, | 119 | i, cl->me_client_id, cl->host_client_id, cl->state, |
| 120 | cl->reading_state, cl->writing_state); | 120 | !list_empty(&cl->rd_completed), cl->writing_state); |
| 121 | i++; | 121 | i++; |
| 122 | } | 122 | } |
| 123 | out: | 123 | out: |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 106c054f573f..4596401888e5 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
| @@ -395,7 +395,6 @@ void mei_device_init(struct mei_device *dev, | |||
| 395 | dev->dev_state = MEI_DEV_INITIALIZING; | 395 | dev->dev_state = MEI_DEV_INITIALIZING; |
| 396 | dev->reset_count = 0; | 396 | dev->reset_count = 0; |
| 397 | 397 | ||
| 398 | mei_io_list_init(&dev->read_list); | ||
| 399 | mei_io_list_init(&dev->write_list); | 398 | mei_io_list_init(&dev->write_list); |
| 400 | mei_io_list_init(&dev->write_waiting_list); | 399 | mei_io_list_init(&dev->write_waiting_list); |
| 401 | mei_io_list_init(&dev->ctrl_wr_list); | 400 | mei_io_list_init(&dev->ctrl_wr_list); |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 1e2f3c774853..3f23629759db 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
| @@ -68,18 +68,6 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl, | |||
| 68 | return cl->host_client_id == mei_hdr->host_addr && | 68 | return cl->host_client_id == mei_hdr->host_addr && |
| 69 | cl->me_client_id == mei_hdr->me_addr; | 69 | cl->me_client_id == mei_hdr->me_addr; |
| 70 | } | 70 | } |
| 71 | /** | ||
| 72 | * mei_cl_is_reading - checks if the client is in reading state | ||
| 73 | * | ||
| 74 | * @cl: mei client | ||
| 75 | * | ||
| 76 | * Return: true if the client is reading | ||
| 77 | */ | ||
| 78 | static bool mei_cl_is_reading(struct mei_cl *cl) | ||
| 79 | { | ||
| 80 | return cl->state == MEI_FILE_CONNECTED && | ||
| 81 | cl->reading_state != MEI_READ_COMPLETE; | ||
| 82 | } | ||
| 83 | 71 | ||
| 84 | /** | 72 | /** |
| 85 | * mei_irq_discard_msg - discard received message | 73 | * mei_irq_discard_msg - discard received message |
| @@ -116,24 +104,18 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
| 116 | struct mei_cl_cb *cb; | 104 | struct mei_cl_cb *cb; |
| 117 | unsigned char *buffer = NULL; | 105 | unsigned char *buffer = NULL; |
| 118 | 106 | ||
| 119 | list_for_each_entry(cb, &dev->read_list.list, list) { | 107 | cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); |
| 120 | if (cl == cb->cl) | 108 | if (!cb) { |
| 121 | break; | 109 | cl_err(dev, cl, "pending read cb not found\n"); |
| 122 | } | ||
| 123 | |||
| 124 | if (&cb->list == &dev->read_list.list) { | ||
| 125 | dev_err(dev->dev, "no reader found\n"); | ||
| 126 | goto out; | 110 | goto out; |
| 127 | } | 111 | } |
| 128 | 112 | ||
| 129 | if (!mei_cl_is_reading(cl)) { | 113 | if (cl->state != MEI_FILE_CONNECTED) { |
| 130 | cl_err(dev, cl, "cl is not reading state=%d reading state=%d\n", | 114 | cl_dbg(dev, cl, "not connected\n"); |
| 131 | cl->state, cl->reading_state); | 115 | cb->status = -ENODEV; |
| 132 | goto out; | 116 | goto out; |
| 133 | } | 117 | } |
| 134 | 118 | ||
| 135 | cl->reading_state = MEI_READING; | ||
| 136 | |||
| 137 | if (cb->buf.size == 0 || cb->buf.data == NULL) { | 119 | if (cb->buf.size == 0 || cb->buf.data == NULL) { |
| 138 | cl_err(dev, cl, "response buffer is not allocated.\n"); | 120 | cl_err(dev, cl, "response buffer is not allocated.\n"); |
| 139 | list_move_tail(&cb->list, &complete_list->list); | 121 | list_move_tail(&cb->list, &complete_list->list); |
| @@ -163,8 +145,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
| 163 | 145 | ||
| 164 | if (mei_hdr->msg_complete) { | 146 | if (mei_hdr->msg_complete) { |
| 165 | cb->read_time = jiffies; | 147 | cb->read_time = jiffies; |
| 166 | cl_dbg(dev, cl, "completed read length = %lu\n", | 148 | cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx); |
| 167 | cb->buf_idx); | ||
| 168 | list_move_tail(&cb->list, &complete_list->list); | 149 | list_move_tail(&cb->list, &complete_list->list); |
| 169 | } | 150 | } |
| 170 | 151 | ||
| @@ -281,7 +262,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
| 281 | return ret; | 262 | return ret; |
| 282 | } | 263 | } |
| 283 | 264 | ||
| 284 | list_move_tail(&cb->list, &dev->read_list.list); | 265 | list_move_tail(&cb->list, &cl->rd_pending); |
| 285 | 266 | ||
| 286 | return 0; | 267 | return 0; |
| 287 | } | 268 | } |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index c34853be963f..d80867e0d803 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
| @@ -112,14 +112,11 @@ static int mei_release(struct inode *inode, struct file *file) | |||
| 112 | cl_dbg(dev, cl, "disconnecting\n"); | 112 | cl_dbg(dev, cl, "disconnecting\n"); |
| 113 | rets = mei_cl_disconnect(cl); | 113 | rets = mei_cl_disconnect(cl); |
| 114 | } | 114 | } |
| 115 | mei_cl_flush_queues(cl); | 115 | mei_cl_flush_queues(cl, file); |
| 116 | cl_dbg(dev, cl, "removing\n"); | 116 | cl_dbg(dev, cl, "removing\n"); |
| 117 | 117 | ||
| 118 | mei_cl_unlink(cl); | 118 | mei_cl_unlink(cl); |
| 119 | 119 | ||
| 120 | mei_io_cb_free(cl->read_cb); | ||
| 121 | cl->read_cb = NULL; | ||
| 122 | |||
| 123 | file->private_data = NULL; | 120 | file->private_data = NULL; |
| 124 | 121 | ||
| 125 | kfree(cl); | 122 | kfree(cl); |
| @@ -143,8 +140,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
| 143 | size_t length, loff_t *offset) | 140 | size_t length, loff_t *offset) |
| 144 | { | 141 | { |
| 145 | struct mei_cl *cl = file->private_data; | 142 | struct mei_cl *cl = file->private_data; |
| 146 | struct mei_cl_cb *cb = NULL; | ||
| 147 | struct mei_device *dev; | 143 | struct mei_device *dev; |
| 144 | struct mei_cl_cb *cb = NULL; | ||
| 148 | int rets; | 145 | int rets; |
| 149 | int err; | 146 | int err; |
| 150 | 147 | ||
| @@ -171,7 +168,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
| 171 | goto out; | 168 | goto out; |
| 172 | } | 169 | } |
| 173 | 170 | ||
| 174 | cb = cl->read_cb; | 171 | cb = mei_cl_read_cb(cl, file); |
| 175 | if (cb) { | 172 | if (cb) { |
| 176 | /* read what left */ | 173 | /* read what left */ |
| 177 | if (cb->buf_idx > *offset) | 174 | if (cb->buf_idx > *offset) |
| @@ -196,9 +193,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
| 196 | goto out; | 193 | goto out; |
| 197 | } | 194 | } |
| 198 | 195 | ||
| 199 | if (MEI_READ_COMPLETE != cl->reading_state && | 196 | if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { |
| 200 | !waitqueue_active(&cl->rx_wait)) { | ||
| 201 | |||
| 202 | if (file->f_flags & O_NONBLOCK) { | 197 | if (file->f_flags & O_NONBLOCK) { |
| 203 | rets = -EAGAIN; | 198 | rets = -EAGAIN; |
| 204 | goto out; | 199 | goto out; |
| @@ -207,7 +202,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
| 207 | mutex_unlock(&dev->device_lock); | 202 | mutex_unlock(&dev->device_lock); |
| 208 | 203 | ||
| 209 | if (wait_event_interruptible(cl->rx_wait, | 204 | if (wait_event_interruptible(cl->rx_wait, |
| 210 | MEI_READ_COMPLETE == cl->reading_state || | 205 | (!list_empty(&cl->rd_completed)) || |
| 211 | mei_cl_is_transitioning(cl))) { | 206 | mei_cl_is_transitioning(cl))) { |
| 212 | 207 | ||
| 213 | if (signal_pending(current)) | 208 | if (signal_pending(current)) |
| @@ -222,14 +217,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
| 222 | } | 217 | } |
| 223 | } | 218 | } |
| 224 | 219 | ||
| 225 | cb = cl->read_cb; | 220 | cb = mei_cl_read_cb(cl, file); |
| 226 | |||
| 227 | if (!cb) { | 221 | if (!cb) { |
| 228 | rets = -ENODEV; | ||
| 229 | goto out; | ||
| 230 | } | ||
| 231 | |||
| 232 | if (cl->reading_state != MEI_READ_COMPLETE) { | ||
| 233 | rets = 0; | 222 | rets = 0; |
| 234 | goto out; | 223 | goto out; |
| 235 | } | 224 | } |
| @@ -266,9 +255,7 @@ copy_buffer: | |||
| 266 | 255 | ||
| 267 | free: | 256 | free: |
| 268 | mei_io_cb_free(cb); | 257 | mei_io_cb_free(cb); |
| 269 | cl->read_cb = NULL; | ||
| 270 | 258 | ||
| 271 | cl->reading_state = MEI_IDLE; | ||
| 272 | out: | 259 | out: |
| 273 | dev_dbg(dev->dev, "end mei read rets= %d\n", rets); | 260 | dev_dbg(dev->dev, "end mei read rets= %d\n", rets); |
| 274 | mutex_unlock(&dev->device_lock); | 261 | mutex_unlock(&dev->device_lock); |
| @@ -335,8 +322,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
| 335 | timeout = write_cb->read_time + | 322 | timeout = write_cb->read_time + |
| 336 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); | 323 | mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); |
| 337 | 324 | ||
| 338 | if (time_after(jiffies, timeout) || | 325 | if (time_after(jiffies, timeout)) { |
| 339 | cl->reading_state == MEI_READ_COMPLETE) { | ||
| 340 | *offset = 0; | 326 | *offset = 0; |
| 341 | mei_io_cb_free(write_cb); | 327 | mei_io_cb_free(write_cb); |
| 342 | write_cb = NULL; | 328 | write_cb = NULL; |
| @@ -344,19 +330,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
| 344 | } | 330 | } |
| 345 | } | 331 | } |
| 346 | 332 | ||
| 347 | /* free entry used in read */ | 333 | *offset = 0; |
| 348 | if (cl->reading_state == MEI_READ_COMPLETE) { | ||
| 349 | *offset = 0; | ||
| 350 | write_cb = mei_cl_find_read_cb(cl); | ||
| 351 | if (write_cb) { | ||
| 352 | mei_io_cb_free(write_cb); | ||
| 353 | write_cb = NULL; | ||
| 354 | cl->read_cb = NULL; | ||
| 355 | cl->reading_state = MEI_IDLE; | ||
| 356 | } | ||
| 357 | } else if (cl->reading_state == MEI_IDLE) | ||
| 358 | *offset = 0; | ||
| 359 | |||
| 360 | write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); | 334 | write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); |
| 361 | if (!write_cb) { | 335 | if (!write_cb) { |
| 362 | rets = -ENOMEM; | 336 | rets = -ENOMEM; |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 1a0f6e9588b6..f066ecd71939 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
| @@ -231,9 +231,9 @@ struct mei_cl_cb { | |||
| 231 | * @me_client_id: me/fw id | 231 | * @me_client_id: me/fw id |
| 232 | * @mei_flow_ctrl_creds: transmit flow credentials | 232 | * @mei_flow_ctrl_creds: transmit flow credentials |
| 233 | * @timer_count: watchdog timer for operation completion | 233 | * @timer_count: watchdog timer for operation completion |
| 234 | * @reading_state: state of the rx | ||
| 235 | * @writing_state: state of the tx | 234 | * @writing_state: state of the tx |
| 236 | * @read_cb: current pending reading callback | 235 | * @rd_pending: pending read credits |
| 236 | * @rd_completed: completed read | ||
| 237 | * | 237 | * |
| 238 | * @device: device on the mei client bus | 238 | * @device: device on the mei client bus |
| 239 | * @device_link: link to bus clients | 239 | * @device_link: link to bus clients |
| @@ -251,9 +251,9 @@ struct mei_cl { | |||
| 251 | u8 me_client_id; | 251 | u8 me_client_id; |
| 252 | u8 mei_flow_ctrl_creds; | 252 | u8 mei_flow_ctrl_creds; |
| 253 | u8 timer_count; | 253 | u8 timer_count; |
| 254 | enum mei_file_transaction_states reading_state; | ||
| 255 | enum mei_file_transaction_states writing_state; | 254 | enum mei_file_transaction_states writing_state; |
| 256 | struct mei_cl_cb *read_cb; | 255 | struct list_head rd_pending; |
| 256 | struct list_head rd_completed; | ||
| 257 | 257 | ||
| 258 | /* MEI CL bus data */ | 258 | /* MEI CL bus data */ |
| 259 | struct mei_cl_device *device; | 259 | struct mei_cl_device *device; |
| @@ -425,7 +425,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); | |||
| 425 | * @cdev : character device | 425 | * @cdev : character device |
| 426 | * @minor : minor number allocated for device | 426 | * @minor : minor number allocated for device |
| 427 | * | 427 | * |
| 428 | * @read_list : read completion list | ||
| 429 | * @write_list : write pending list | 428 | * @write_list : write pending list |
| 430 | * @write_waiting_list : write completion list | 429 | * @write_waiting_list : write completion list |
| 431 | * @ctrl_wr_list : pending control write list | 430 | * @ctrl_wr_list : pending control write list |
| @@ -501,7 +500,6 @@ struct mei_device { | |||
| 501 | struct cdev cdev; | 500 | struct cdev cdev; |
| 502 | int minor; | 501 | int minor; |
| 503 | 502 | ||
| 504 | struct mei_cl_cb read_list; | ||
| 505 | struct mei_cl_cb write_list; | 503 | struct mei_cl_cb write_list; |
| 506 | struct mei_cl_cb write_waiting_list; | 504 | struct mei_cl_cb write_waiting_list; |
| 507 | struct mei_cl_cb ctrl_wr_list; | 505 | struct mei_cl_cb ctrl_wr_list; |
