summaryrefslogtreecommitdiff
path: root/drivers/misc/mei/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/main.c')
-rw-r--r--drivers/misc/mei/main.c198
1 files changed, 73 insertions, 125 deletions
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 3c019c0e60eb..e9513d651cd3 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -22,7 +22,6 @@
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
-#include <linux/aio.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/ioctl.h>
@@ -59,24 +58,18 @@ static int mei_open(struct inode *inode, struct file *file)
mutex_lock(&dev->device_lock);
- cl = NULL;
-
- err = -ENODEV;
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(dev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
+ err = -ENODEV;
goto err_unlock;
}
- err = -ENOMEM;
- cl = mei_cl_allocate(dev);
- if (!cl)
- goto err_unlock;
-
- /* open_handle_count check is handled in the mei_cl_link */
- err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
- if (err)
+ cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY);
+ if (IS_ERR(cl)) {
+ err = PTR_ERR(cl);
goto err_unlock;
+ }
file->private_data = cl;
@@ -86,7 +79,6 @@ static int mei_open(struct inode *inode, struct file *file)
err_unlock:
mutex_unlock(&dev->device_lock);
- kfree(cl);
return err;
}
@@ -101,9 +93,8 @@ err_unlock:
static int mei_release(struct inode *inode, struct file *file)
{
struct mei_cl *cl = file->private_data;
- struct mei_cl_cb *cb;
struct mei_device *dev;
- int rets = 0;
+ int rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -115,33 +106,15 @@ static int mei_release(struct inode *inode, struct file *file)
rets = mei_amthif_release(dev, file);
goto out;
}
- if (cl->state == MEI_FILE_CONNECTED) {
- cl->state = MEI_FILE_DISCONNECTING;
- cl_dbg(dev, cl, "disconnecting\n");
- rets = mei_cl_disconnect(cl);
- }
- mei_cl_flush_queues(cl);
+ rets = mei_cl_disconnect(cl);
+
+ mei_cl_flush_queues(cl, file);
cl_dbg(dev, cl, "removing\n");
mei_cl_unlink(cl);
-
- /* free read cb */
- cb = NULL;
- if (cl->read_cb) {
- cb = mei_cl_find_read_cb(cl);
- /* Remove entry from read list */
- if (cb)
- list_del(&cb->list);
-
- cb = cl->read_cb;
- cl->read_cb = NULL;
- }
-
file->private_data = NULL;
- mei_io_cb_free(cb);
-
kfree(cl);
out:
mutex_unlock(&dev->device_lock);
@@ -163,9 +136,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
- struct mei_cl_cb *cb_pos = NULL;
- struct mei_cl_cb *cb = NULL;
struct mei_device *dev;
+ struct mei_cl_cb *cb = NULL;
int rets;
int err;
@@ -192,8 +164,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;
}
- if (cl->read_cb) {
- cb = cl->read_cb;
+ cb = mei_cl_read_cb(cl, file);
+ if (cb) {
/* read what left */
if (cb->buf_idx > *offset)
goto copy_buffer;
@@ -209,16 +181,14 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
*offset = 0;
}
- err = mei_cl_read_start(cl, length);
+ err = mei_cl_read_start(cl, length, file);
if (err && err != -EBUSY) {
- dev_dbg(dev->dev,
- "mei start read failure with status = %d\n", err);
+ cl_dbg(dev, cl, "mei start read failure status = %d\n", err);
rets = err;
goto out;
}
- if (MEI_READ_COMPLETE != cl->reading_state &&
- !waitqueue_active(&cl->rx_wait)) {
+ if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
if (file->f_flags & O_NONBLOCK) {
rets = -EAGAIN;
goto out;
@@ -227,8 +197,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
mutex_unlock(&dev->device_lock);
if (wait_event_interruptible(cl->rx_wait,
- MEI_READ_COMPLETE == cl->reading_state ||
- mei_cl_is_transitioning(cl))) {
+ (!list_empty(&cl->rd_completed)) ||
+ (!mei_cl_is_connected(cl)))) {
if (signal_pending(current))
return -EINTR;
@@ -236,26 +206,33 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
}
mutex_lock(&dev->device_lock);
- if (mei_cl_is_transitioning(cl)) {
+ if (!mei_cl_is_connected(cl)) {
rets = -EBUSY;
goto out;
}
}
- cb = cl->read_cb;
-
+ cb = mei_cl_read_cb(cl, file);
if (!cb) {
- rets = -ENODEV;
- goto out;
- }
- if (cl->reading_state != MEI_READ_COMPLETE) {
+ if (mei_cl_is_fixed_address(cl) && dev->allow_fixed_address) {
+ cb = mei_cl_read_cb(cl, NULL);
+ if (cb)
+ goto copy_buffer;
+ }
rets = 0;
goto out;
}
- /* now copy the data to user space */
+
copy_buffer:
- dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n",
- cb->response_buffer.size, cb->buf_idx);
+ /* now copy the data to user space */
+ if (cb->status) {
+ rets = cb->status;
+ cl_dbg(dev, cl, "read operation failed %d\n", rets);
+ goto free;
+ }
+
+ cl_dbg(dev, cl, "buf.size = %d buf.idx = %ld\n",
+ cb->buf.size, cb->buf_idx);
if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
rets = -EMSGSIZE;
goto free;
@@ -265,7 +242,7 @@ copy_buffer:
* however buf_idx may point beyond that */
length = min_t(size_t, length, cb->buf_idx - *offset);
- if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) {
+ if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
dev_dbg(dev->dev, "failed to copy data to userland\n");
rets = -EFAULT;
goto free;
@@ -277,15 +254,10 @@ copy_buffer:
goto out;
free:
- cb_pos = mei_cl_find_read_cb(cl);
- /* Remove entry from read list */
- if (cb_pos)
- list_del(&cb_pos->list);
mei_io_cb_free(cb);
- cl->reading_state = MEI_IDLE;
- cl->read_cb = NULL;
+
out:
- dev_dbg(dev->dev, "end mei read rets= %d\n", rets);
+ cl_dbg(dev, cl, "end mei read rets = %d\n", rets);
mutex_unlock(&dev->device_lock);
return rets;
}
@@ -303,7 +275,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
- struct mei_me_client *me_cl = NULL;
struct mei_cl_cb *write_cb = NULL;
struct mei_device *dev;
unsigned long timeout = 0;
@@ -321,28 +292,27 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
goto out;
}
- me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
- if (!me_cl) {
- rets = -ENOTTY;
+ if (!mei_cl_is_connected(cl)) {
+ cl_err(dev, cl, "is not connected");
+ rets = -ENODEV;
goto out;
}
- if (length == 0) {
- rets = 0;
+ if (!mei_me_cl_is_active(cl->me_cl)) {
+ rets = -ENOTTY;
goto out;
}
- if (length > me_cl->props.max_msg_length) {
+ if (length > mei_cl_mtu(cl)) {
rets = -EFBIG;
goto out;
}
- if (cl->state != MEI_FILE_CONNECTED) {
- dev_err(dev->dev, "host client = %d, is not connected to ME client = %d",
- cl->host_client_id, cl->me_client_id);
- rets = -ENODEV;
+ if (length == 0) {
+ rets = 0;
goto out;
}
+
if (cl == &dev->iamthif_cl) {
write_cb = mei_amthif_find_read_list_entry(dev, file);
@@ -350,41 +320,22 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
timeout = write_cb->read_time +
mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER);
- if (time_after(jiffies, timeout) ||
- cl->reading_state == MEI_READ_COMPLETE) {
+ if (time_after(jiffies, timeout)) {
*offset = 0;
- list_del(&write_cb->list);
mei_io_cb_free(write_cb);
write_cb = NULL;
}
}
}
- /* free entry used in read */
- if (cl->reading_state == MEI_READ_COMPLETE) {
- *offset = 0;
- write_cb = mei_cl_find_read_cb(cl);
- if (write_cb) {
- list_del(&write_cb->list);
- mei_io_cb_free(write_cb);
- write_cb = NULL;
- cl->reading_state = MEI_IDLE;
- cl->read_cb = NULL;
- }
- } else if (cl->reading_state == MEI_IDLE)
- *offset = 0;
-
-
- write_cb = mei_io_cb_init(cl, file);
+ *offset = 0;
+ write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
if (!write_cb) {
rets = -ENOMEM;
goto out;
}
- rets = mei_io_cb_alloc_req_buf(write_cb, length);
- if (rets)
- goto out;
- rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
+ rets = copy_from_user(write_cb->buf.data, ubuf, length);
if (rets) {
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
@@ -392,21 +343,19 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
}
if (cl == &dev->iamthif_cl) {
- rets = mei_amthif_write(dev, write_cb);
+ rets = mei_amthif_write(cl, write_cb);
if (rets) {
dev_err(dev->dev,
"amthif write failed with status = %d\n", rets);
goto out;
}
- mei_me_cl_put(me_cl);
mutex_unlock(&dev->device_lock);
return length;
}
rets = mei_cl_write(cl, write_cb, false);
out:
- mei_me_cl_put(me_cl);
mutex_unlock(&dev->device_lock);
if (rets < 0)
mei_io_cb_free(write_cb);
@@ -444,17 +393,16 @@ static int mei_ioctl_connect_client(struct file *file,
/* find ME client we're trying to connect to */
me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
- if (!me_cl || me_cl->props.fixed_address) {
+ if (!me_cl ||
+ (me_cl->props.fixed_address && !dev->allow_fixed_address)) {
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
- &data->in_client_uuid);
+ &data->in_client_uuid);
+ mei_me_cl_put(me_cl);
return -ENOTTY;
}
- cl->me_client_id = me_cl->client_id;
- cl->cl_uuid = me_cl->props.protocol_name;
-
dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
- cl->me_client_id);
+ me_cl->client_id);
dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
me_cl->props.protocol_version);
dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
@@ -465,7 +413,7 @@ static int mei_ioctl_connect_client(struct file *file,
*/
if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
dev_dbg(dev->dev, "FW Client is amthi\n");
- if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
+ if (!mei_cl_is_connected(&dev->iamthif_cl)) {
rets = -ENODEV;
goto end;
}
@@ -490,7 +438,7 @@ static int mei_ioctl_connect_client(struct file *file,
client->protocol_version = me_cl->props.protocol_version;
dev_dbg(dev->dev, "Can connect?\n");
- rets = mei_cl_connect(cl, file);
+ rets = mei_cl_connect(cl, me_cl, file);
end:
mei_me_cl_put(me_cl);
@@ -589,6 +537,7 @@ static long mei_compat_ioctl(struct file *file,
*/
static unsigned int mei_poll(struct file *file, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct mei_cl *cl = file->private_data;
struct mei_device *dev;
unsigned int mask = 0;
@@ -600,27 +549,26 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
mutex_lock(&dev->device_lock);
- if (!mei_cl_is_connected(cl)) {
+
+ if (dev->dev_state != MEI_DEV_ENABLED ||
+ !mei_cl_is_connected(cl)) {
mask = POLLERR;
goto out;
}
- mutex_unlock(&dev->device_lock);
-
-
- if (cl == &dev->iamthif_cl)
- return mei_amthif_poll(dev, file, wait);
-
- poll_wait(file, &cl->tx_wait, wait);
-
- mutex_lock(&dev->device_lock);
-
- if (!mei_cl_is_connected(cl)) {
- mask = POLLERR;
+ if (cl == &dev->iamthif_cl) {
+ mask = mei_amthif_poll(dev, file, wait);
goto out;
}
- mask |= (POLLIN | POLLRDNORM);
+ if (req_events & (POLLIN | POLLRDNORM)) {
+ poll_wait(file, &cl->rx_wait, wait);
+
+ if (!list_empty(&cl->rd_completed))
+ mask |= POLLIN | POLLRDNORM;
+ else
+ mei_cl_read_start(cl, 0, file);
+ }
out:
mutex_unlock(&dev->device_lock);
@@ -734,7 +682,7 @@ int mei_register(struct mei_device *dev, struct device *parent)
/* Fill in the data structures */
devno = MKDEV(MAJOR(mei_devt), dev->minor);
cdev_init(&dev->cdev, &mei_fops);
- dev->cdev.owner = mei_fops.owner;
+ dev->cdev.owner = parent->driver->owner;
/* Add the device */
ret = cdev_add(&dev->cdev, devno, 1);