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>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
928fa6664b
commit
a9bed61053
@@ -288,19 +288,20 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
|
|||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
if (!cl->read_cb) {
|
cb = mei_cl_read_cb(cl, NULL);
|
||||||
rets = mei_cl_read_start(cl, length, NULL);
|
if (cb)
|
||||||
if (rets < 0)
|
goto copy;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cl->reading_state != MEI_READ_COMPLETE &&
|
rets = mei_cl_read_start(cl, length, NULL);
|
||||||
!waitqueue_active(&cl->rx_wait)) {
|
if (rets && rets != -EBUSY)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
|
||||||
|
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
if (wait_event_interruptible(cl->rx_wait,
|
if (wait_event_interruptible(cl->rx_wait,
|
||||||
cl->reading_state == MEI_READ_COMPLETE ||
|
(!list_empty(&cl->rd_completed)) ||
|
||||||
mei_cl_is_transitioning(cl))) {
|
mei_cl_is_transitioning(cl))) {
|
||||||
|
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
@@ -309,15 +310,20 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
|
if (mei_cl_is_transitioning(cl)) {
|
||||||
|
rets = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cb = mei_cl_read_cb(cl, NULL);
|
||||||
if (cl->reading_state != MEI_READ_COMPLETE) {
|
if (!cb) {
|
||||||
rets = 0;
|
rets = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cb = cl->read_cb;
|
copy:
|
||||||
if (cb->status) {
|
if (cb->status) {
|
||||||
rets = cb->status;
|
rets = cb->status;
|
||||||
goto free;
|
goto free;
|
||||||
@@ -329,9 +335,6 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
|
|||||||
|
|
||||||
free:
|
free:
|
||||||
mei_io_cb_free(cb);
|
mei_io_cb_free(cb);
|
||||||
cl->read_cb = NULL;
|
|
||||||
cl->reading_state = MEI_IDLE;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
@@ -443,7 +446,7 @@ int mei_cl_enable_device(struct mei_cl_device *device)
|
|||||||
|
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
if (device->event_cb && !cl->read_cb)
|
if (device->event_cb)
|
||||||
mei_cl_read_start(device->cl, 0, NULL);
|
mei_cl_read_start(device->cl, 0, NULL);
|
||||||
|
|
||||||
if (!device->ops || !device->ops->enable)
|
if (!device->ops || !device->ops->enable)
|
||||||
@@ -485,8 +488,7 @@ int mei_cl_disable_device(struct mei_cl_device *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Flush queues and remove any pending read */
|
/* Flush queues and remove any pending read */
|
||||||
mei_cl_flush_queues(cl);
|
mei_cl_flush_queues(cl, NULL);
|
||||||
mei_io_cb_free(cl->read_cb);
|
|
||||||
|
|
||||||
device->event_cb = NULL;
|
device->event_cb = NULL;
|
||||||
|
|
||||||
|
@@ -457,14 +457,56 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
|
|||||||
return cb;
|
return cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_cl_read_cb - find this cl's callback in the read list
|
||||||
|
* for a specific file
|
||||||
|
*
|
||||||
|
* @cl: host client
|
||||||
|
* @fp: file pointer (matching cb file object), may be NULL
|
||||||
|
*
|
||||||
|
* Return: cb on success, NULL if cb is not found
|
||||||
|
*/
|
||||||
|
struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp)
|
||||||
|
{
|
||||||
|
struct mei_cl_cb *cb;
|
||||||
|
|
||||||
|
list_for_each_entry(cb, &cl->rd_completed, list)
|
||||||
|
if (!fp || fp == cb->file_object)
|
||||||
|
return cb;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_cl_read_cb_flush - free client's read pending and completed cbs
|
||||||
|
* for a specific file
|
||||||
|
*
|
||||||
|
* @cl: host client
|
||||||
|
* @fp: file pointer (matching cb file object), may be NULL
|
||||||
|
*/
|
||||||
|
void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp)
|
||||||
|
{
|
||||||
|
struct mei_cl_cb *cb, *next;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(cb, next, &cl->rd_completed, list)
|
||||||
|
if (!fp || fp == cb->file_object)
|
||||||
|
mei_io_cb_free(cb);
|
||||||
|
|
||||||
|
|
||||||
|
list_for_each_entry_safe(cb, next, &cl->rd_pending, list)
|
||||||
|
if (!fp || fp == cb->file_object)
|
||||||
|
mei_io_cb_free(cb);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_cl_flush_queues - flushes queue lists belonging to cl.
|
* mei_cl_flush_queues - flushes queue lists belonging to cl.
|
||||||
*
|
*
|
||||||
* @cl: host client
|
* @cl: host client
|
||||||
|
* @fp: file pointer (matching cb file object), may be NULL
|
||||||
*
|
*
|
||||||
* Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
|
* Return: 0 on success, -EINVAL if cl or cl->dev is NULL.
|
||||||
*/
|
*/
|
||||||
int mei_cl_flush_queues(struct mei_cl *cl)
|
int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
|
||||||
{
|
{
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
|
|
||||||
@@ -474,13 +516,15 @@ int mei_cl_flush_queues(struct mei_cl *cl)
|
|||||||
dev = cl->dev;
|
dev = cl->dev;
|
||||||
|
|
||||||
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
|
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
|
||||||
mei_io_list_flush(&cl->dev->read_list, cl);
|
|
||||||
mei_io_list_free(&cl->dev->write_list, cl);
|
mei_io_list_free(&cl->dev->write_list, cl);
|
||||||
mei_io_list_free(&cl->dev->write_waiting_list, cl);
|
mei_io_list_free(&cl->dev->write_waiting_list, cl);
|
||||||
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
|
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
|
||||||
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
|
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
|
||||||
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
|
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
|
||||||
mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
|
mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl);
|
||||||
|
|
||||||
|
mei_cl_read_cb_flush(cl, fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,9 +541,10 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
|
|||||||
init_waitqueue_head(&cl->wait);
|
init_waitqueue_head(&cl->wait);
|
||||||
init_waitqueue_head(&cl->rx_wait);
|
init_waitqueue_head(&cl->rx_wait);
|
||||||
init_waitqueue_head(&cl->tx_wait);
|
init_waitqueue_head(&cl->tx_wait);
|
||||||
|
INIT_LIST_HEAD(&cl->rd_completed);
|
||||||
|
INIT_LIST_HEAD(&cl->rd_pending);
|
||||||
INIT_LIST_HEAD(&cl->link);
|
INIT_LIST_HEAD(&cl->link);
|
||||||
INIT_LIST_HEAD(&cl->device_link);
|
INIT_LIST_HEAD(&cl->device_link);
|
||||||
cl->reading_state = MEI_IDLE;
|
|
||||||
cl->writing_state = MEI_IDLE;
|
cl->writing_state = MEI_IDLE;
|
||||||
cl->dev = dev;
|
cl->dev = dev;
|
||||||
}
|
}
|
||||||
@@ -523,24 +568,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
|
|||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* mei_cl_find_read_cb - find this cl's callback in the read list
|
|
||||||
*
|
|
||||||
* @cl: host client
|
|
||||||
*
|
|
||||||
* Return: cb on success, NULL on error
|
|
||||||
*/
|
|
||||||
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
|
|
||||||
{
|
|
||||||
struct mei_device *dev = cl->dev;
|
|
||||||
struct mei_cl_cb *cb;
|
|
||||||
|
|
||||||
list_for_each_entry(cb, &dev->read_list.list, list)
|
|
||||||
if (mei_cl_cmp_id(cl, cb->cl))
|
|
||||||
return cb;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_cl_link - allocate host id in the host map
|
* mei_cl_link - allocate host id in the host map
|
||||||
*
|
*
|
||||||
@@ -1006,10 +1033,10 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp)
|
|||||||
if (!mei_cl_is_connected(cl))
|
if (!mei_cl_is_connected(cl))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (cl->read_cb) {
|
/* HW currently supports only one pending read */
|
||||||
cl_dbg(dev, cl, "read is pending.\n");
|
if (!list_empty(&cl->rd_pending))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
|
||||||
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
|
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
|
||||||
if (!me_cl) {
|
if (!me_cl) {
|
||||||
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
|
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)
|
|||||||
if (rets < 0)
|
if (rets < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
list_add_tail(&cb->list, &dev->read_list.list);
|
list_add_tail(&cb->list, &cl->rd_pending);
|
||||||
} else {
|
} else {
|
||||||
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
|
list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
|
||||||
}
|
}
|
||||||
|
|
||||||
cl->read_cb = cb;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
cl_dbg(dev, cl, "rpm: autosuspend\n");
|
||||||
pm_runtime_mark_last_busy(dev->dev);
|
pm_runtime_mark_last_busy(dev->dev);
|
||||||
@@ -1268,9 +1293,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
|
|||||||
if (waitqueue_active(&cl->tx_wait))
|
if (waitqueue_active(&cl->tx_wait))
|
||||||
wake_up_interruptible(&cl->tx_wait);
|
wake_up_interruptible(&cl->tx_wait);
|
||||||
|
|
||||||
} else if (cb->fop_type == MEI_FOP_READ &&
|
} else if (cb->fop_type == MEI_FOP_READ) {
|
||||||
MEI_READING == cl->reading_state) {
|
list_add_tail(&cb->list, &cl->rd_completed);
|
||||||
cl->reading_state = MEI_READ_COMPLETE;
|
|
||||||
if (waitqueue_active(&cl->rx_wait))
|
if (waitqueue_active(&cl->rx_wait))
|
||||||
wake_up_interruptible(&cl->rx_wait);
|
wake_up_interruptible(&cl->rx_wait);
|
||||||
else
|
else
|
||||||
|
@@ -77,11 +77,12 @@ int mei_cl_unlink(struct mei_cl *cl);
|
|||||||
|
|
||||||
struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id);
|
struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id);
|
||||||
|
|
||||||
int mei_cl_flush_queues(struct mei_cl *cl);
|
struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl,
|
||||||
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
|
const struct file *fp);
|
||||||
|
void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
|
||||||
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
|
struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
|
||||||
enum mei_cb_file_ops type, struct file *fp);
|
enum mei_cb_file_ops type, struct file *fp);
|
||||||
|
int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
|
||||||
|
|
||||||
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
|
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);
|
||||||
|
|
||||||
|
@@ -117,7 +117,7 @@ static ssize_t mei_dbgfs_read_active(struct file *fp, char __user *ubuf,
|
|||||||
pos += scnprintf(buf + pos, bufsz - pos,
|
pos += scnprintf(buf + pos, bufsz - pos,
|
||||||
"%2d|%2d|%4d|%5d|%2d|%2d|\n",
|
"%2d|%2d|%4d|%5d|%2d|%2d|\n",
|
||||||
i, cl->me_client_id, cl->host_client_id, cl->state,
|
i, cl->me_client_id, cl->host_client_id, cl->state,
|
||||||
cl->reading_state, cl->writing_state);
|
!list_empty(&cl->rd_completed), cl->writing_state);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@@ -395,7 +395,6 @@ void mei_device_init(struct mei_device *dev,
|
|||||||
dev->dev_state = MEI_DEV_INITIALIZING;
|
dev->dev_state = MEI_DEV_INITIALIZING;
|
||||||
dev->reset_count = 0;
|
dev->reset_count = 0;
|
||||||
|
|
||||||
mei_io_list_init(&dev->read_list);
|
|
||||||
mei_io_list_init(&dev->write_list);
|
mei_io_list_init(&dev->write_list);
|
||||||
mei_io_list_init(&dev->write_waiting_list);
|
mei_io_list_init(&dev->write_waiting_list);
|
||||||
mei_io_list_init(&dev->ctrl_wr_list);
|
mei_io_list_init(&dev->ctrl_wr_list);
|
||||||
|
@@ -68,18 +68,6 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
|
|||||||
return cl->host_client_id == mei_hdr->host_addr &&
|
return cl->host_client_id == mei_hdr->host_addr &&
|
||||||
cl->me_client_id == mei_hdr->me_addr;
|
cl->me_client_id == mei_hdr->me_addr;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* mei_cl_is_reading - checks if the client is in reading state
|
|
||||||
*
|
|
||||||
* @cl: mei client
|
|
||||||
*
|
|
||||||
* Return: true if the client is reading
|
|
||||||
*/
|
|
||||||
static bool mei_cl_is_reading(struct mei_cl *cl)
|
|
||||||
{
|
|
||||||
return cl->state == MEI_FILE_CONNECTED &&
|
|
||||||
cl->reading_state != MEI_READ_COMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_irq_discard_msg - discard received message
|
* mei_irq_discard_msg - discard received message
|
||||||
@@ -116,24 +104,18 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
|
|||||||
struct mei_cl_cb *cb;
|
struct mei_cl_cb *cb;
|
||||||
unsigned char *buffer = NULL;
|
unsigned char *buffer = NULL;
|
||||||
|
|
||||||
list_for_each_entry(cb, &dev->read_list.list, list) {
|
cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
|
||||||
if (cl == cb->cl)
|
if (!cb) {
|
||||||
break;
|
cl_err(dev, cl, "pending read cb not found\n");
|
||||||
}
|
|
||||||
|
|
||||||
if (&cb->list == &dev->read_list.list) {
|
|
||||||
dev_err(dev->dev, "no reader found\n");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mei_cl_is_reading(cl)) {
|
if (cl->state != MEI_FILE_CONNECTED) {
|
||||||
cl_err(dev, cl, "cl is not reading state=%d reading state=%d\n",
|
cl_dbg(dev, cl, "not connected\n");
|
||||||
cl->state, cl->reading_state);
|
cb->status = -ENODEV;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl->reading_state = MEI_READING;
|
|
||||||
|
|
||||||
if (cb->buf.size == 0 || cb->buf.data == NULL) {
|
if (cb->buf.size == 0 || cb->buf.data == NULL) {
|
||||||
cl_err(dev, cl, "response buffer is not allocated.\n");
|
cl_err(dev, cl, "response buffer is not allocated.\n");
|
||||||
list_move_tail(&cb->list, &complete_list->list);
|
list_move_tail(&cb->list, &complete_list->list);
|
||||||
@@ -163,8 +145,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
|
|||||||
|
|
||||||
if (mei_hdr->msg_complete) {
|
if (mei_hdr->msg_complete) {
|
||||||
cb->read_time = jiffies;
|
cb->read_time = jiffies;
|
||||||
cl_dbg(dev, cl, "completed read length = %lu\n",
|
cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx);
|
||||||
cb->buf_idx);
|
|
||||||
list_move_tail(&cb->list, &complete_list->list);
|
list_move_tail(&cb->list, &complete_list->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,7 +262,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_move_tail(&cb->list, &dev->read_list.list);
|
list_move_tail(&cb->list, &cl->rd_pending);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -112,14 +112,11 @@ static int mei_release(struct inode *inode, struct file *file)
|
|||||||
cl_dbg(dev, cl, "disconnecting\n");
|
cl_dbg(dev, cl, "disconnecting\n");
|
||||||
rets = mei_cl_disconnect(cl);
|
rets = mei_cl_disconnect(cl);
|
||||||
}
|
}
|
||||||
mei_cl_flush_queues(cl);
|
mei_cl_flush_queues(cl, file);
|
||||||
cl_dbg(dev, cl, "removing\n");
|
cl_dbg(dev, cl, "removing\n");
|
||||||
|
|
||||||
mei_cl_unlink(cl);
|
mei_cl_unlink(cl);
|
||||||
|
|
||||||
mei_io_cb_free(cl->read_cb);
|
|
||||||
cl->read_cb = NULL;
|
|
||||||
|
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
|
|
||||||
kfree(cl);
|
kfree(cl);
|
||||||
@@ -143,8 +140,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||||||
size_t length, loff_t *offset)
|
size_t length, loff_t *offset)
|
||||||
{
|
{
|
||||||
struct mei_cl *cl = file->private_data;
|
struct mei_cl *cl = file->private_data;
|
||||||
struct mei_cl_cb *cb = NULL;
|
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
|
struct mei_cl_cb *cb = NULL;
|
||||||
int rets;
|
int rets;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -171,7 +168,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cb = cl->read_cb;
|
cb = mei_cl_read_cb(cl, file);
|
||||||
if (cb) {
|
if (cb) {
|
||||||
/* read what left */
|
/* read what left */
|
||||||
if (cb->buf_idx > *offset)
|
if (cb->buf_idx > *offset)
|
||||||
@@ -196,9 +193,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MEI_READ_COMPLETE != cl->reading_state &&
|
if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
|
||||||
!waitqueue_active(&cl->rx_wait)) {
|
|
||||||
|
|
||||||
if (file->f_flags & O_NONBLOCK) {
|
if (file->f_flags & O_NONBLOCK) {
|
||||||
rets = -EAGAIN;
|
rets = -EAGAIN;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -207,7 +202,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
if (wait_event_interruptible(cl->rx_wait,
|
if (wait_event_interruptible(cl->rx_wait,
|
||||||
MEI_READ_COMPLETE == cl->reading_state ||
|
(!list_empty(&cl->rd_completed)) ||
|
||||||
mei_cl_is_transitioning(cl))) {
|
mei_cl_is_transitioning(cl))) {
|
||||||
|
|
||||||
if (signal_pending(current))
|
if (signal_pending(current))
|
||||||
@@ -222,14 +217,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cb = cl->read_cb;
|
cb = mei_cl_read_cb(cl, file);
|
||||||
|
|
||||||
if (!cb) {
|
if (!cb) {
|
||||||
rets = -ENODEV;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cl->reading_state != MEI_READ_COMPLETE) {
|
|
||||||
rets = 0;
|
rets = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -266,9 +255,7 @@ copy_buffer:
|
|||||||
|
|
||||||
free:
|
free:
|
||||||
mei_io_cb_free(cb);
|
mei_io_cb_free(cb);
|
||||||
cl->read_cb = NULL;
|
|
||||||
|
|
||||||
cl->reading_state = MEI_IDLE;
|
|
||||||
out:
|
out:
|
||||||
dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
|
dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
@@ -335,8 +322,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
|||||||
timeout = write_cb->read_time +
|
timeout = write_cb->read_time +
|
||||||
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
|
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
|
||||||
|
|
||||||
if (time_after(jiffies, timeout) ||
|
if (time_after(jiffies, timeout)) {
|
||||||
cl->reading_state == MEI_READ_COMPLETE) {
|
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
mei_io_cb_free(write_cb);
|
mei_io_cb_free(write_cb);
|
||||||
write_cb = NULL;
|
write_cb = NULL;
|
||||||
@@ -344,19 +330,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free entry used in read */
|
|
||||||
if (cl->reading_state == MEI_READ_COMPLETE) {
|
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
write_cb = mei_cl_find_read_cb(cl);
|
|
||||||
if (write_cb) {
|
|
||||||
mei_io_cb_free(write_cb);
|
|
||||||
write_cb = NULL;
|
|
||||||
cl->read_cb = NULL;
|
|
||||||
cl->reading_state = MEI_IDLE;
|
|
||||||
}
|
|
||||||
} else if (cl->reading_state == MEI_IDLE)
|
|
||||||
*offset = 0;
|
|
||||||
|
|
||||||
write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
|
write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
|
||||||
if (!write_cb) {
|
if (!write_cb) {
|
||||||
rets = -ENOMEM;
|
rets = -ENOMEM;
|
||||||
|
@@ -231,9 +231,9 @@ struct mei_cl_cb {
|
|||||||
* @me_client_id: me/fw id
|
* @me_client_id: me/fw id
|
||||||
* @mei_flow_ctrl_creds: transmit flow credentials
|
* @mei_flow_ctrl_creds: transmit flow credentials
|
||||||
* @timer_count: watchdog timer for operation completion
|
* @timer_count: watchdog timer for operation completion
|
||||||
* @reading_state: state of the rx
|
|
||||||
* @writing_state: state of the tx
|
* @writing_state: state of the tx
|
||||||
* @read_cb: current pending reading callback
|
* @rd_pending: pending read credits
|
||||||
|
* @rd_completed: completed read
|
||||||
*
|
*
|
||||||
* @device: device on the mei client bus
|
* @device: device on the mei client bus
|
||||||
* @device_link: link to bus clients
|
* @device_link: link to bus clients
|
||||||
@@ -251,9 +251,9 @@ struct mei_cl {
|
|||||||
u8 me_client_id;
|
u8 me_client_id;
|
||||||
u8 mei_flow_ctrl_creds;
|
u8 mei_flow_ctrl_creds;
|
||||||
u8 timer_count;
|
u8 timer_count;
|
||||||
enum mei_file_transaction_states reading_state;
|
|
||||||
enum mei_file_transaction_states writing_state;
|
enum mei_file_transaction_states writing_state;
|
||||||
struct mei_cl_cb *read_cb;
|
struct list_head rd_pending;
|
||||||
|
struct list_head rd_completed;
|
||||||
|
|
||||||
/* MEI CL bus data */
|
/* MEI CL bus data */
|
||||||
struct mei_cl_device *device;
|
struct mei_cl_device *device;
|
||||||
@@ -425,7 +425,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
|
|||||||
* @cdev : character device
|
* @cdev : character device
|
||||||
* @minor : minor number allocated for device
|
* @minor : minor number allocated for device
|
||||||
*
|
*
|
||||||
* @read_list : read completion list
|
|
||||||
* @write_list : write pending list
|
* @write_list : write pending list
|
||||||
* @write_waiting_list : write completion list
|
* @write_waiting_list : write completion list
|
||||||
* @ctrl_wr_list : pending control write list
|
* @ctrl_wr_list : pending control write list
|
||||||
@@ -501,7 +500,6 @@ struct mei_device {
|
|||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
int minor;
|
int minor;
|
||||||
|
|
||||||
struct mei_cl_cb read_list;
|
|
||||||
struct mei_cl_cb write_list;
|
struct mei_cl_cb write_list;
|
||||||
struct mei_cl_cb write_waiting_list;
|
struct mei_cl_cb write_waiting_list;
|
||||||
struct mei_cl_cb ctrl_wr_list;
|
struct mei_cl_cb ctrl_wr_list;
|
||||||
|
Reference in New Issue
Block a user