diff options
Diffstat (limited to 'drivers/misc/mei')
-rw-r--r-- | drivers/misc/mei/amthif.c | 14 | ||||
-rw-r--r-- | drivers/misc/mei/bus.c | 69 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 156 | ||||
-rw-r--r-- | drivers/misc/mei/client.h | 17 | ||||
-rw-r--r-- | drivers/misc/mei/debugfs.c | 32 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 34 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 15 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 22 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 8 | ||||
-rw-r--r-- | drivers/misc/mei/nfc.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/wd.c | 1 |
11 files changed, 253 insertions, 117 deletions
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 79f53941779..c4cb9a984a5 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -97,23 +97,25 @@ int mei_amthif_host_init(struct mei_device *dev) /* allocate storage for ME message buffer */ msg_buf = kcalloc(dev->iamthif_mtu, sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) - return -ENOMEM; + if (!msg_buf) { + ret = -ENOMEM; + goto out; + } dev->iamthif_msg_buf = msg_buf; ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); - if (ret < 0) { - dev_err(dev->dev, - "amthif: failed link client %d\n", ret); - return ret; + dev_err(dev->dev, "amthif: failed cl_link %d\n", ret); + goto out; } ret = mei_cl_connect(cl, NULL); dev->iamthif_state = MEI_IAMTHIF_IDLE; +out: + mei_me_cl_put(me_cl); return ret; } diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index b3a72bca524..be767f4db26 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -224,46 +224,53 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver) } EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); -static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, +static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking) { struct mei_device *dev; - struct mei_me_client *me_cl; - struct mei_cl_cb *cb; - int rets; + struct mei_me_client *me_cl = NULL; + struct mei_cl_cb *cb = NULL; + ssize_t rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; dev = cl->dev; - if (cl->state != MEI_FILE_CONNECTED) - return -ENODEV; + mutex_lock(&dev->device_lock); + if (cl->state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + goto out; + } /* Check if we have an ME client device */ me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); - if (!me_cl) - return -ENOTTY; + if (!me_cl) { + rets = -ENOTTY; + goto out; + } - if (length > me_cl->props.max_msg_length) - return -EFBIG; + if (length > me_cl->props.max_msg_length) { + rets = -EFBIG; + goto out; + } cb = mei_io_cb_init(cl, NULL); - if (!cb) - return -ENOMEM; + if (!cb) { + rets = -ENOMEM; + goto out; + } rets = mei_io_cb_alloc_req_buf(cb, length); - if (rets < 0) { - mei_io_cb_free(cb); - return rets; - } + if (rets < 0) + goto out; memcpy(cb->request_buffer.data, buf, length); - mutex_lock(&dev->device_lock); - rets = mei_cl_write(cl, cb, blocking); +out: + mei_me_cl_put(me_cl); mutex_unlock(&dev->device_lock); if (rets < 0) mei_io_cb_free(cb); @@ -271,12 +278,12 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, return rets; } -int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) +ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) { struct mei_device *dev; struct mei_cl_cb *cb; size_t r_length; - int err; + ssize_t rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; @@ -286,11 +293,9 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) mutex_lock(&dev->device_lock); if (!cl->read_cb) { - err = mei_cl_read_start(cl, length); - if (err < 0) { - mutex_unlock(&dev->device_lock); - return err; - } + rets = mei_cl_read_start(cl, length); + if (rets < 0) + goto out; } if (cl->reading_state != MEI_READ_COMPLETE && @@ -313,13 +318,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) cb = cl->read_cb; if (cl->reading_state != MEI_READ_COMPLETE) { - r_length = 0; + rets = 0; goto out; } r_length = min_t(size_t, length, cb->buf_idx); - memcpy(buf, cb->response_buffer.data, r_length); + rets = r_length; mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; @@ -328,20 +333,20 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) out: mutex_unlock(&dev->device_lock); - return r_length; + return rets; } -inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) +inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length) { return ___mei_cl_send(cl, buf, length, 0); } -inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) +inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length) { return ___mei_cl_send(cl, buf, length, 1); } -int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) { struct mei_cl *cl = device->cl; @@ -355,7 +360,7 @@ int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) } EXPORT_SYMBOL_GPL(mei_cl_send); -int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) { struct mei_cl *cl = device->cl; diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 1382d551d7e..dfbddfe1c7a 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -27,7 +27,63 @@ #include "client.h" /** + * mei_me_cl_init - initialize me client + * + * @me_cl: me client + */ +void mei_me_cl_init(struct mei_me_client *me_cl) +{ + INIT_LIST_HEAD(&me_cl->list); + kref_init(&me_cl->refcnt); +} + +/** + * mei_me_cl_get - increases me client refcount + * + * @me_cl: me client + * + * Locking: called under "dev->device_lock" lock + * + * Return: me client or NULL + */ +struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl) +{ + if (me_cl) + kref_get(&me_cl->refcnt); + + return me_cl; +} + +/** + * mei_me_cl_release - unlink and free me client + * + * Locking: called under "dev->device_lock" lock + * + * @ref: me_client refcount + */ +static void mei_me_cl_release(struct kref *ref) +{ + struct mei_me_client *me_cl = + container_of(ref, struct mei_me_client, refcnt); + list_del(&me_cl->list); + kfree(me_cl); +} +/** + * mei_me_cl_put - decrease me client refcount and free client if necessary + * + * Locking: called under "dev->device_lock" lock + * + * @me_cl: me client + */ +void mei_me_cl_put(struct mei_me_client *me_cl) +{ + if (me_cl) + kref_put(&me_cl->refcnt, mei_me_cl_release); +} + +/** * mei_me_cl_by_uuid - locate me client by uuid + * increases ref count * * @dev: mei device * @uuid: me client uuid @@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, list_for_each_entry(me_cl, &dev->me_clients, list) if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) - return me_cl; + return mei_me_cl_get(me_cl); return NULL; } /** * mei_me_cl_by_id - locate me client by client id + * increases ref count * * @dev: the device structure * @client_id: me client id @@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id) list_for_each_entry(me_cl, &dev->me_clients, list) if (me_cl->client_id == client_id) - return me_cl; + return mei_me_cl_get(me_cl); + return NULL; } /** * mei_me_cl_by_uuid_id - locate me client by client id and uuid + * increases ref count * * @dev: the device structure * @uuid: me client uuid @@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, list_for_each_entry(me_cl, &dev->me_clients, list) if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && me_cl->client_id == client_id) - return me_cl; + return mei_me_cl_get(me_cl); + return NULL; } /** - * mei_me_cl_remove - remove me client matching uuid and client_id + * mei_me_cl_rm_by_uuid - remove all me clients matching uuid * * @dev: the device structure * @uuid: me client uuid - * @client_id: me client address + * + * Locking: called under "dev->device_lock" lock */ -void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id) +void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid) { struct mei_me_client *me_cl, *next; + dev_dbg(dev->dev, "remove %pUl\n", uuid); + list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) + if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) + mei_me_cl_put(me_cl); +} + +/** + * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id + * + * @dev: the device structure + * @uuid: me client uuid + * @id: me client id + * + * Locking: called under "dev->device_lock" lock + */ +void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id) +{ + struct mei_me_client *me_cl, *next; + const uuid_le *pn; + + dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id); list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { - if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 && - me_cl->client_id == client_id) { - list_del(&me_cl->list); - kfree(me_cl); - break; - } + pn = &me_cl->props.protocol_name; + if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0) + mei_me_cl_put(me_cl); } } +/** + * mei_me_cl_rm_all - remove all me clients + * + * @dev: the device structure + * + * Locking: called under "dev->device_lock" lock + */ +void mei_me_cl_rm_all(struct mei_device *dev) +{ + struct mei_me_client *me_cl, *next; + + list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) + mei_me_cl_put(me_cl); +} + + /** * mei_cl_cmp_id - tells if the clients are the same @@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl) { struct mei_device *dev; struct mei_me_client *me_cl; + int rets = 0; if (WARN_ON(!cl || !cl->dev)) return -EINVAL; @@ -704,18 +800,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl) if (cl->mei_flow_ctrl_creds > 0) return 1; - me_cl = mei_me_cl_by_id(dev, cl->me_client_id); + me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); if (!me_cl) { cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOENT; } - if (me_cl->mei_flow_ctrl_creds) { + if (me_cl->mei_flow_ctrl_creds > 0) { + rets = 1; if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; - return 1; + rets = -EINVAL; } - return 0; + mei_me_cl_put(me_cl); + return rets; } /** @@ -732,28 +829,36 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) { struct mei_device *dev; struct mei_me_client *me_cl; + int rets; if (WARN_ON(!cl || !cl->dev)) return -EINVAL; dev = cl->dev; - me_cl = mei_me_cl_by_id(dev, cl->me_client_id); + me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id); if (!me_cl) { cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOENT; } if (me_cl->props.single_recv_buf) { - if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; + if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) { + rets = -EINVAL; + goto out; + } me_cl->mei_flow_ctrl_creds--; } else { - if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; + if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) { + rets = -EINVAL; + goto out; + } cl->mei_flow_ctrl_creds--; } - return 0; + rets = 0; +out: + mei_me_cl_put(me_cl); + return rets; } /** @@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); return -ENOTTY; } + /* always allocate at least client max message */ + length = max_t(size_t, length, me_cl->props.max_msg_length); + mei_me_cl_put(me_cl); rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { @@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) goto out; } - /* always allocate at least client max message */ - length = max_t(size_t, length, me_cl->props.max_msg_length); rets = mei_io_cb_alloc_resp_buf(cb, length); if (rets) goto out; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index d9d0c152525..cfcde8e97fc 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -24,15 +24,22 @@ #include "mei_dev.h" +/* + * reference counting base function + */ +void mei_me_cl_init(struct mei_me_client *me_cl); +void mei_me_cl_put(struct mei_me_client *me_cl); +struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl); + struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, - const uuid_le *cuuid); + const uuid_le *uuid); struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id); - struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 client_id); - -void mei_me_cl_remove(struct mei_device *dev, - const uuid_le *uuid, u8 client_id); +void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid); +void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, + const uuid_le *uuid, u8 id); +void mei_me_cl_rm_all(struct mei_device *dev); /* * MEI IO Functions diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index b60b4263cf0..b125380ee87 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -21,20 +21,22 @@ #include <linux/mei.h> #include "mei_dev.h" +#include "client.h" #include "hw.h" static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct mei_device *dev = fp->private_data; - struct mei_me_client *me_cl; + struct mei_me_client *me_cl, *n; size_t bufsz = 1; char *buf; int i = 0; int pos = 0; int ret; -#define HDR " |id|fix| UUID |con|msg len|sb|\n" +#define HDR \ +" |id|fix| UUID |con|msg len|sb|refc|\n" mutex_lock(&dev->device_lock); @@ -54,16 +56,22 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, if (dev->dev_state != MEI_DEV_ENABLED) goto out; - list_for_each_entry(me_cl, &dev->me_clients, list) { - - pos += scnprintf(buf + pos, bufsz - pos, - "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n", - i++, me_cl->client_id, - me_cl->props.fixed_address, - &me_cl->props.protocol_name, - me_cl->props.max_number_of_connections, - me_cl->props.max_msg_length, - me_cl->props.single_recv_buf); + list_for_each_entry_safe(me_cl, n, &dev->me_clients, list) { + + me_cl = mei_me_cl_get(me_cl); + if (me_cl) { + pos += scnprintf(buf + pos, bufsz - pos, + "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n", + i++, me_cl->client_id, + me_cl->props.fixed_address, + &me_cl->props.protocol_name, + me_cl->props.max_number_of_connections, + me_cl->props.max_msg_length, + me_cl->props.single_recv_buf, + atomic_read(&me_cl->refcnt.refcount)); + } + + mei_me_cl_put(me_cl); } out: mutex_unlock(&dev->device_lock); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 239d7f5d6a9..c8412d41e4f 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -105,21 +105,6 @@ void mei_hbm_idle(struct mei_device *dev) } /** - * mei_me_cl_remove_all - remove all me clients - * - * @dev: the device structure - */ -static void mei_me_cl_remove_all(struct mei_device *dev) -{ - struct mei_me_client *me_cl, *next; - - list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { - list_del(&me_cl->list); - kfree(me_cl); - } -} - -/** * mei_hbm_reset - reset hbm counters and book keeping data structurs * * @dev: the device structure @@ -128,7 +113,7 @@ void mei_hbm_reset(struct mei_device *dev) { dev->me_client_index = 0; - mei_me_cl_remove_all(dev); + mei_me_cl_rm_all(dev); mei_hbm_idle(dev); } @@ -339,11 +324,16 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, struct hbm_props_response *res) { struct mei_me_client *me_cl; + const uuid_le *uuid = &res->client_properties.protocol_name; + + mei_me_cl_rm_by_uuid(dev, uuid); me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL); if (!me_cl) return -ENOMEM; + mei_me_cl_init(me_cl); + me_cl->props = res->client_properties; me_cl->client_id = res->me_addr; me_cl->mei_flow_ctrl_creds = 0; @@ -484,6 +474,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev, struct hbm_flow_control *flow) { struct mei_me_client *me_cl; + int rets; me_cl = mei_me_cl_by_id(dev, flow->me_addr); if (!me_cl) { @@ -492,14 +483,19 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev, return -ENOENT; } - if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; + if (WARN_ON(me_cl->props.single_recv_buf == 0)) { + rets = -EINVAL; + goto out; + } me_cl->mei_flow_ctrl_creds++; dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n", flow->me_addr, me_cl->mei_flow_ctrl_creds); - return 0; + rets = 0; +out: + mei_me_cl_put(me_cl); + return rets; } /** diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index ff2755062b4..f8fd503dfbd 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -234,6 +234,18 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) struct mei_me_hw *hw = to_me_hw(dev); u32 hcsr = mei_hcsr_read(hw); + /* H_RST may be found lit before reset is started, + * for example if preceding reset flow hasn't completed. + * In that case asserting H_RST will be ignored, therefore + * we need to clean H_RST bit to start a successful reset sequence. + */ + if ((hcsr & H_RST) == H_RST) { + dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); + hcsr &= ~H_RST; + mei_hcsr_set(hw, hcsr); + hcsr = mei_hcsr_read(hw); + } + hcsr |= H_RST | H_IG | H_IS; if (intr_enable) @@ -323,6 +335,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev) return -ETIME; } + mei_me_hw_reset_release(dev); dev->recvd_hw_ready = false; return 0; } @@ -719,9 +732,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if we need to start the dev */ if (!mei_host_is_ready(dev)) { if (mei_hw_is_ready(dev)) { - mei_me_hw_reset_release(dev); dev_dbg(dev->dev, "we need to start the dev.\n"); - dev->recvd_hw_ready = true; wake_up(&dev->wait_hw_ready); } else { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ae56ba6ca0e..3c019c0e60e 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -303,7 +303,7 @@ 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; + struct mei_me_client *me_cl = NULL; struct mei_cl_cb *write_cb = NULL; struct mei_device *dev; unsigned long timeout = 0; @@ -399,12 +399,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, "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); @@ -433,24 +435,19 @@ static int mei_ioctl_connect_client(struct file *file, cl = file->private_data; dev = cl->dev; - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto end; - } + if (dev->dev_state != MEI_DEV_ENABLED) + return -ENODEV; if (cl->state != MEI_FILE_INITIALIZING && - cl->state != MEI_FILE_DISCONNECTED) { - rets = -EBUSY; - goto end; - } + 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); if (!me_cl || me_cl->props.fixed_address) { dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n", &data->in_client_uuid); - rets = -ENOTTY; - goto end; + return -ENOTTY; } cl->me_client_id = me_cl->client_id; @@ -487,17 +484,16 @@ static int mei_ioctl_connect_client(struct file *file, goto end; } - /* 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"); - rets = mei_cl_connect(cl, file); end: + mei_me_cl_put(me_cl); return rets; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 3dad74a8d49..6c6ce938153 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -172,12 +172,14 @@ struct mei_fw_status { * struct mei_me_client - representation of me (fw) client * * @list: link in me client list + * @refcnt: struct reference count * @props: client properties * @client_id: me client id * @mei_flow_ctrl_creds: flow control credits */ struct mei_me_client { struct list_head list; + struct kref refcnt; struct mei_client_properties props; u8 client_id; u8 mei_flow_ctrl_creds; @@ -345,9 +347,9 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, struct mei_cl_ops *ops); void mei_cl_remove_device(struct mei_cl_device *device); -int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); -int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); -int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length); +ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *dev); int mei_cl_bus_init(void); diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 60ca9240368..bb61a119b8b 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -521,6 +521,7 @@ int mei_nfc_host_init(struct mei_device *dev) cl_info->me_client_id = me_cl->client_id; cl_info->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY); if (ret) @@ -539,6 +540,7 @@ int mei_nfc_host_init(struct mei_device *dev) cl->me_client_id = me_cl->client_id; cl->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); if (ret) diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index b1d892cea94..475f1dea45b 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -76,6 +76,7 @@ int mei_wd_host_init(struct mei_device *dev) cl->me_client_id = me_cl->client_id; cl->cl_uuid = me_cl->props.protocol_name; + mei_me_cl_put(me_cl); ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); |