592 lines
16 KiB
Diff
592 lines
16 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Usyskin <alexander.usyskin@intel.com>
|
|
Date: Thu, 2 Aug 2018 14:54:47 +0300
|
|
Subject: [PATCH] mei: add connect with vtag ioctl
|
|
|
|
Change-Id: I3d68af4fd71bacac1180b80ace6d3b843142069c
|
|
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
|
|
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
|
|
---
|
|
drivers/misc/mei/client.c | 82 +++++++++++++-
|
|
drivers/misc/mei/client.h | 10 +-
|
|
drivers/misc/mei/main.c | 227 ++++++++++++++++++++++++++++++++++---
|
|
drivers/misc/mei/mei_dev.h | 9 ++
|
|
include/uapi/linux/mei.h | 19 ++++
|
|
5 files changed, 320 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
|
|
index 24dc7ae..07bd98b 100644
|
|
--- a/drivers/misc/mei/client.c
|
|
+++ b/drivers/misc/mei/client.c
|
|
@@ -362,6 +362,19 @@ static inline void mei_tx_cb_dequeue(struct mei_cl_cb *cb)
|
|
mei_io_cb_free(cb);
|
|
}
|
|
|
|
+static void mei_cl_set_read_by_fp(const struct mei_cl *cl,
|
|
+ const struct file *fp)
|
|
+{
|
|
+ struct mei_cl_vtag *cl_vtag;
|
|
+
|
|
+ list_for_each_entry(cl_vtag, &cl->vtag_map, list) {
|
|
+ if (cl_vtag->fp == fp) {
|
|
+ cl_vtag->pending_read = true;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* mei_io_cb_init - allocate and initialize io callback
|
|
*
|
|
@@ -387,6 +400,7 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
|
|
cb->buf_idx = 0;
|
|
cb->fop_type = type;
|
|
cb->vtag = 0;
|
|
+
|
|
return cb;
|
|
}
|
|
|
|
@@ -569,6 +583,7 @@ static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
|
|
init_waitqueue_head(&cl->rx_wait);
|
|
init_waitqueue_head(&cl->tx_wait);
|
|
init_waitqueue_head(&cl->ev_wait);
|
|
+ INIT_LIST_HEAD(&cl->vtag_map);
|
|
spin_lock_init(&cl->rd_completed_lock);
|
|
INIT_LIST_HEAD(&cl->rd_completed);
|
|
INIT_LIST_HEAD(&cl->rd_pending);
|
|
@@ -1241,6 +1256,61 @@ static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
|
|
return 0;
|
|
}
|
|
|
|
+const struct file *mei_cl_fp_by_vtag(const struct mei_cl *cl, u8 vtag)
|
|
+{
|
|
+ struct mei_cl_vtag *vtag_l;
|
|
+
|
|
+ list_for_each_entry(vtag_l, &cl->vtag_map, list)
|
|
+ if (vtag_l->vtag == vtag)
|
|
+ return vtag_l->fp;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void mei_cl_reset_read_by_vtag(const struct mei_cl *cl, u8 vtag)
|
|
+{
|
|
+ struct mei_cl_vtag *vtag_l;
|
|
+
|
|
+ list_for_each_entry(vtag_l, &cl->vtag_map, list) {
|
|
+ if (vtag_l->vtag == vtag) {
|
|
+ vtag_l->pending_read = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void mei_cl_read_vtag_add_fc(struct mei_cl *cl)
|
|
+{
|
|
+ struct mei_cl_vtag *cl_vtag;
|
|
+
|
|
+ list_for_each_entry(cl_vtag, &cl->vtag_map, list) {
|
|
+ if (cl_vtag->pending_read) {
|
|
+ if (mei_cl_enqueue_ctrl_wr_cb(cl,
|
|
+ mei_cl_mtu(cl),
|
|
+ MEI_FOP_READ,
|
|
+ cl_vtag->fp))
|
|
+ cl->rx_flow_ctrl_creds++;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb)
|
|
+{
|
|
+ const struct file *fp;
|
|
+
|
|
+ fp = mei_cl_fp_by_vtag(cl, cb->vtag);
|
|
+ if (fp)
|
|
+ cb->fp = fp;
|
|
+ mei_cl_reset_read_by_vtag(cl, cb->vtag);
|
|
+
|
|
+ spin_lock(&cl->rd_completed_lock);
|
|
+ list_add_tail(&cb->list, &cl->rd_completed);
|
|
+ spin_unlock(&cl->rd_completed_lock);
|
|
+
|
|
+ mei_cl_read_vtag_add_fc(cl);
|
|
+}
|
|
+
|
|
/**
|
|
* mei_cl_notify_fop2req - convert fop to proper request
|
|
*
|
|
@@ -1496,13 +1566,17 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
|
|
return 0;
|
|
|
|
/* HW currently supports only one pending read */
|
|
- if (cl->rx_flow_ctrl_creds)
|
|
+ if (cl->rx_flow_ctrl_creds) {
|
|
+ mei_cl_set_read_by_fp(cl, fp);
|
|
return -EBUSY;
|
|
+ }
|
|
|
|
cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp);
|
|
if (!cb)
|
|
return -ENOMEM;
|
|
|
|
+ mei_cl_set_read_by_fp(cl, fp);
|
|
+
|
|
rets = pm_runtime_get(dev->dev);
|
|
if (rets < 0 && rets != -EINPROGRESS) {
|
|
pm_runtime_put_noidle(dev->dev);
|
|
@@ -1620,6 +1694,9 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
|
|
|
|
hdr_len = mei_msg_hdr_init(mei_hdr, cb);
|
|
|
|
+ cl_dbg(dev, cl, "Extend Header %d vtag = %d\n",
|
|
+ mei_hdr->extended, cb->vtag);
|
|
+
|
|
/**
|
|
* Split the message only if we can write the whole host buffer
|
|
* otherwise wait for next time the host buffer is empty.
|
|
@@ -1730,6 +1807,9 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb)
|
|
|
|
hdr_len = mei_msg_hdr_init(mei_hdr, cb);
|
|
|
|
+ cl_dbg(dev, cl, "Extend Header %d vtag = %d\n",
|
|
+ mei_hdr->extended, cb->vtag);
|
|
+
|
|
if (rets == 0) {
|
|
cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
|
|
rets = len;
|
|
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
|
|
index 13223b5..1ac297f 100644
|
|
--- a/drivers/misc/mei/client.h
|
|
+++ b/drivers/misc/mei/client.h
|
|
@@ -96,14 +96,7 @@ int mei_cl_unlink(struct mei_cl *cl);
|
|
struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev);
|
|
|
|
struct mei_cl_cb *mei_cl_read_cb(struct mei_cl *cl, const struct file *fp);
|
|
-
|
|
-static inline void mei_cl_add_rd_completed(struct mei_cl *cl,
|
|
- struct mei_cl_cb *cb)
|
|
-{
|
|
- spin_lock(&cl->rd_completed_lock);
|
|
- list_add_tail(&cb->list, &cl->rd_completed);
|
|
- spin_unlock(&cl->rd_completed_lock);
|
|
-}
|
|
+void mei_cl_add_rd_completed(struct mei_cl *cl, struct mei_cl_cb *cb);
|
|
|
|
static inline void mei_cl_del_rd_completed(struct mei_cl *cl,
|
|
struct mei_cl_cb *cb)
|
|
@@ -121,6 +114,7 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
|
|
const struct file *fp);
|
|
int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
|
|
|
|
+const struct file *mei_cl_fp_by_vtag(const struct mei_cl *cl, u8 vtag);
|
|
/*
|
|
* MEI input output function prototype
|
|
*/
|
|
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
|
|
index 6227b40..697f18d 100644
|
|
--- a/drivers/misc/mei/main.c
|
|
+++ b/drivers/misc/mei/main.c
|
|
@@ -83,6 +83,20 @@ static int mei_open(struct inode *inode, struct file *file)
|
|
return err;
|
|
}
|
|
|
|
+static void mei_cl_vtag_remove_by_fp(const struct mei_cl *cl,
|
|
+ const struct file *fp)
|
|
+{
|
|
+ struct mei_cl_vtag *vtag_l, *next;
|
|
+
|
|
+ list_for_each_entry_safe(vtag_l, next, &cl->vtag_map, list) {
|
|
+ if (vtag_l->fp == fp) {
|
|
+ list_del(&vtag_l->list);
|
|
+ kfree(vtag_l);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* mei_release - the release function
|
|
*
|
|
@@ -104,17 +118,26 @@ static int mei_release(struct inode *inode, struct file *file)
|
|
|
|
mutex_lock(&dev->device_lock);
|
|
|
|
+ mei_cl_vtag_remove_by_fp(cl, file);
|
|
+
|
|
+ if (!list_empty(&cl->vtag_map)) {
|
|
+ cl_dbg(dev, cl, "not the last vtag\n");
|
|
+ mei_cl_flush_queues(cl, file);
|
|
+ rets = 0;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
rets = mei_cl_disconnect(cl);
|
|
|
|
mei_cl_flush_queues(cl, file);
|
|
cl_dbg(dev, cl, "removing\n");
|
|
|
|
mei_cl_unlink(cl);
|
|
+ kfree(cl);
|
|
|
|
+out:
|
|
file->private_data = NULL;
|
|
|
|
- kfree(cl);
|
|
-
|
|
mutex_unlock(&dev->device_lock);
|
|
return rets;
|
|
}
|
|
@@ -240,6 +263,20 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|
mutex_unlock(&dev->device_lock);
|
|
return rets;
|
|
}
|
|
+
|
|
+static u8 mei_cl_vtag_by_fp(const struct mei_cl *cl, const struct file *fp)
|
|
+{
|
|
+ struct mei_cl_vtag *cl_vtag;
|
|
+
|
|
+ if (!fp)
|
|
+ return 0;
|
|
+
|
|
+ list_for_each_entry(cl_vtag, &cl->vtag_map, list)
|
|
+ if (cl_vtag->fp == fp)
|
|
+ return cl_vtag->vtag;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* mei_write - the write function.
|
|
*
|
|
@@ -317,6 +354,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
|
rets = -ENOMEM;
|
|
goto out;
|
|
}
|
|
+ cb->vtag = mei_cl_vtag_by_fp(cl, file);
|
|
|
|
rets = copy_from_user(cb->buf.data, ubuf, length);
|
|
if (rets) {
|
|
@@ -336,17 +374,18 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
|
* mei_ioctl_connect_client - the connect to fw client IOCTL function
|
|
*
|
|
* @file: private data of the file object
|
|
- * @data: IOCTL connect data, input and output parameters
|
|
+ * @in_client_uuid: requested UUID for connection
|
|
+ * @client: IOCTL connect data, output parameters
|
|
*
|
|
* Locking: called under "dev->device_lock" lock
|
|
*
|
|
* Return: 0 on success, <0 on failure.
|
|
*/
|
|
static int mei_ioctl_connect_client(struct file *file,
|
|
- struct mei_connect_client_data *data)
|
|
+ const uuid_le *in_client_uuid,
|
|
+ struct mei_client *client)
|
|
{
|
|
struct mei_device *dev;
|
|
- struct mei_client *client;
|
|
struct mei_me_client *me_cl;
|
|
struct mei_cl *cl;
|
|
int rets;
|
|
@@ -354,18 +393,15 @@ static int mei_ioctl_connect_client(struct file *file,
|
|
cl = file->private_data;
|
|
dev = cl->dev;
|
|
|
|
- if (dev->dev_state != MEI_DEV_ENABLED)
|
|
- return -ENODEV;
|
|
-
|
|
if (cl->state != MEI_FILE_INITIALIZING &&
|
|
cl->state != MEI_FILE_DISCONNECTED)
|
|
return -EBUSY;
|
|
|
|
/* find ME client we're trying to connect to */
|
|
- me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
|
|
+ me_cl = mei_me_cl_by_uuid(dev, in_client_uuid);
|
|
if (!me_cl) {
|
|
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
|
|
- &data->in_client_uuid);
|
|
+ in_client_uuid);
|
|
rets = -ENOTTY;
|
|
goto end;
|
|
}
|
|
@@ -375,7 +411,7 @@ static int mei_ioctl_connect_client(struct file *file,
|
|
!dev->allow_fixed_address : !dev->hbm_f_fa_supported;
|
|
if (forbidden) {
|
|
dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
|
|
- &data->in_client_uuid);
|
|
+ in_client_uuid);
|
|
rets = -ENOTTY;
|
|
goto end;
|
|
}
|
|
@@ -389,7 +425,6 @@ static int mei_ioctl_connect_client(struct file *file,
|
|
me_cl->props.max_msg_length);
|
|
|
|
/* prepare the output buffer */
|
|
- client = &data->out_client_properties;
|
|
client->max_msg_length = me_cl->props.max_msg_length;
|
|
client->protocol_version = me_cl->props.protocol_version;
|
|
dev_dbg(dev->dev, "Can connect?\n");
|
|
@@ -401,6 +436,113 @@ static int mei_ioctl_connect_client(struct file *file,
|
|
return rets;
|
|
}
|
|
|
|
+static int mei_cl_vm_support_check(struct mei_device *dev, const uuid_le *uuid)
|
|
+{
|
|
+ struct mei_me_client *me_cl;
|
|
+ int ret;
|
|
+
|
|
+ if (!dev->hbm_f_vm_supported) {
|
|
+ dev_dbg(dev->dev, "VTag not supported\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ me_cl = mei_me_cl_by_uuid(dev, uuid);
|
|
+ if (!me_cl) {
|
|
+ dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
|
|
+ uuid);
|
|
+ return -ENOTTY;
|
|
+ }
|
|
+ ret = me_cl->props.vm_supported ? 0 : -EOPNOTSUPP;
|
|
+ mei_me_cl_put(me_cl);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct mei_cl_vtag *mei_cl_vtag_alloc(struct file *fp, u8 vtag)
|
|
+{
|
|
+ struct mei_cl_vtag *cl_vtag;
|
|
+
|
|
+ cl_vtag = kzalloc(sizeof(*cl_vtag), GFP_KERNEL);
|
|
+ if (!cl_vtag)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ INIT_LIST_HEAD(&cl_vtag->list);
|
|
+ cl_vtag->vtag = vtag;
|
|
+ cl_vtag->fp = fp;
|
|
+
|
|
+ return cl_vtag;
|
|
+}
|
|
+
|
|
+static int mei_ioctl_connect_vtag(struct file *file,
|
|
+ const uuid_le *in_client_uuid,
|
|
+ struct mei_client *client,
|
|
+ u8 vtag)
|
|
+{
|
|
+ struct mei_device *dev;
|
|
+ struct mei_cl *cl;
|
|
+ struct mei_cl *pos;
|
|
+ struct mei_cl_vtag *cl_vtag;
|
|
+
|
|
+ cl = file->private_data;
|
|
+ dev = cl->dev;
|
|
+
|
|
+ dev_dbg(dev->dev, "FW Client %pUl vtag %d\n", in_client_uuid, vtag);
|
|
+
|
|
+ if (cl->state != MEI_FILE_INITIALIZING &&
|
|
+ cl->state != MEI_FILE_DISCONNECTED)
|
|
+ return -EBUSY;
|
|
+
|
|
+ list_for_each_entry(pos, &dev->file_list, link) {
|
|
+ if (pos == cl)
|
|
+ continue;
|
|
+ if (!pos->me_cl)
|
|
+ continue;
|
|
+
|
|
+ /* FIXME: just compare me_cl addr */
|
|
+ if (uuid_le_cmp(*mei_cl_uuid(pos), *in_client_uuid))
|
|
+ continue;
|
|
+
|
|
+ /* if tag already exist try another fp */
|
|
+ if (mei_cl_fp_by_vtag(pos, vtag))
|
|
+ continue;
|
|
+
|
|
+ /* replace cl with acquired one */
|
|
+ dev_dbg(dev->dev, "replacing with existing cl\n");
|
|
+ mei_cl_unlink(cl);
|
|
+ kfree(cl);
|
|
+ file->private_data = pos;
|
|
+ cl = pos;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ cl_vtag = mei_cl_vtag_alloc(file, vtag);
|
|
+ if (IS_ERR(cl_vtag))
|
|
+ return -ENOMEM;
|
|
+
|
|
+ list_add_tail(&cl_vtag->list, &cl->vtag_map);
|
|
+
|
|
+ while (cl->state != MEI_FILE_INITIALIZING &&
|
|
+ cl->state != MEI_FILE_DISCONNECTED &&
|
|
+ cl->state != MEI_FILE_CONNECTED) {
|
|
+ mutex_unlock(&dev->device_lock);
|
|
+ wait_event_timeout(cl->wait,
|
|
+ (cl->state == MEI_FILE_CONNECTED ||
|
|
+ cl->state == MEI_FILE_DISCONNECTED ||
|
|
+ cl->state == MEI_FILE_DISCONNECT_REQUIRED ||
|
|
+ cl->state == MEI_FILE_DISCONNECT_REPLY),
|
|
+ mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
|
|
+ mutex_lock(&dev->device_lock);
|
|
+ }
|
|
+
|
|
+ if (!mei_cl_is_connected(cl))
|
|
+ return mei_ioctl_connect_client(file, in_client_uuid, client);
|
|
+
|
|
+ client->max_msg_length = cl->me_cl->props.max_msg_length;
|
|
+ client->protocol_version = cl->me_cl->props.protocol_version;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* mei_ioctl_client_notify_request -
|
|
* propagate event notification request to client
|
|
@@ -457,7 +599,11 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
|
|
{
|
|
struct mei_device *dev;
|
|
struct mei_cl *cl = file->private_data;
|
|
- struct mei_connect_client_data connect_data;
|
|
+ struct mei_connect_client_data conn;
|
|
+ struct mei_connect_client_data_vtag conn_vtag;
|
|
+ const uuid_le *cl_uuid;
|
|
+ struct mei_client *props;
|
|
+ u8 vtag;
|
|
u32 notify_get, notify_req;
|
|
int rets;
|
|
|
|
@@ -478,20 +624,65 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
|
|
switch (cmd) {
|
|
case IOCTL_MEI_CONNECT_CLIENT:
|
|
dev_dbg(dev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
|
|
- if (copy_from_user(&connect_data, (char __user *)data,
|
|
- sizeof(struct mei_connect_client_data))) {
|
|
+ if (copy_from_user(&conn, (char __user *)data, sizeof(conn))) {
|
|
dev_dbg(dev->dev, "failed to copy data from userland\n");
|
|
rets = -EFAULT;
|
|
goto out;
|
|
}
|
|
+ cl_uuid = &conn.in_client_uuid;
|
|
+ props = &conn.out_client_properties;
|
|
+ vtag = 0;
|
|
+
|
|
+ if (!mei_cl_vm_support_check(dev, cl_uuid))
|
|
+ rets = mei_ioctl_connect_vtag(file, cl_uuid, props,
|
|
+ vtag);
|
|
+ else
|
|
+ rets = mei_ioctl_connect_client(file, cl_uuid, props);
|
|
+ if (rets)
|
|
+ goto out;
|
|
+
|
|
+ /* if all is ok, copying the data back to user. */
|
|
+ if (copy_to_user((char __user *)data, &conn, sizeof(conn))) {
|
|
+ dev_dbg(dev->dev, "failed to copy data to userland\n");
|
|
+ rets = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ break;
|
|
+
|
|
+ case IOCTL_MEI_CONNECT_CLIENT_VTAG:
|
|
+ dev_dbg(dev->dev, "IOCTL_MEI_CONNECT_CLIENT_VTAG\n");
|
|
+ if (copy_from_user(&conn_vtag, (char __user *)data,
|
|
+ sizeof(conn_vtag))) {
|
|
+ dev_dbg(dev->dev, "failed to copy data from userland\n");
|
|
+ rets = -EFAULT;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ cl_uuid = &conn_vtag.connect.in_client_uuid;
|
|
+ props = &conn_vtag.out_client_properties;
|
|
+ vtag = conn_vtag.connect.vtag;
|
|
+
|
|
+ if (mei_cl_vm_support_check(dev, cl_uuid)) {
|
|
+ dev_dbg(dev->dev, "FW Client %pUl does not support vtags\n",
|
|
+ cl_uuid);
|
|
+ rets = -EOPNOTSUPP;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!vtag) {
|
|
+ dev_dbg(dev->dev, "vtag can't be zero\n");
|
|
+ rets = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
|
|
- rets = mei_ioctl_connect_client(file, &connect_data);
|
|
+ rets = mei_ioctl_connect_vtag(file, cl_uuid, props, vtag);
|
|
if (rets)
|
|
goto out;
|
|
|
|
/* if all is ok, copying the data back to user. */
|
|
- if (copy_to_user((char __user *)data, &connect_data,
|
|
- sizeof(struct mei_connect_client_data))) {
|
|
+ if (copy_to_user((char __user *)data, &conn_vtag,
|
|
+ sizeof(conn_vtag))) {
|
|
dev_dbg(dev->dev, "failed to copy data to userland\n");
|
|
rets = -EFAULT;
|
|
goto out;
|
|
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
|
|
index 7058475..384f1b6 100644
|
|
--- a/drivers/misc/mei/mei_dev.h
|
|
+++ b/drivers/misc/mei/mei_dev.h
|
|
@@ -203,6 +203,13 @@ struct mei_cl_cb {
|
|
u32 blocking:1;
|
|
};
|
|
|
|
+struct mei_cl_vtag {
|
|
+ struct list_head list;
|
|
+ const struct file *fp;
|
|
+ u8 vtag;
|
|
+ u8 pending_read:1;
|
|
+};
|
|
+
|
|
/**
|
|
* struct mei_cl - me client host representation
|
|
* carried in file->private_data
|
|
@@ -219,6 +226,7 @@ struct mei_cl_cb {
|
|
* @me_cl: fw client connected
|
|
* @fp: file associated with client
|
|
* @host_client_id: host id
|
|
+ * @vtag_map: vm tag map
|
|
* @tx_flow_ctrl_creds: transmit flow credentials
|
|
* @rx_flow_ctrl_creds: receive flow credentials
|
|
* @timer_count: watchdog timer for operation completion
|
|
@@ -245,6 +253,7 @@ struct mei_cl {
|
|
struct mei_me_client *me_cl;
|
|
const struct file *fp;
|
|
u8 host_client_id;
|
|
+ struct list_head vtag_map;
|
|
u8 tx_flow_ctrl_creds;
|
|
u8 rx_flow_ctrl_creds;
|
|
u8 timer_count;
|
|
diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h
|
|
index 0f681cb..0bc184b 100644
|
|
--- a/include/uapi/linux/mei.h
|
|
+++ b/include/uapi/linux/mei.h
|
|
@@ -127,4 +127,23 @@ struct mei_connect_client_data {
|
|
*/
|
|
#define IOCTL_MEI_NOTIFY_GET _IOR('H', 0x03, __u32)
|
|
|
|
+/*
|
|
+ * IOCTL Connect Client Data structure with vtag
|
|
+ */
|
|
+struct mei_connect_client_vtag {
|
|
+ uuid_le in_client_uuid;
|
|
+ __u8 vtag;
|
|
+ __u8 reserved[3];
|
|
+};
|
|
+
|
|
+struct mei_connect_client_data_vtag {
|
|
+ union {
|
|
+ struct mei_connect_client_vtag connect;
|
|
+ struct mei_client out_client_properties;
|
|
+ };
|
|
+};
|
|
+
|
|
+#define IOCTL_MEI_CONNECT_CLIENT_VTAG \
|
|
+ _IOWR('H', 0x04, struct mei_connect_client_data_vtag)
|
|
+
|
|
#endif /* _LINUX_MEI_H */
|
|
--
|
|
https://clearlinux.org
|
|
|