diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2015-02-10 03:39:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-01 22:37:00 -0500 |
commit | a9bed61053af13c0768f82c9d1c8793515dd067c (patch) | |
tree | 3beb3a01fbfc4c8cc1d73c18a220478ad5683cd8 /drivers/misc | |
parent | 928fa6664b362aad70c16f04483414f60743e15e (diff) |
mei: allow read concurrency
Replace clunky read state machine with read stack
implemented as per client read list, this is important
mostly for mei drivers with unsolicited reads
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc')
-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; |