From b7d885145538ddedb1ae23b782ab7c7c0a856e9f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:31 +0200 Subject: mei: revamp me clients list handling 1. Use rw lock to access the me_clients list 2. Reuse already defined find functions also when removing particular me client 3. Add wrappers for addition and deletion Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 194 +++++++++++++++++++++++++++++++++------------ drivers/misc/mei/client.h | 5 +- drivers/misc/mei/debugfs.c | 19 +++-- drivers/misc/mei/hbm.c | 3 +- drivers/misc/mei/init.c | 1 + drivers/misc/mei/mei_dev.h | 2 + 6 files changed, 162 insertions(+), 62 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index dfbddfe1c7a0..48813c27a47c 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -48,14 +48,14 @@ void mei_me_cl_init(struct mei_me_client *me_cl) */ struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl) { - if (me_cl) - kref_get(&me_cl->refcnt); + if (me_cl && kref_get_unless_zero(&me_cl->refcnt)) + return me_cl; - return me_cl; + return NULL; } /** - * mei_me_cl_release - unlink and free me client + * mei_me_cl_release - free me client * * Locking: called under "dev->device_lock" lock * @@ -65,9 +65,10 @@ 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 * @@ -82,28 +83,87 @@ void mei_me_cl_put(struct mei_me_client *me_cl) } /** - * mei_me_cl_by_uuid - locate me client by uuid + * __mei_me_cl_del - delete me client form the list and decrease + * reference counter + * + * @dev: mei device + * @me_cl: me client + * + * Locking: dev->me_clients_rwsem + */ +static void __mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl) +{ + if (!me_cl) + return; + + list_del(&me_cl->list); + mei_me_cl_put(me_cl); +} + +/** + * mei_me_cl_add - add me client to the list + * + * @dev: mei device + * @me_cl: me client + */ +void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl) +{ + down_write(&dev->me_clients_rwsem); + list_add(&me_cl->list, &dev->me_clients); + up_write(&dev->me_clients_rwsem); +} + +/** + * __mei_me_cl_by_uuid - locate me client by uuid * increases ref count * * @dev: mei device * @uuid: me client uuid * - * Locking: called under "dev->device_lock" lock - * * Return: me client or NULL if not found + * + * Locking: dev->me_clients_rwsem */ -struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, +static struct mei_me_client *__mei_me_cl_by_uuid(struct mei_device *dev, const uuid_le *uuid) { struct mei_me_client *me_cl; + const uuid_le *pn; + + WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem)); - list_for_each_entry(me_cl, &dev->me_clients, list) - if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0) + list_for_each_entry(me_cl, &dev->me_clients, list) { + pn = &me_cl->props.protocol_name; + if (uuid_le_cmp(*uuid, *pn) == 0) return mei_me_cl_get(me_cl); + } return NULL; } +/** + * mei_me_cl_by_uuid - locate me client by uuid + * increases ref count + * + * @dev: mei device + * @uuid: me client uuid + * + * Return: me client or NULL if not found + * + * Locking: dev->me_clients_rwsem + */ +struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev, + const uuid_le *uuid) +{ + struct mei_me_client *me_cl; + + down_read(&dev->me_clients_rwsem); + me_cl = __mei_me_cl_by_uuid(dev, uuid); + up_read(&dev->me_clients_rwsem); + + return me_cl; +} + /** * mei_me_cl_by_id - locate me client by client id * increases ref count @@ -111,22 +171,58 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev, * @dev: the device structure * @client_id: me client id * - * Locking: called under "dev->device_lock" lock - * * Return: me client or NULL if not found + * + * Locking: dev->me_clients_rwsem */ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id) { + struct mei_me_client *__me_cl, *me_cl = NULL; + + down_read(&dev->me_clients_rwsem); + list_for_each_entry(__me_cl, &dev->me_clients, list) { + if (__me_cl->client_id == client_id) { + me_cl = mei_me_cl_get(__me_cl); + break; + } + } + up_read(&dev->me_clients_rwsem); + + return me_cl; +} + +/** + * __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 + * @client_id: me client id + * + * Return: me client or null if not found + * + * Locking: dev->me_clients_rwsem + */ +static struct mei_me_client *__mei_me_cl_by_uuid_id(struct mei_device *dev, + const uuid_le *uuid, u8 client_id) +{ struct mei_me_client *me_cl; + const uuid_le *pn; + + WARN_ON(!rwsem_is_locked(&dev->me_clients_rwsem)); - list_for_each_entry(me_cl, &dev->me_clients, list) - if (me_cl->client_id == client_id) + list_for_each_entry(me_cl, &dev->me_clients, list) { + pn = &me_cl->props.protocol_name; + if (uuid_le_cmp(*uuid, *pn) == 0 && + me_cl->client_id == client_id) 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 @@ -135,21 +231,18 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id) * @uuid: me client uuid * @client_id: me client id * - * Locking: called under "dev->device_lock" lock - * - * Return: me client or NULL if not found + * Return: me client or null if not found */ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 client_id) { struct mei_me_client *me_cl; - 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 mei_me_cl_get(me_cl); + down_read(&dev->me_clients_rwsem); + me_cl = __mei_me_cl_by_uuid_id(dev, uuid, client_id); + up_read(&dev->me_clients_rwsem); - return NULL; + return me_cl; } /** @@ -162,12 +255,14 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev, */ void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid) { - struct mei_me_client *me_cl, *next; + struct mei_me_client *me_cl; 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); + + down_write(&dev->me_clients_rwsem); + me_cl = __mei_me_cl_by_uuid(dev, uuid); + __mei_me_cl_del(dev, me_cl); + up_write(&dev->me_clients_rwsem); } /** @@ -181,15 +276,14 @@ 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) { - struct mei_me_client *me_cl, *next; - const uuid_le *pn; + struct mei_me_client *me_cl; dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id); - list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) { - pn = &me_cl->props.protocol_name; - if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0) - mei_me_cl_put(me_cl); - } + + down_write(&dev->me_clients_rwsem); + me_cl = __mei_me_cl_by_uuid_id(dev, uuid, id); + __mei_me_cl_del(dev, me_cl); + up_write(&dev->me_clients_rwsem); } /** @@ -203,12 +297,12 @@ void mei_me_cl_rm_all(struct mei_device *dev) { struct mei_me_client *me_cl, *next; + down_write(&dev->me_clients_rwsem); list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) - mei_me_cl_put(me_cl); + __mei_me_cl_del(dev, me_cl); + up_write(&dev->me_clients_rwsem); } - - /** * mei_cl_cmp_id - tells if the clients are the same * @@ -535,28 +629,28 @@ int mei_cl_unlink(struct mei_cl *cl) void mei_host_client_init(struct work_struct *work) { - struct mei_device *dev = container_of(work, - struct mei_device, init_work); + struct mei_device *dev = + container_of(work, struct mei_device, init_work); struct mei_me_client *me_cl; - struct mei_client_properties *props; mutex_lock(&dev->device_lock); - list_for_each_entry(me_cl, &dev->me_clients, list) { - props = &me_cl->props; - if (!uuid_le_cmp(props->protocol_name, mei_amthif_guid)) - mei_amthif_host_init(dev); - else if (!uuid_le_cmp(props->protocol_name, mei_wd_guid)) - mei_wd_host_init(dev); - else if (!uuid_le_cmp(props->protocol_name, mei_nfc_guid)) - mei_nfc_host_init(dev); + me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid); + if (me_cl) + mei_amthif_host_init(dev); + + me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid); + if (me_cl) + mei_wd_host_init(dev); + + me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid); + if (me_cl) + mei_nfc_host_init(dev); - } dev->dev_state = MEI_DEV_ENABLED; dev->reset_count = 0; - mutex_unlock(&dev->device_lock); pm_runtime_mark_last_busy(dev->dev); diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index cfcde8e97fc4..80386f9c27e9 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -31,7 +31,10 @@ 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, +void mei_me_cl_add(struct mei_device *dev, struct mei_me_client *me_cl); +void mei_me_cl_del(struct mei_device *dev, struct mei_me_client *me_cl); + +struct mei_me_client *mei_me_cl_by_uuid(struct mei_device *dev, 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, diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index b125380ee871..50fc6635fab1 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -28,7 +28,7 @@ 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, *n; + struct mei_me_client *me_cl; size_t bufsz = 1; char *buf; int i = 0; @@ -38,15 +38,14 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, #define HDR \ " |id|fix| UUID |con|msg len|sb|refc|\n" - mutex_lock(&dev->device_lock); - + down_read(&dev->me_clients_rwsem); list_for_each_entry(me_cl, &dev->me_clients, list) bufsz++; bufsz *= sizeof(HDR) + 1; buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { - mutex_unlock(&dev->device_lock); + up_read(&dev->me_clients_rwsem); return -ENOMEM; } @@ -56,10 +55,9 @@ 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_safe(me_cl, n, &dev->me_clients, list) { + list_for_each_entry(me_cl, &dev->me_clients, list) { - me_cl = mei_me_cl_get(me_cl); - if (me_cl) { + if (mei_me_cl_get(me_cl)) { pos += scnprintf(buf + pos, bufsz - pos, "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n", i++, me_cl->client_id, @@ -69,12 +67,13 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, me_cl->props.max_msg_length, me_cl->props.single_recv_buf, atomic_read(&me_cl->refcnt.refcount)); - } - mei_me_cl_put(me_cl); + mei_me_cl_put(me_cl); + } } + out: - mutex_unlock(&dev->device_lock); + up_read(&dev->me_clients_rwsem); ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos); kfree(buf); return ret; diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index c8412d41e4f1..4f83e9aaa6f9 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -338,7 +338,8 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, me_cl->client_id = res->me_addr; me_cl->mei_flow_ctrl_creds = 0; - list_add(&me_cl->list, &dev->me_clients); + mei_me_cl_add(dev, me_cl); + return 0; } diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 9306219d5675..106c054f573f 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -387,6 +387,7 @@ void mei_device_init(struct mei_device *dev, INIT_LIST_HEAD(&dev->device_list); INIT_LIST_HEAD(&dev->me_clients); mutex_init(&dev->device_lock); + init_rwsem(&dev->me_clients_rwsem); init_waitqueue_head(&dev->wait_hw_ready); init_waitqueue_head(&dev->wait_pg); init_waitqueue_head(&dev->wait_hbm_start); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6c6ce9381535..102cc6603eba 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -460,6 +460,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @version : HBM protocol version in use * @hbm_f_pg_supported : hbm feature pgi protocol * + * @me_clients_rwsem: rw lock over me_clients list * @me_clients : list of FW clients * @me_clients_map : FW clients bit map * @host_clients_map : host clients id pool @@ -556,6 +557,7 @@ struct mei_device { struct hbm_version version; unsigned int hbm_f_pg_supported:1; + struct rw_semaphore me_clients_rwsem; struct list_head me_clients; DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX); -- cgit v1.2.3-55-g7522 From 381a58c70985ca1256b0f51aa6694f79662bb166 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:32 +0200 Subject: mei: me: use io register wrappers consistently 1. Use mei_device structure as the first argument to the io register access wrappers so we'll have access to the device structure needed for tracing. 2. Use wrapper consistently Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 123 +++++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 57 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index f8fd503dfbd6..ac82b56ccbb5 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -61,45 +61,68 @@ static inline void mei_me_reg_write(const struct mei_me_hw *hw, * * Return: ME_CB_RW register value (u32) */ -static u32 mei_me_mecbrw_read(const struct mei_device *dev) +static inline u32 mei_me_mecbrw_read(const struct mei_device *dev) { return mei_me_reg_read(to_me_hw(dev), ME_CB_RW); } + +/** + * mei_me_hcbww_write - write 32bit data to the host circular buffer + * + * @dev: the device structure + * @data: 32bit data to be written to the host circular buffer + */ +static inline void mei_me_hcbww_write(struct mei_device *dev, u32 data) +{ + mei_me_reg_write(to_me_hw(dev), H_CB_WW, data); +} + /** * mei_me_mecsr_read - Reads 32bit data from the ME CSR * - * @hw: the me hardware structure + * @dev: the device structure * * Return: ME_CSR_HA register value (u32) */ -static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw) +static inline u32 mei_me_mecsr_read(const struct mei_device *dev) { - return mei_me_reg_read(hw, ME_CSR_HA); + return mei_me_reg_read(to_me_hw(dev), ME_CSR_HA); } /** * mei_hcsr_read - Reads 32bit data from the host CSR * - * @hw: the me hardware structure + * @dev: the device structure * * Return: H_CSR register value (u32) */ -static inline u32 mei_hcsr_read(const struct mei_me_hw *hw) +static inline u32 mei_hcsr_read(const struct mei_device *dev) { - return mei_me_reg_read(hw, H_CSR); + return mei_me_reg_read(to_me_hw(dev), H_CSR); +} + +/** + * mei_hcsr_write - writes H_CSR register to the mei device + * + * @dev: the device structure + * @reg: new register value + */ +static inline void mei_hcsr_write(struct mei_device *dev, u32 reg) +{ + mei_me_reg_write(to_me_hw(dev), H_CSR, reg); } /** * mei_hcsr_set - writes H_CSR register to the mei device, * and ignores the H_IS bit for it is write-one-to-zero. * - * @hw: the me hardware structure - * @hcsr: new register value + * @dev: the device structure + * @reg: new register value */ -static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr) +static inline void mei_hcsr_set(struct mei_device *dev, u32 reg) { - hcsr &= ~H_IS; - mei_me_reg_write(hw, H_CSR, hcsr); + reg &= ~H_IS; + mei_hcsr_write(dev, reg); } /** @@ -141,7 +164,7 @@ static int mei_me_fw_status(struct mei_device *dev, static void mei_me_hw_config(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(to_me_hw(dev)); + u32 hcsr = mei_hcsr_read(dev); /* Doesn't change in runtime */ dev->hbuf_depth = (hcsr & H_CBD) >> 24; @@ -170,11 +193,10 @@ static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev) */ static void mei_me_intr_clear(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); if ((hcsr & H_IS) == H_IS) - mei_me_reg_write(hw, H_CSR, hcsr); + mei_hcsr_write(dev, hcsr); } /** * mei_me_intr_enable - enables mei device interrupts @@ -183,11 +205,10 @@ static void mei_me_intr_clear(struct mei_device *dev) */ static void mei_me_intr_enable(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); hcsr |= H_IE; - mei_hcsr_set(hw, hcsr); + mei_hcsr_set(dev, hcsr); } /** @@ -197,11 +218,10 @@ static void mei_me_intr_enable(struct mei_device *dev) */ static void mei_me_intr_disable(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); hcsr &= ~H_IE; - mei_hcsr_set(hw, hcsr); + mei_hcsr_set(dev, hcsr); } /** @@ -211,12 +231,11 @@ static void mei_me_intr_disable(struct mei_device *dev) */ static void mei_me_hw_reset_release(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); hcsr |= H_IG; hcsr &= ~H_RST; - mei_hcsr_set(hw, hcsr); + mei_hcsr_set(dev, hcsr); /* complete this write before we set host ready on another CPU */ mmiowb(); @@ -231,8 +250,7 @@ static void mei_me_hw_reset_release(struct mei_device *dev) */ 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); + u32 hcsr = mei_hcsr_read(dev); /* H_RST may be found lit before reset is started, * for example if preceding reset flow hasn't completed. @@ -242,8 +260,8 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) 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); + mei_hcsr_set(dev, hcsr); + hcsr = mei_hcsr_read(dev); } hcsr |= H_RST | H_IG | H_IS; @@ -254,13 +272,13 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) hcsr &= ~H_IE; dev->recvd_hw_ready = false; - mei_me_reg_write(hw, H_CSR, hcsr); + mei_hcsr_write(dev, hcsr); /* * Host reads the H_CSR once to ensure that the * posted write to H_CSR completes. */ - hcsr = mei_hcsr_read(hw); + hcsr = mei_hcsr_read(dev); if ((hcsr & H_RST) == 0) dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr); @@ -281,11 +299,10 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) */ static void mei_me_host_set_ready(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); hcsr |= H_IE | H_IG | H_RDY; - mei_hcsr_set(hw, hcsr); + mei_hcsr_set(dev, hcsr); } /** @@ -296,8 +313,7 @@ static void mei_me_host_set_ready(struct mei_device *dev) */ static bool mei_me_host_is_ready(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); return (hcsr & H_RDY) == H_RDY; } @@ -310,8 +326,7 @@ static bool mei_me_host_is_ready(struct mei_device *dev) */ static bool mei_me_hw_is_ready(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 mecsr = mei_me_mecsr_read(hw); + u32 mecsr = mei_me_mecsr_read(dev); return (mecsr & ME_RDY_HRA) == ME_RDY_HRA; } @@ -368,11 +383,10 @@ static int mei_me_hw_start(struct mei_device *dev) */ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); u32 hcsr; char read_ptr, write_ptr; - hcsr = mei_hcsr_read(hw); + hcsr = mei_hcsr_read(dev); read_ptr = (char) ((hcsr & H_CBRP) >> 8); write_ptr = (char) ((hcsr & H_CBWP) >> 16); @@ -439,7 +453,6 @@ static int mei_me_write_message(struct mei_device *dev, struct mei_msg_hdr *header, unsigned char *buf) { - struct mei_me_hw *hw = to_me_hw(dev); unsigned long rem; unsigned long length = header->length; u32 *reg_buf = (u32 *)buf; @@ -457,21 +470,21 @@ static int mei_me_write_message(struct mei_device *dev, if (empty_slots < 0 || dw_cnt > empty_slots) return -EMSGSIZE; - mei_me_reg_write(hw, H_CB_WW, *((u32 *) header)); + mei_me_hcbww_write(dev, *((u32 *) header)); for (i = 0; i < length / 4; i++) - mei_me_reg_write(hw, H_CB_WW, reg_buf[i]); + mei_me_hcbww_write(dev, reg_buf[i]); rem = length & 0x3; if (rem > 0) { u32 reg = 0; memcpy(®, &buf[length - rem], rem); - mei_me_reg_write(hw, H_CB_WW, reg); + mei_me_hcbww_write(dev, reg); } - hcsr = mei_hcsr_read(hw) | H_IG; - mei_hcsr_set(hw, hcsr); + hcsr = mei_hcsr_read(dev) | H_IG; + mei_hcsr_set(dev, hcsr); if (!mei_me_hw_is_ready(dev)) return -EIO; @@ -487,12 +500,11 @@ static int mei_me_write_message(struct mei_device *dev, */ static int mei_me_count_full_read_slots(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); u32 me_csr; char read_ptr, write_ptr; unsigned char buffer_depth, filled_slots; - me_csr = mei_me_mecsr_read(hw); + me_csr = mei_me_mecsr_read(dev); buffer_depth = (unsigned char)((me_csr & ME_CBD_HRA) >> 24); read_ptr = (char) ((me_csr & ME_CBRP_HRA) >> 8); write_ptr = (char) ((me_csr & ME_CBWP_HRA) >> 16); @@ -518,7 +530,6 @@ static int mei_me_count_full_read_slots(struct mei_device *dev) static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, unsigned long buffer_length) { - struct mei_me_hw *hw = to_me_hw(dev); u32 *reg_buf = (u32 *)buffer; u32 hcsr; @@ -531,8 +542,8 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, memcpy(reg_buf, ®, buffer_length); } - hcsr = mei_hcsr_read(hw) | H_IG; - mei_hcsr_set(hw, hcsr); + hcsr = mei_hcsr_read(dev) | H_IG; + mei_hcsr_set(dev, hcsr); return 0; } @@ -649,8 +660,7 @@ reply: */ static bool mei_me_pg_is_enabled(struct mei_device *dev) { - struct mei_me_hw *hw = to_me_hw(dev); - u32 reg = mei_me_reg_read(hw, ME_CSR_HA); + u32 reg = mei_me_mecsr_read(dev); if ((reg & ME_PGIC_HRA) == 0) goto notsupported; @@ -683,14 +693,13 @@ notsupported: irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) { struct mei_device *dev = (struct mei_device *) dev_id; - struct mei_me_hw *hw = to_me_hw(dev); - u32 csr_reg = mei_hcsr_read(hw); + u32 hcsr = mei_hcsr_read(dev); - if ((csr_reg & H_IS) != H_IS) + if ((hcsr & H_IS) != H_IS) return IRQ_NONE; /* clear H_IS bit in H_CSR */ - mei_me_reg_write(hw, H_CSR, csr_reg); + mei_hcsr_write(dev, hcsr); return IRQ_WAKE_THREAD; } -- cgit v1.2.3-55-g7522 From a0a927d06d79d59c55ae7ac0b2fd7f3c0ea3c14c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:33 +0200 Subject: mei: me: add io register tracing To make debugging a bit easier we add me register access tracing /tracing/events/mei/mei_reg_{read,write} Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/Makefile | 3 ++ drivers/misc/mei/hw-me.c | 31 ++++++++++++++++--- drivers/misc/mei/mei-trace.c | 25 +++++++++++++++ drivers/misc/mei/mei-trace.h | 74 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 drivers/misc/mei/mei-trace.c create mode 100644 drivers/misc/mei/mei-trace.h (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 8ebc6cda1373..518914a82b83 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -21,3 +21,6 @@ mei-me-objs += hw-me.o obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o mei-txe-objs := pci-txe.o mei-txe-objs += hw-txe.o + +mei-$(CONFIG_EVENT_TRACING) += mei-trace.o +CFLAGS_mei-trace.o = -I$(src) diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index ac82b56ccbb5..d3aef82a6c89 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -25,6 +25,8 @@ #include "hw-me.h" #include "hw-me-regs.h" +#include "mei-trace.h" + /** * mei_me_reg_read - Reads 32bit data from the mei device * @@ -86,7 +88,12 @@ static inline void mei_me_hcbww_write(struct mei_device *dev, u32 data) */ static inline u32 mei_me_mecsr_read(const struct mei_device *dev) { - return mei_me_reg_read(to_me_hw(dev), ME_CSR_HA); + u32 reg; + + reg = mei_me_reg_read(to_me_hw(dev), ME_CSR_HA); + trace_mei_reg_read(dev->dev, "ME_CSR_HA", ME_CSR_HA, reg); + + return reg; } /** @@ -98,7 +105,12 @@ static inline u32 mei_me_mecsr_read(const struct mei_device *dev) */ static inline u32 mei_hcsr_read(const struct mei_device *dev) { - return mei_me_reg_read(to_me_hw(dev), H_CSR); + u32 reg; + + reg = mei_me_reg_read(to_me_hw(dev), H_CSR); + trace_mei_reg_read(dev->dev, "H_CSR", H_CSR, reg); + + return reg; } /** @@ -109,6 +121,7 @@ static inline u32 mei_hcsr_read(const struct mei_device *dev) */ static inline void mei_hcsr_write(struct mei_device *dev, u32 reg) { + trace_mei_reg_write(dev->dev, "H_CSR", H_CSR, reg); mei_me_reg_write(to_me_hw(dev), H_CSR, reg); } @@ -555,9 +568,14 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, static void mei_me_pg_enter(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); - u32 reg = mei_me_reg_read(hw, H_HPG_CSR); + u32 reg; + + reg = mei_me_reg_read(hw, H_HPG_CSR); + trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); reg |= H_HPG_CSR_PGI; + + trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); mei_me_reg_write(hw, H_HPG_CSR, reg); } @@ -569,11 +587,16 @@ static void mei_me_pg_enter(struct mei_device *dev) static void mei_me_pg_exit(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); - u32 reg = mei_me_reg_read(hw, H_HPG_CSR); + u32 reg; + + reg = mei_me_reg_read(hw, H_HPG_CSR); + trace_mei_reg_read(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); WARN(!(reg & H_HPG_CSR_PGI), "PGI is not set\n"); reg |= H_HPG_CSR_PGIHEXR; + + trace_mei_reg_write(dev->dev, "H_HPG_CSR", H_HPG_CSR, reg); mei_me_reg_write(hw, H_HPG_CSR, reg); } diff --git a/drivers/misc/mei/mei-trace.c b/drivers/misc/mei/mei-trace.c new file mode 100644 index 000000000000..388efb519138 --- /dev/null +++ b/drivers/misc/mei/mei-trace.c @@ -0,0 +1,25 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#include + +/* sparse doesn't like tracepoint macros */ +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "mei-trace.h" + +EXPORT_TRACEPOINT_SYMBOL(mei_reg_read); +EXPORT_TRACEPOINT_SYMBOL(mei_reg_write); +#endif /* __CHECKER__ */ diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h new file mode 100644 index 000000000000..d5c38d15cdd9 --- /dev/null +++ b/drivers/misc/mei/mei-trace.h @@ -0,0 +1,74 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#if !defined(_MEI_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _MEI_TRACE_H_ + +#include +#include +#include + +#undef TRACE_SYSTEM + +#define TRACE_SYSTEM mei +#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) + +TRACE_EVENT(mei_reg_read, + TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), + TP_ARGS(dev, reg, offs, val), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __field(const char *, reg) + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)) + __entry->reg = reg; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%s] read %s:[%#x] = %#x", + __get_str(dev), __entry->reg, __entry->offs, __entry->val) +); + +TRACE_EVENT(mei_reg_write, + TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), + TP_ARGS(dev, reg, offs, val), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __field(const char *, reg) + __field(u32, offs) + __field(u32, val) + ), + TP_fast_assign( + __assign_str(dev, dev_name(dev)) + __entry->reg = reg; + __entry->offs = offs; + __entry->val = val; + ), + TP_printk("[%s] write %s[%#x] = %#x)", + __get_str(dev), __entry->reg, __entry->offs, __entry->val) +); + +#endif /* _MEI_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE mei-trace +#include -- cgit v1.2.3-55-g7522 From 2d1995fce3f9b9a0bdb88d47144509e3b84db0f9 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 10 Feb 2015 10:39:34 +0200 Subject: mei: me: change power gating function name conventions The current power gating naming was confusing, we wish to swap meanings of register and flow level power gating terms, For registers writing level use terms set and unset: mei_me_pg_set, mei_me_pg_unset For flow/high level use power gating enter and power gating exit terms mei_me_pg_enter_sync, mei_me_pg_exit_sync Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 20 ++++++++++---------- drivers/misc/mei/hw-me.h | 4 ++-- drivers/misc/mei/pci-me.c | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index d3aef82a6c89..6fb75e62a764 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -561,11 +561,11 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, } /** - * mei_me_pg_enter - write pg enter register + * mei_me_pg_set - write pg enter register * * @dev: the device structure */ -static void mei_me_pg_enter(struct mei_device *dev) +static void mei_me_pg_set(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); u32 reg; @@ -580,11 +580,11 @@ static void mei_me_pg_enter(struct mei_device *dev) } /** - * mei_me_pg_exit - write pg exit register + * mei_me_pg_unset - write pg exit register * * @dev: the device structure */ -static void mei_me_pg_exit(struct mei_device *dev) +static void mei_me_pg_unset(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); u32 reg; @@ -601,13 +601,13 @@ static void mei_me_pg_exit(struct mei_device *dev) } /** - * mei_me_pg_set_sync - perform pg entry procedure + * mei_me_pg_enter_sync - perform pg entry procedure * * @dev: the device structure * * Return: 0 on success an error code otherwise */ -int mei_me_pg_set_sync(struct mei_device *dev) +int mei_me_pg_enter_sync(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); @@ -625,7 +625,7 @@ int mei_me_pg_set_sync(struct mei_device *dev) mutex_lock(&dev->device_lock); if (dev->pg_event == MEI_PG_EVENT_RECEIVED) { - mei_me_pg_enter(dev); + mei_me_pg_set(dev); ret = 0; } else { ret = -ETIME; @@ -638,13 +638,13 @@ int mei_me_pg_set_sync(struct mei_device *dev) } /** - * mei_me_pg_unset_sync - perform pg exit procedure + * mei_me_pg_exit_sync - perform pg exit procedure * * @dev: the device structure * * Return: 0 on success an error code otherwise */ -int mei_me_pg_unset_sync(struct mei_device *dev) +int mei_me_pg_exit_sync(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); @@ -655,7 +655,7 @@ int mei_me_pg_unset_sync(struct mei_device *dev) dev->pg_event = MEI_PG_EVENT_WAIT; - mei_me_pg_exit(dev); + mei_me_pg_unset(dev); mutex_unlock(&dev->device_lock); wait_event_timeout(dev->wait_pg, diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index d6567af44377..6022d52af6f6 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -71,8 +71,8 @@ extern const struct mei_cfg mei_me_pch8_sps_cfg; struct mei_device *mei_me_dev_init(struct pci_dev *pdev, const struct mei_cfg *cfg); -int mei_me_pg_set_sync(struct mei_device *dev); -int mei_me_pg_unset_sync(struct mei_device *dev); +int mei_me_pg_enter_sync(struct mei_device *dev); +int mei_me_pg_exit_sync(struct mei_device *dev); irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index bd3039ab8f98..72fb381a1245 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -389,7 +389,7 @@ static int mei_me_pm_runtime_suspend(struct device *device) mutex_lock(&dev->device_lock); if (mei_write_is_idle(dev)) - ret = mei_me_pg_set_sync(dev); + ret = mei_me_pg_enter_sync(dev); else ret = -EAGAIN; @@ -414,7 +414,7 @@ static int mei_me_pm_runtime_resume(struct device *device) mutex_lock(&dev->device_lock); - ret = mei_me_pg_unset_sync(dev); + ret = mei_me_pg_exit_sync(dev); mutex_unlock(&dev->device_lock); -- cgit v1.2.3-55-g7522 From 3908be6f9aa5517bc717f8ffdaaafd89a1b78471 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 10 Feb 2015 10:39:35 +0200 Subject: mei: fix function names and format in KDoc Align functions names in KDoc with real ones. Fix comment format to be KDoc and fix wrong syntax there. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 9 +++++---- drivers/misc/mei/hw-txe.c | 2 +- drivers/misc/mei/pci-txe.c | 4 ++-- drivers/misc/mei/wd.c | 18 +++++++++--------- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 48813c27a47c..3e9cf0db5540 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -321,7 +321,7 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, } /** - * mei_io_list_flush - removes cbs belonging to cl. + * __mei_io_list_flush - removes and frees cbs belonging to cl. * * @list: an instance of our list structure * @cl: host client, can be NULL for flushing the whole list @@ -540,10 +540,11 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) return NULL; } -/** mei_cl_link: allocate host id in the host map +/** + * mei_cl_link - allocate host id in the host map * - * @cl - host client - * @id - fixed host id or -1 for generic one + * @cl: host client + * @id: fixed host id or -1 for generic one * * Return: 0 on success * -EINVAL on incorrect values diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index 618ea721aca8..7abafe7d120d 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c @@ -412,7 +412,7 @@ static void mei_txe_intr_disable(struct mei_device *dev) mei_txe_br_reg_write(hw, HIER_REG, 0); } /** - * mei_txe_intr_disable - enable all interrupts + * mei_txe_intr_enable - enable all interrupts * * @dev: the device structure */ diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index c86e2ddbe30a..dcfcba44b6f7 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c @@ -63,7 +63,7 @@ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) } } /** - * mei_probe - Device Initialization Routine + * mei_txe_probe - Device Initialization Routine * * @pdev: PCI device structure * @ent: entry in mei_txe_pci_tbl @@ -193,7 +193,7 @@ end: } /** - * mei_remove - Device Removal Routine + * mei_txe_remove - Device Removal Routine * * @pdev: PCI device structure * diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 475f1dea45bf..ac1e6235692d 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -202,10 +202,10 @@ err: return ret; } -/* +/** * mei_wd_ops_start - wd start command from the watchdog core. * - * @wd_dev - watchdog device struct + * @wd_dev: watchdog device struct * * Return: 0 if success, negative errno code for failure */ @@ -239,10 +239,10 @@ end_unlock: return err; } -/* +/** * mei_wd_ops_stop - wd stop command from the watchdog core. * - * @wd_dev - watchdog device struct + * @wd_dev: watchdog device struct * * Return: 0 if success, negative errno code for failure */ @@ -261,10 +261,10 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev) return 0; } -/* +/** * mei_wd_ops_ping - wd ping command from the watchdog core. * - * @wd_dev - watchdog device struct + * @wd_dev: watchdog device struct * * Return: 0 if success, negative errno code for failure */ @@ -311,11 +311,11 @@ end: return ret; } -/* +/** * mei_wd_ops_set_timeout - wd set timeout command from the watchdog core. * - * @wd_dev - watchdog device struct - * @timeout - timeout value to set + * @wd_dev: watchdog device struct + * @timeout: timeout value to set * * Return: 0 if success, negative errno code for failure */ -- cgit v1.2.3-55-g7522 From 3d33ff2457355a9dd3c3178b04ab6669882b306c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:36 +0200 Subject: mei: fix device reset on mei_cl_irq_read_msg allocation failure On memory allocation failure mei_cl_irq_read_msg will return with error that will cause device reset. Instead we should propagate error to caller and just clean the read queues. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 6 +++ drivers/misc/mei/interrupt.c | 117 ++++++++++++++++++++++--------------------- drivers/misc/mei/main.c | 17 +++++-- drivers/misc/mei/mei_dev.h | 2 + 4 files changed, 80 insertions(+), 62 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index be767f4db26a..025626f4467d 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -322,10 +322,16 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) goto out; } + if (cb->status) { + rets = cb->status; + goto free; + } + r_length = min_t(size_t, length, cb->buf_idx); memcpy(buf, cb->response_buffer.data, r_length); rets = r_length; +free: mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; cl->read_cb = NULL; diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 711cddfa9c99..587cb04a3cf5 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -69,85 +69,91 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl, cl->me_client_id == mei_hdr->me_addr; } /** - * mei_cl_is_reading - checks if the client - * is the one to read this message + * mei_cl_is_reading - checks if the client is in reading state * * @cl: mei client - * @mei_hdr: header of mei message * - * Return: true on match and false otherwise + * Return: true if the client is reading */ -static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr) +static bool mei_cl_is_reading(struct mei_cl *cl) { - return mei_cl_hbm_equal(cl, mei_hdr) && - cl->state == MEI_FILE_CONNECTED && + return cl->state == MEI_FILE_CONNECTED && cl->reading_state != MEI_READ_COMPLETE; } /** * mei_cl_irq_read_msg - process client message * - * @dev: the device structure + * @cl: reading client * @mei_hdr: header of mei client message - * @complete_list: An instance of our list structure + * @complete_list: completion list * - * Return: 0 on success, <0 on failure. + * Return: always 0 */ -static int mei_cl_irq_read_msg(struct mei_device *dev, +static int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *complete_list) { - struct mei_cl *cl; - struct mei_cl_cb *cb, *next; + struct mei_device *dev = cl->dev; + struct mei_cl_cb *cb; unsigned char *buffer = NULL; - list_for_each_entry_safe(cb, next, &dev->read_list.list, list) { - cl = cb->cl; - if (!mei_cl_is_reading(cl, mei_hdr)) - continue; + list_for_each_entry(cb, &dev->read_list.list, list) { + if (cl == cb->cl) + break; + } - cl->reading_state = MEI_READING; + if (&cb->list == &dev->read_list.list) { + dev_err(dev->dev, "no reader found\n"); + goto out; + } - if (cb->response_buffer.size == 0 || - cb->response_buffer.data == NULL) { - cl_err(dev, cl, "response buffer is not allocated.\n"); - list_del(&cb->list); - return -ENOMEM; - } + if (!mei_cl_is_reading(cl)) { + cl_err(dev, cl, "cl is not reading state=%d reading state=%d\n", + cl->state, cl->reading_state); + goto out; + } - if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { - cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", - cb->response_buffer.size, - mei_hdr->length, cb->buf_idx); - buffer = krealloc(cb->response_buffer.data, - mei_hdr->length + cb->buf_idx, - GFP_KERNEL); - - if (!buffer) { - list_del(&cb->list); - return -ENOMEM; - } - cb->response_buffer.data = buffer; - cb->response_buffer.size = - mei_hdr->length + cb->buf_idx; - } + cl->reading_state = MEI_READING; - buffer = cb->response_buffer.data + cb->buf_idx; - mei_read_slots(dev, buffer, mei_hdr->length); + if (cb->response_buffer.size == 0 || + cb->response_buffer.data == NULL) { + cl_err(dev, cl, "response buffer is not allocated.\n"); + list_move_tail(&cb->list, &complete_list->list); + cb->status = -ENOMEM; + goto out; + } - cb->buf_idx += mei_hdr->length; - if (mei_hdr->msg_complete) { - cl->status = 0; - list_del(&cb->list); - cl_dbg(dev, cl, "completed read length = %lu\n", - cb->buf_idx); - list_add_tail(&cb->list, &complete_list->list); + if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { + cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", + cb->response_buffer.size, mei_hdr->length, cb->buf_idx); + buffer = krealloc(cb->response_buffer.data, + mei_hdr->length + cb->buf_idx, + GFP_KERNEL); + + if (!buffer) { + cb->status = -ENOMEM; + list_move_tail(&cb->list, &complete_list->list); + goto out; } - break; + cb->response_buffer.data = buffer; + cb->response_buffer.size = mei_hdr->length + cb->buf_idx; } - dev_dbg(dev->dev, "message read\n"); + buffer = cb->response_buffer.data + cb->buf_idx; + mei_read_slots(dev, buffer, mei_hdr->length); + + cb->buf_idx += mei_hdr->length; + if (mei_hdr->msg_complete) { + cl_dbg(dev, cl, "completed read length = %lu\n", + cb->buf_idx); + list_move_tail(&cb->list, &complete_list->list); + } + +out: if (!buffer) { + /* assume that mei_hdr->length <= MEI_RD_MSG_BUF_SIZE */ + BUG_ON(mei_hdr->length > MEI_RD_MSG_BUF_SIZE); mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", MEI_HDR_PRM(mei_hdr)); @@ -389,14 +395,10 @@ int mei_irq_read_handler(struct mei_device *dev, goto end; } } else { - ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list); - if (ret) { - dev_err(dev->dev, "mei_cl_irq_read_msg failed = %d\n", - ret); - goto end; - } + ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); } + reset_slots: /* reset the number of slots and header */ *slots = mei_count_full_read_slots(dev); @@ -636,4 +638,3 @@ out: schedule_delayed_work(&dev->timer_work, 2 * HZ); mutex_unlock(&dev->device_lock); } - diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 3c019c0e60eb..cbdbf4af2bf7 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -192,8 +192,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, goto out; } - if (cl->read_cb) { - cb = cl->read_cb; + cb = cl->read_cb; + if (cb) { /* read what left */ if (cb->buf_idx > *offset) goto copy_buffer; @@ -218,7 +218,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, } if (MEI_READ_COMPLETE != cl->reading_state && - !waitqueue_active(&cl->rx_wait)) { + !waitqueue_active(&cl->rx_wait)) { + if (file->f_flags & O_NONBLOCK) { rets = -EAGAIN; goto out; @@ -248,12 +249,20 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, rets = -ENODEV; goto out; } + if (cl->reading_state != MEI_READ_COMPLETE) { rets = 0; goto out; } - /* now copy the data to user space */ + copy_buffer: + /* now copy the data to user space */ + if (cb->status) { + rets = cb->status; + dev_dbg(dev->dev, "read operation failed %d\n", rets); + goto free; + } + dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n", cb->response_buffer.size, cb->buf_idx); if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 102cc6603eba..195e426b08f0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -199,6 +199,7 @@ struct mei_cl; * @buf_idx: last read index * @read_time: last read operation time stamp (iamthif) * @file_object: pointer to file structure + * @status: io status of the cb * @internal: communication between driver and FW flag */ struct mei_cl_cb { @@ -210,6 +211,7 @@ struct mei_cl_cb { unsigned long buf_idx; unsigned long read_time; struct file *file_object; + int status; u32 internal:1; }; -- cgit v1.2.3-55-g7522 From db4756fd2f16efae8469dd1e37710919a0af9370 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:37 +0200 Subject: mei: iamthif: fix device reset on mei_amthif_irq_read_msg On failure mei_amthif_irq_read_msg returns an error that will cause device reset but the issue is software one so instead we should propagate error to caller and just clean the read queues. As a side effect also removes useless BUG_ONs Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 76 ++++++++++++++++++++++++++++---------------- drivers/misc/mei/interrupt.c | 7 ++-- drivers/misc/mei/mei_dev.h | 2 +- 3 files changed, 51 insertions(+), 34 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index c4cb9a984a5f..2ad2f94678c8 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -195,23 +195,26 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, dev_dbg(dev->dev, "woke up from sleep\n"); } + if (cb->status) { + rets = cb->status; + dev_dbg(dev->dev, "read operation failed %d\n", rets); + goto free; + } dev_dbg(dev->dev, "Got amthif data\n"); dev->iamthif_timer = 0; - if (cb) { - timeout = cb->read_time + - mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); - dev_dbg(dev->dev, "amthif timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(dev->dev, "amthif Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->list); - rets = -ETIME; - goto free; - } + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); + dev_dbg(dev->dev, "amthif timeout = %lud\n", + timeout); + + if (time_after(jiffies, timeout)) { + dev_dbg(dev->dev, "amthif Time out\n"); + /* 15 sec for the message has expired */ + list_del(&cb->list); + rets = -ETIME; + goto free; } /* if the whole message will fit remove it from the list */ if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) @@ -501,25 +504,42 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, * mei_amthif_irq_read_msg - read routine after ISR to * handle the read amthif message * - * @dev: the device structure + * @cl: mei client * @mei_hdr: header of amthif message - * @complete_list: An instance of our list structure + * @complete_list: completed callbacks list * - * Return: 0 on success, <0 on failure. + * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status */ -int mei_amthif_irq_read_msg(struct mei_device *dev, +int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *complete_list) { + struct mei_device *dev; struct mei_cl_cb *cb; unsigned char *buffer; + int ret = 0; - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); + dev = cl->dev; - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); + if (cl->state != MEI_FILE_CONNECTED) + goto err; + + if (dev->iamthif_state != MEI_IAMTHIF_READING) + goto err; + + cb = dev->iamthif_current_cb; + if (!cb) { + ret = -ENODEV; + goto err; + } + + if (dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length) { + cb->status = -ERANGE; + goto err; + } + + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; mei_read_slots(dev, buffer, mei_hdr->length); dev->iamthif_msg_buf_index += mei_hdr->length; @@ -527,14 +547,8 @@ int mei_amthif_irq_read_msg(struct mei_device *dev, if (!mei_hdr->msg_complete) return 0; - dev_dbg(dev->dev, "amthif_message_buffer_index =%d\n", - mei_hdr->length); - dev_dbg(dev->dev, "completed amthif read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - cb = dev->iamthif_current_cb; dev->iamthif_current_cb = NULL; dev->iamthif_stall_timer = 0; @@ -543,10 +557,16 @@ int mei_amthif_irq_read_msg(struct mei_device *dev, if (dev->iamthif_ioctl) { /* found the iamthif cb */ dev_dbg(dev->dev, "complete the amthif read cb.\n "); - dev_dbg(dev->dev, "add the amthif read cb to complete.\n "); list_add_tail(&cb->list, &complete_list->list); } + return 0; + +err: + mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); + dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", + MEI_HDR_PRM(mei_hdr)); + return ret; } /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 587cb04a3cf5..151f0c84a65e 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -384,11 +384,8 @@ int mei_irq_read_handler(struct mei_device *dev, goto end; } - if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && - MEI_FILE_CONNECTED == dev->iamthif_cl.state && - dev->iamthif_state == MEI_IAMTHIF_READING) { - - ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list); + if (cl == &dev->iamthif_cl) { + ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list); if (ret) { dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n", ret); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 195e426b08f0..b74d156ed600 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -685,7 +685,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); -int mei_amthif_irq_read_msg(struct mei_device *dev, +int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, struct mei_cl_cb *complete_list); int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); -- cgit v1.2.3-55-g7522 From 4e097bc5d5c948ff8a60ac38a5826f5b6699603d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:38 +0200 Subject: mei: iamthif: remove useless iamthif_ioctl variable iamthif_ioctl is obsolete and can be safely dropped Currently it is set to true during driver runtime Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 11 +++-------- drivers/misc/mei/interrupt.c | 1 - drivers/misc/mei/mei_dev.h | 2 -- 3 files changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 2ad2f94678c8..788b00e23353 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -52,7 +52,6 @@ void mei_amthif_reset_params(struct mei_device *dev) dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; - dev->iamthif_ioctl = false; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; dev->iamthif_stall_timer = 0; @@ -279,7 +278,6 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) dev->iamthif_current_cb = cb; dev->iamthif_file_object = cb->file_object; dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; dev->iamthif_msg_buf_size = cb->request_buffer.size; memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, cb->request_buffer.size); @@ -375,7 +373,6 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; dev->iamthif_file_object = NULL; @@ -554,11 +551,9 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, dev->iamthif_stall_timer = 0; cb->buf_idx = dev->iamthif_msg_buf_index; cb->read_time = jiffies; - if (dev->iamthif_ioctl) { - /* found the iamthif cb */ - dev_dbg(dev->dev, "complete the amthif read cb.\n "); - list_add_tail(&cb->list, &complete_list->list); - } + + dev_dbg(dev->dev, "complete the amthif read cb.\n "); + list_add_tail(&cb->list, &complete_list->list); return 0; diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 151f0c84a65e..4cb602fba593 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -589,7 +589,6 @@ void mei_timer(struct work_struct *work) dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index b74d156ed600..6cc68de580ba 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -488,7 +488,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @iamthif_msg_buf_index : current index in amthif message request buffer * @iamthif_state : amthif processor state * @iamthif_flow_control_pending: amthif waits for flow control - * @iamthif_ioctl : wait for completion if amthif control message * @iamthif_canceled : current amthif command is canceled * * @init_work : work item for the device init @@ -588,7 +587,6 @@ struct mei_device { u32 iamthif_msg_buf_index; enum iamthif_states iamthif_state; bool iamthif_flow_control_pending; - bool iamthif_ioctl; bool iamthif_canceled; struct work_struct init_work; -- cgit v1.2.3-55-g7522 From c54bf3ab7536e062b507b625bfd2befb9b2cb841 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:39 +0200 Subject: mei: iamthif: send flow control as a regular client Reuse common client mechanism for sending flow control hbm message. Add new function mei_amthif_read_start similar to mei_cl_read_start that puts control flow request onto the control write queue and drop mei_amthif_irq_read function Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 134 +++++++++++++++++++++++-------------------- drivers/misc/mei/interrupt.c | 25 ++------ drivers/misc/mei/mei_dev.h | 2 - 3 files changed, 77 insertions(+), 84 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 788b00e23353..e6f7180fd8f2 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -254,6 +254,47 @@ out: return rets; } +/** + * mei_amthif_read_start - queue message for sending read credential + * + * @cl: host client + * @file: file pointer of message recipient + * + * Return: 0 on success, <0 on failure. + */ +static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) +{ + struct mei_device *dev = cl->dev; + struct mei_cl_cb *cb; + size_t length = dev->iamthif_mtu; + int rets; + + cb = mei_io_cb_init(cl, file); + if (!cb) { + rets = -ENOMEM; + goto err; + } + + rets = mei_io_cb_alloc_resp_buf(cb, length); + if (rets) + goto err; + + cb->fop_type = MEI_FOP_READ; + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + + dev->iamthif_msg_buf_index = 0; + dev->iamthif_msg_buf_size = 0; + + dev->iamthif_state = MEI_IAMTHIF_READING; + dev->iamthif_file_object = cb->file_object; + dev->iamthif_current_cb = cb; + + return 0; +err: + mei_io_cb_free(cb); + return rets; +} + /** * mei_amthif_send_cmd - send amthif command to the ME * @@ -287,6 +328,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) if (ret < 0) return ret; + cb->fop_type = MEI_FOP_WRITE; if (ret && mei_hbuf_acquire(dev)) { ret = 0; if (cb->request_buffer.size > mei_hbuf_max_len(dev)) { @@ -309,19 +351,17 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) if (mei_hdr.msg_complete) { if (mei_cl_flow_ctrl_reduce(cl)) return -EIO; - dev->iamthif_flow_control_pending = true; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(dev->dev, "add amthif cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; + cb->status = mei_amthif_read_start(cl, cb->file_object); list_add_tail(&cb->list, &dev->write_waiting_list.list); } else { dev_dbg(dev->dev, "message does not complete, so add amthif cb to write list.\n"); list_add_tail(&cb->list, &dev->write_list.list); } } else { + list_add_tail(&cb->list, &dev->write_list.list); } + return 0; } @@ -336,17 +376,10 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) */ int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) { - int ret; - if (!dev || !cb) return -ENODEV; - ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); - if (ret) - return ret; - cb->fop_type = MEI_FOP_WRITE; - if (!list_empty(&dev->amthif_cmd_list.list) || dev->iamthif_state != MEI_IAMTHIF_IDLE) { dev_dbg(dev->dev, @@ -383,7 +416,7 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) typeof(*cb), list); if (!cb) return; - list_del(&cb->list); + list_del_init(&cb->list); ret = mei_amthif_send_cmd(dev, cb); if (ret) dev_warn(dev->dev, "amthif write failed status = %d\n", ret); @@ -483,13 +516,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cl->status = 0; if (mei_hdr.msg_complete) { - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - - /* save iamthif cb sent to amthif client */ - cb->buf_idx = dev->iamthif_msg_buf_index; - dev->iamthif_current_cb = cb; - + cb->status = mei_amthif_read_start(cl, cb->file_object); list_move_tail(&cb->list, &dev->write_waiting_list.list); } @@ -505,7 +532,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, * @mei_hdr: header of amthif message * @complete_list: completed callbacks list * - * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status + * Return: Always 0; error message is in cb->status */ int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, @@ -514,7 +541,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_device *dev; struct mei_cl_cb *cb; unsigned char *buffer; - int ret = 0; dev = cl->dev; @@ -524,10 +550,13 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, if (dev->iamthif_state != MEI_IAMTHIF_READING) goto err; - cb = dev->iamthif_current_cb; + list_for_each_entry(cb, &dev->read_list.list, list) { + if (cl == cb->cl) + break; + } - if (!cb) { - ret = -ENODEV; + if (&cb->list == &dev->read_list.list) { + dev_err(dev->dev, "no reader found\n"); goto err; } @@ -553,7 +582,7 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl, cb->read_time = jiffies; dev_dbg(dev->dev, "complete the amthif read cb.\n "); - list_add_tail(&cb->list, &complete_list->list); + list_move_tail(&cb->list, &complete_list->list); return 0; @@ -561,38 +590,6 @@ err: mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", MEI_HDR_PRM(mei_hdr)); - return ret; -} - -/** - * mei_amthif_irq_read - prepares to read amthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * Return: 0, OK; otherwise, error. - */ -int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) -{ - u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control)); - - if (*slots < msg_slots) - return -EMSGSIZE; - - *slots -= msg_slots; - - if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) { - dev_dbg(dev->dev, "iamthif flow control failed\n"); - return -EIO; - } - - dev_dbg(dev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = false; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; - dev->hbuf_is_ready = mei_hbuf_is_ready(dev); return 0; } @@ -604,17 +601,32 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) */ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) { + + if (cb->fop_type == MEI_FOP_WRITE) { + if (!cb->status) { + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; + mei_io_cb_free(cb); + return; + } + /* + * in case of error enqueue the write cb to complete read list + * so it can be propagated to the reader + */ + list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); + wake_up_interruptible(&dev->iamthif_cl.wait); + return; + } + if (dev->iamthif_canceled != 1) { dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; dev->iamthif_stall_timer = 0; memcpy(cb->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); + dev->iamthif_msg_buf, dev->iamthif_msg_buf_index); list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); dev_dbg(dev->dev, "amthif read completed\n"); dev->iamthif_timer = jiffies; dev_dbg(dev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); + dev->iamthif_timer); } else { mei_amthif_run_next_cmd(dev); } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 4cb602fba593..89f2fbce160f 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -43,7 +43,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list) list_for_each_entry_safe(cb, next, &compl_list->list, list) { cl = cb->cl; - list_del(&cb->list); + list_del_init(&cb->list); dev_dbg(dev->dev, "completing call back.\n"); if (cl == &dev->iamthif_cl) @@ -386,11 +386,6 @@ int mei_irq_read_handler(struct mei_device *dev, if (cl == &dev->iamthif_cl) { ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list); - if (ret) { - dev_err(dev->dev, "mei_amthif_irq_read_msg failed = %d\n", - ret); - goto end; - } } else { ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); } @@ -448,21 +443,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) cl = cb->cl; cl->status = 0; - list_del(&cb->list); - if (cb->fop_type == MEI_FOP_WRITE && - cl != &dev->iamthif_cl) { - cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); - cl->writing_state = MEI_WRITE_COMPLETE; - list_add_tail(&cb->list, &cmpl_list->list); - } - if (cl == &dev->iamthif_cl) { - cl_dbg(dev, cl, "check iamthif flow control.\n"); - if (dev->iamthif_flow_control_pending) { - ret = mei_amthif_irq_read(dev, &slots); - if (ret) - return ret; - } - } + cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); + cl->writing_state = MEI_WRITE_COMPLETE; + list_move_tail(&cb->list, &cmpl_list->list); } if (dev->wd_state == MEI_WD_STOPPING) { diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6cc68de580ba..fc460af131d4 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -487,7 +487,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @iamthif_msg_buf_size : size of current amthif message request buffer * @iamthif_msg_buf_index : current index in amthif message request buffer * @iamthif_state : amthif processor state - * @iamthif_flow_control_pending: amthif waits for flow control * @iamthif_canceled : current amthif command is canceled * * @init_work : work item for the device init @@ -586,7 +585,6 @@ struct mei_device { u32 iamthif_msg_buf_size; u32 iamthif_msg_buf_index; enum iamthif_states iamthif_state; - bool iamthif_flow_control_pending; bool iamthif_canceled; struct work_struct init_work; -- cgit v1.2.3-55-g7522 From 8660172e1d6528be02eba78516ff8282e694bb26 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:40 +0200 Subject: mei: iamthif: use client write functions Reduce code duplication in amthif code by reusing regular client write functions. Add completed flag to cb so amthif client can add rx credits on write completion Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 178 +++++++++++---------------------------------- drivers/misc/mei/client.c | 2 + drivers/misc/mei/main.c | 2 +- drivers/misc/mei/mei_dev.h | 8 +- 4 files changed, 51 insertions(+), 139 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index e6f7180fd8f2..916625a8f037 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -298,110 +298,47 @@ err: /** * mei_amthif_send_cmd - send amthif command to the ME * - * @dev: the device structure + * @cl: the host client * @cb: mei call back struct * * Return: 0 on success, <0 on failure. - * */ -static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) +static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb) { - struct mei_msg_hdr mei_hdr; - struct mei_cl *cl; + struct mei_device *dev; int ret; - if (!dev || !cb) + if (!cl->dev || !cb) return -ENODEV; - dev_dbg(dev->dev, "write data to amthif client.\n"); + dev = cl->dev; dev->iamthif_state = MEI_IAMTHIF_WRITING; dev->iamthif_current_cb = cb; dev->iamthif_file_object = cb->file_object; dev->iamthif_canceled = false; - dev->iamthif_msg_buf_size = cb->request_buffer.size; - memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); - cl = &dev->iamthif_cl; - ret = mei_cl_flow_ctrl_creds(cl); + ret = mei_cl_write(cl, cb, false); if (ret < 0) return ret; - cb->fop_type = MEI_FOP_WRITE; - if (ret && mei_hbuf_acquire(dev)) { - ret = 0; - if (cb->request_buffer.size > mei_hbuf_max_len(dev)) { - mei_hdr.length = mei_hbuf_max_len(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = cb->request_buffer.size; - mei_hdr.msg_complete = 1; - } - - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - mei_hdr.internal = 0; - dev->iamthif_msg_buf_index += mei_hdr.length; - ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); - if (ret) - return ret; - - if (mei_hdr.msg_complete) { - if (mei_cl_flow_ctrl_reduce(cl)) - return -EIO; - cb->status = mei_amthif_read_start(cl, cb->file_object); - list_add_tail(&cb->list, &dev->write_waiting_list.list); - } else { - dev_dbg(dev->dev, "message does not complete, so add amthif cb to write list.\n"); - list_add_tail(&cb->list, &dev->write_list.list); - } - } else { - - list_add_tail(&cb->list, &dev->write_list.list); - } + if (cb->completed) + cb->status = mei_amthif_read_start(cl, cb->file_object); return 0; } /** - * mei_amthif_write - write amthif data to amthif client + * mei_amthif_run_next_cmd - send next amt command from queue * * @dev: the device structure - * @cb: mei call back struct * * Return: 0 on success, <0 on failure. - * */ -int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) -{ - if (!dev || !cb) - return -ENODEV; - - cb->fop_type = MEI_FOP_WRITE; - if (!list_empty(&dev->amthif_cmd_list.list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(dev->dev, - "amthif state = %d\n", dev->iamthif_state); - dev_dbg(dev->dev, "AMTHIF: add cb to the wait list\n"); - list_add_tail(&cb->list, &dev->amthif_cmd_list.list); - return 0; - } - return mei_amthif_send_cmd(dev, cb); -} -/** - * mei_amthif_run_next_cmd - send next amt command from queue - * - * @dev: the device structure - */ -void mei_amthif_run_next_cmd(struct mei_device *dev) +int mei_amthif_run_next_cmd(struct mei_device *dev) { + struct mei_cl *cl = &dev->iamthif_cl; struct mei_cl_cb *cb; - int ret; - - if (!dev) - return; dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_index = 0; @@ -415,13 +352,37 @@ void mei_amthif_run_next_cmd(struct mei_device *dev) cb = list_first_entry_or_null(&dev->amthif_cmd_list.list, typeof(*cb), list); if (!cb) - return; + return 0; + list_del_init(&cb->list); - ret = mei_amthif_send_cmd(dev, cb); - if (ret) - dev_warn(dev->dev, "amthif write failed status = %d\n", ret); + return mei_amthif_send_cmd(cl, cb); } +/** + * mei_amthif_write - write amthif data to amthif client + * + * @cl: host client + * @cb: mei call back struct + * + * Return: 0 on success, <0 on failure. + */ +int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) +{ + + struct mei_device *dev; + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + if (WARN_ON(!cb)) + return -EINVAL; + + dev = cl->dev; + + cb->fop_type = MEI_FOP_WRITE; + list_add_tail(&cb->list, &dev->amthif_cmd_list.list); + return mei_amthif_run_next_cmd(dev); +} unsigned int mei_amthif_poll(struct mei_device *dev, struct file *file, poll_table *wait) @@ -461,65 +422,14 @@ unsigned int mei_amthif_poll(struct mei_device *dev, int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) { - struct mei_device *dev = cl->dev; - struct mei_msg_hdr mei_hdr; - size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; - u32 msg_slots = mei_data2slots(len); - int slots; - int rets; - - rets = mei_cl_flow_ctrl_creds(cl); - if (rets < 0) - return rets; - - if (rets == 0) { - cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); - return 0; - } - - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - mei_hdr.internal = 0; - - slots = mei_hbuf_empty_slots(dev); - - if (slots >= msg_slots) { - mei_hdr.length = len; - mei_hdr.msg_complete = 1; - /* Split the message only if we can write the whole host buffer */ - } else if (slots == dev->hbuf_depth) { - msg_slots = slots; - len = (slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr.length = len; - mei_hdr.msg_complete = 0; - } else { - /* wait for next time the host buffer is empty */ - return 0; - } - - dev_dbg(dev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); - - rets = mei_write_message(dev, &mei_hdr, - dev->iamthif_msg_buf + dev->iamthif_msg_buf_index); - if (rets) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - cl->status = rets; - list_del(&cb->list); - return rets; - } - - if (mei_cl_flow_ctrl_reduce(cl)) - return -EIO; + int ret; - dev->iamthif_msg_buf_index += mei_hdr.length; - cl->status = 0; + ret = mei_cl_irq_write(cl, cb, cmpl_list); + if (ret) + return ret; - if (mei_hdr.msg_complete) { + if (cb->completed) cb->status = mei_amthif_read_start(cl, cb->file_object); - list_move_tail(&cb->list, &dev->write_waiting_list.list); - } - return 0; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 3e9cf0db5540..d9f4e28ac972 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1106,6 +1106,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cl->status = 0; cl->writing_state = MEI_WRITING; cb->buf_idx += mei_hdr.length; + cb->completed = mei_hdr.msg_complete == 1; if (mei_hdr.msg_complete) { if (mei_cl_flow_ctrl_reduce(cl)) @@ -1194,6 +1195,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) cl->writing_state = MEI_WRITING; cb->buf_idx = mei_hdr.length; + cb->completed = mei_hdr.msg_complete == 1; out: if (mei_hdr.msg_complete) { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index cbdbf4af2bf7..9d1a8cba81c9 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -401,7 +401,7 @@ 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, diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index fc460af131d4..2f2242f1bed1 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -201,6 +201,7 @@ struct mei_cl; * @file_object: pointer to file structure * @status: io status of the cb * @internal: communication between driver and FW flag + * @completed: the transfer or reception has completed */ struct mei_cl_cb { struct list_head list; @@ -213,6 +214,7 @@ struct mei_cl_cb { struct file *file_object; int status; u32 internal:1; + u32 completed:1; }; /** @@ -662,8 +664,6 @@ void mei_amthif_reset_params(struct mei_device *dev); int mei_amthif_host_init(struct mei_device *dev); -int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); - int mei_amthif_read(struct mei_device *dev, struct file *file, char __user *ubuf, size_t length, loff_t *offset); @@ -675,8 +675,8 @@ int mei_amthif_release(struct mei_device *dev, struct file *file); struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file); -void mei_amthif_run_next_cmd(struct mei_device *dev); - +int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb); +int mei_amthif_run_next_cmd(struct mei_device *dev); int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); -- cgit v1.2.3-55-g7522 From 331e4187017e5dc12fddfcca3f8041e5610ea23b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:41 +0200 Subject: mei: iamthif: use regular client read functions Reduce code duplication in amthif by reusing regular client read functions. The change also removes the need for amthif own buffering Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 71 +++++--------------------------------------- drivers/misc/mei/client.h | 2 ++ drivers/misc/mei/interrupt.c | 37 +++++++++++++++-------- drivers/misc/mei/mei_dev.h | 6 ---- 4 files changed, 35 insertions(+), 81 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 916625a8f037..4060e2f40286 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -49,8 +49,6 @@ void mei_amthif_reset_params(struct mei_device *dev) { /* reset iamthif parameters. */ dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; @@ -69,7 +67,6 @@ int mei_amthif_host_init(struct mei_device *dev) { struct mei_cl *cl = &dev->iamthif_cl; struct mei_me_client *me_cl; - unsigned char *msg_buf; int ret; dev->iamthif_state = MEI_IAMTHIF_IDLE; @@ -90,18 +87,6 @@ int mei_amthif_host_init(struct mei_device *dev) dev->iamthif_mtu = me_cl->props.max_msg_length; dev_dbg(dev->dev, "IAMTHIF_MTU = %d\n", dev->iamthif_mtu); - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - 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) { @@ -282,9 +267,6 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) cb->fop_type = MEI_FOP_READ; list_add_tail(&cb->list, &dev->ctrl_wr_list.list); - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_state = MEI_IAMTHIF_READING; dev->iamthif_file_object = cb->file_object; dev->iamthif_current_cb = cb; @@ -340,8 +322,6 @@ int mei_amthif_run_next_cmd(struct mei_device *dev) struct mei_cl *cl = &dev->iamthif_cl; struct mei_cl_cb *cb; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; @@ -440,67 +420,34 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, * * @cl: mei client * @mei_hdr: header of amthif message - * @complete_list: completed callbacks list + * @cmpl_list: completed callbacks list * - * Return: Always 0; error message is in cb->status + * Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status */ int mei_amthif_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr, - struct mei_cl_cb *complete_list) + struct mei_cl_cb *cmpl_list) { struct mei_device *dev; - struct mei_cl_cb *cb; - unsigned char *buffer; + int ret; dev = cl->dev; - if (cl->state != MEI_FILE_CONNECTED) - goto err; - if (dev->iamthif_state != MEI_IAMTHIF_READING) - goto err; - - list_for_each_entry(cb, &dev->read_list.list, list) { - if (cl == cb->cl) - break; - } - - if (&cb->list == &dev->read_list.list) { - dev_err(dev->dev, "no reader found\n"); - goto err; - } - - if (dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length) { - cb->status = -ERANGE; - goto err; - } - - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - mei_read_slots(dev, buffer, mei_hdr->length); + return 0; - dev->iamthif_msg_buf_index += mei_hdr->length; + ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list); + if (ret) + return ret; if (!mei_hdr->msg_complete) return 0; dev_dbg(dev->dev, "completed amthif read.\n "); - dev->iamthif_current_cb = NULL; - dev->iamthif_stall_timer = 0; - cb->buf_idx = dev->iamthif_msg_buf_index; - cb->read_time = jiffies; - - dev_dbg(dev->dev, "complete the amthif read cb.\n "); - list_move_tail(&cb->list, &complete_list->list); return 0; - -err: - mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); - dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", - MEI_HDR_PRM(mei_hdr)); - return 0; } /** @@ -530,8 +477,6 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) if (dev->iamthif_canceled != 1) { dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; dev->iamthif_stall_timer = 0; - memcpy(cb->response_buffer.data, - dev->iamthif_msg_buf, dev->iamthif_msg_buf_index); list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); dev_dbg(dev->dev, "amthif read completed\n"); dev->iamthif_timer = jiffies; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 80386f9c27e9..21cf626e8908 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -102,6 +102,8 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl); int mei_cl_disconnect(struct mei_cl *cl); int mei_cl_connect(struct mei_cl *cl, struct file *file); int mei_cl_read_start(struct mei_cl *cl, size_t length); +int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr, + struct mei_cl_cb *cmpl_list); int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking); int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 89f2fbce160f..466c1d22fb16 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -81,6 +81,24 @@ static bool mei_cl_is_reading(struct mei_cl *cl) cl->reading_state != MEI_READ_COMPLETE; } +/** + * mei_irq_discard_msg - discard received message + * + * @dev: mei device + * @hdr: message header + */ +static inline +void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr) +{ + /* + * no need to check for size as it is guarantied + * that length fits into rd_msg_buf + */ + mei_read_slots(dev, dev->rd_msg_buf, hdr->length); + dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", + MEI_HDR_PRM(hdr)); +} + /** * mei_cl_irq_read_msg - process client message * @@ -90,9 +108,9 @@ static bool mei_cl_is_reading(struct mei_cl *cl) * * Return: always 0 */ -static int mei_cl_irq_read_msg(struct mei_cl *cl, - struct mei_msg_hdr *mei_hdr, - struct mei_cl_cb *complete_list) +int mei_cl_irq_read_msg(struct mei_cl *cl, + struct mei_msg_hdr *mei_hdr, + struct mei_cl_cb *complete_list) { struct mei_device *dev = cl->dev; struct mei_cl_cb *cb; @@ -144,20 +162,17 @@ static int mei_cl_irq_read_msg(struct mei_cl *cl, mei_read_slots(dev, buffer, mei_hdr->length); cb->buf_idx += mei_hdr->length; + if (mei_hdr->msg_complete) { + cb->read_time = jiffies; cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx); list_move_tail(&cb->list, &complete_list->list); } out: - if (!buffer) { - /* assume that mei_hdr->length <= MEI_RD_MSG_BUF_SIZE */ - BUG_ON(mei_hdr->length > MEI_RD_MSG_BUF_SIZE); - mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length); - dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n", - MEI_HDR_PRM(mei_hdr)); - } + if (!buffer) + mei_irq_discard_msg(dev, mei_hdr); return 0; } @@ -569,8 +584,6 @@ void mei_timer(struct work_struct *work) if (--dev->iamthif_stall_timer == 0) { dev_err(dev->dev, "timer: amthif hanged.\n"); mei_reset(dev); - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; dev->iamthif_canceled = false; dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 2f2242f1bed1..57a47d6b63ee 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -485,9 +485,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @iamthif_mtu : amthif client max message length * @iamthif_timer : time stamp of current amthif command completion * @iamthif_stall_timer : timer to detect amthif hang - * @iamthif_msg_buf : amthif current message buffer - * @iamthif_msg_buf_size : size of current amthif message request buffer - * @iamthif_msg_buf_index : current index in amthif message request buffer * @iamthif_state : amthif processor state * @iamthif_canceled : current amthif command is canceled * @@ -583,9 +580,6 @@ struct mei_device { int iamthif_mtu; unsigned long iamthif_timer; u32 iamthif_stall_timer; - unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */ - u32 iamthif_msg_buf_size; - u32 iamthif_msg_buf_index; enum iamthif_states iamthif_state; bool iamthif_canceled; -- cgit v1.2.3-55-g7522 From 5db7514d9333c920791538c850cfb9dbd19025f7 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:42 +0200 Subject: mei: use only one buffer in callback The callback structure is used exclusively for reading or writing therefore there is no reason to hold both response and request buffers in the callback structure Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 8 ++++---- drivers/misc/mei/bus.c | 6 +++--- drivers/misc/mei/client.c | 47 ++++++++++---------------------------------- drivers/misc/mei/client.h | 3 +-- drivers/misc/mei/interrupt.c | 16 +++++++-------- drivers/misc/mei/main.c | 8 ++++---- drivers/misc/mei/mei_dev.h | 6 ++---- 7 files changed, 31 insertions(+), 63 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 4060e2f40286..2cc41cb3bb38 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -213,15 +213,15 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, * remove message from deletion list */ - dev_dbg(dev->dev, "amthif cb->response_buffer size - %d\n", - cb->response_buffer.size); + dev_dbg(dev->dev, "amthif cb->buf size - %d\n", + cb->buf.size); dev_dbg(dev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); /* length is being truncated to PAGE_SIZE, however, * the buf_idx may point beyond */ 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; } else { @@ -260,7 +260,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) goto err; } - rets = mei_io_cb_alloc_resp_buf(cb, length); + rets = mei_io_cb_alloc_buf(cb, length); if (rets) goto err; diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 025626f4467d..36b949a0fddb 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -261,11 +261,11 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, goto out; } - rets = mei_io_cb_alloc_req_buf(cb, length); + rets = mei_io_cb_alloc_buf(cb, length); if (rets < 0) goto out; - memcpy(cb->request_buffer.data, buf, length); + memcpy(cb->buf.data, buf, length); rets = mei_cl_write(cl, cb, blocking); @@ -328,7 +328,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) } r_length = min_t(size_t, length, cb->buf_idx); - memcpy(buf, cb->response_buffer.data, r_length); + memcpy(buf, cb->buf.data, r_length); rets = r_length; free: diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index d9f4e28ac972..5ecb6cc79d70 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -376,8 +376,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb) if (cb == NULL) return; - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); + kfree(cb->buf.data); kfree(cb); } @@ -406,7 +405,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) } /** - * mei_io_cb_alloc_req_buf - allocate request buffer + * mei_io_cb_alloc_buf - allocate callback buffer * * @cb: io callback structure * @length: size of the buffer @@ -415,7 +414,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) * -EINVAL if cb is NULL * -ENOMEM if allocation failed */ -int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length) { if (!cb) return -EINVAL; @@ -423,38 +422,12 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) if (length == 0) return 0; - cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->request_buffer.data) + cb->buf.data = kmalloc(length, GFP_KERNEL); + if (!cb->buf.data) return -ENOMEM; - cb->request_buffer.size = length; + cb->buf.size = length; return 0; } -/** - * mei_io_cb_alloc_resp_buf - allocate response buffer - * - * @cb: io callback structure - * @length: size of the buffer - * - * Return: 0 on success - * -EINVAL if cb is NULL - * -ENOMEM if allocation failed - */ -int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) -{ - if (!cb) - return -EINVAL; - - if (length == 0) - return 0; - - cb->response_buffer.data = kmalloc(length, GFP_KERNEL); - if (!cb->response_buffer.data) - return -ENOMEM; - cb->response_buffer.size = length; - return 0; -} - - /** * mei_cl_flush_queues - flushes queue lists belonging to cl. @@ -1005,7 +978,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) goto out; } - rets = mei_io_cb_alloc_resp_buf(cb, length); + rets = mei_io_cb_alloc_buf(cb, length); if (rets) goto out; @@ -1059,7 +1032,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, dev = cl->dev; - buf = &cb->request_buffer; + buf = &cb->buf; rets = mei_cl_flow_ctrl_creds(cl); if (rets < 0) @@ -1094,7 +1067,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, } cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", - cb->request_buffer.size, cb->buf_idx); + cb->buf.size, cb->buf_idx); rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); if (rets) { @@ -1144,7 +1117,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) dev = cl->dev; - buf = &cb->request_buffer; + buf = &cb->buf; cl_dbg(dev, cl, "size=%d\n", buf->size); diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 21cf626e8908..d430a6e09ae8 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -49,8 +49,7 @@ void mei_me_cl_rm_all(struct mei_device *dev); */ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); void mei_io_cb_free(struct mei_cl_cb *priv_cb); -int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); -int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); +int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length); /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 466c1d22fb16..60469a0053bb 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -134,19 +134,17 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, cl->reading_state = MEI_READING; - if (cb->response_buffer.size == 0 || - cb->response_buffer.data == NULL) { + if (cb->buf.size == 0 || cb->buf.data == NULL) { cl_err(dev, cl, "response buffer is not allocated.\n"); list_move_tail(&cb->list, &complete_list->list); cb->status = -ENOMEM; goto out; } - if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) { + if (cb->buf.size < mei_hdr->length + cb->buf_idx) { cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n", - cb->response_buffer.size, mei_hdr->length, cb->buf_idx); - buffer = krealloc(cb->response_buffer.data, - mei_hdr->length + cb->buf_idx, + cb->buf.size, mei_hdr->length, cb->buf_idx); + buffer = krealloc(cb->buf.data, mei_hdr->length + cb->buf_idx, GFP_KERNEL); if (!buffer) { @@ -154,11 +152,11 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, list_move_tail(&cb->list, &complete_list->list); goto out; } - cb->response_buffer.data = buffer; - cb->response_buffer.size = mei_hdr->length + cb->buf_idx; + cb->buf.data = buffer; + cb->buf.size = mei_hdr->length + cb->buf_idx; } - buffer = cb->response_buffer.data + cb->buf_idx; + buffer = cb->buf.data + cb->buf_idx; mei_read_slots(dev, buffer, mei_hdr->length); cb->buf_idx += mei_hdr->length; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 9d1a8cba81c9..1d44d110ed94 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -264,7 +264,7 @@ copy_buffer: } dev_dbg(dev->dev, "buf.size = %d buf.idx= %ld\n", - cb->response_buffer.size, cb->buf_idx); + cb->buf.size, cb->buf_idx); if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { rets = -EMSGSIZE; goto free; @@ -274,7 +274,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; @@ -389,11 +389,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, rets = -ENOMEM; goto out; } - rets = mei_io_cb_alloc_req_buf(write_cb, length); + rets = mei_io_cb_alloc_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; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 57a47d6b63ee..1a0f6e9588b6 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -194,8 +194,7 @@ struct mei_cl; * @list: link in callback queue * @cl: file client who is running this operation * @fop_type: file operation type - * @request_buffer: buffer to store request data - * @response_buffer: buffer to store response data + * @buf: buffer for data associated with the callback * @buf_idx: last read index * @read_time: last read operation time stamp (iamthif) * @file_object: pointer to file structure @@ -207,8 +206,7 @@ struct mei_cl_cb { struct list_head list; struct mei_cl *cl; enum mei_cb_file_ops fop_type; - struct mei_msg_data request_buffer; - struct mei_msg_data response_buffer; + struct mei_msg_data buf; unsigned long buf_idx; unsigned long read_time; struct file *file_object; -- cgit v1.2.3-55-g7522 From bca67d681c4864b74fa5fae9ee47e562d1e272b1 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:43 +0200 Subject: mei: always initialize the callback with the intended operation type We set the operation type at initialization time as each cb is used only for a single type of operation As a byproduct we add a convenient wrapper for allocating cb with the data buffer. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 4 +-- drivers/misc/mei/bus.c | 14 ++++------- drivers/misc/mei/client.c | 64 ++++++++++++++++++++++++++++++----------------- drivers/misc/mei/client.h | 7 ++++-- drivers/misc/mei/hbm.c | 3 +-- drivers/misc/mei/main.c | 8 ++---- 6 files changed, 55 insertions(+), 45 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 2cc41cb3bb38..3fdd22395b9f 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -254,7 +254,7 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) size_t length = dev->iamthif_mtu; int rets; - cb = mei_io_cb_init(cl, file); + cb = mei_io_cb_init(cl, MEI_FOP_READ, file); if (!cb) { rets = -ENOMEM; goto err; @@ -264,7 +264,6 @@ static int mei_amthif_read_start(struct mei_cl *cl, struct file *file) if (rets) goto err; - cb->fop_type = MEI_FOP_READ; list_add_tail(&cb->list, &dev->ctrl_wr_list.list); dev->iamthif_state = MEI_IAMTHIF_READING; @@ -359,7 +358,6 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) dev = cl->dev; - cb->fop_type = MEI_FOP_WRITE; list_add_tail(&cb->list, &dev->amthif_cmd_list.list); return mei_amthif_run_next_cmd(dev); } diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 36b949a0fddb..3e6ffed9402a 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -255,16 +255,12 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, goto out; } - cb = mei_io_cb_init(cl, NULL); + cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL); if (!cb) { rets = -ENOMEM; goto out; } - rets = mei_io_cb_alloc_buf(cb, length); - if (rets < 0) - goto out; - memcpy(cb->buf.data, buf, length); rets = mei_cl_write(cl, cb, blocking); @@ -293,7 +289,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) mutex_lock(&dev->device_lock); if (!cl->read_cb) { - rets = mei_cl_read_start(cl, length); + rets = mei_cl_read_start(cl, length, NULL); if (rets < 0) goto out; } @@ -392,7 +388,7 @@ static void mei_bus_event_work(struct work_struct *work) device->events = 0; /* Prepare for the next read */ - mei_cl_read_start(device->cl, 0); + mei_cl_read_start(device->cl, 0, NULL); } int mei_cl_register_event_cb(struct mei_cl_device *device, @@ -406,7 +402,7 @@ int mei_cl_register_event_cb(struct mei_cl_device *device, device->event_context = context; INIT_WORK(&device->event_work, mei_bus_event_work); - mei_cl_read_start(device->cl, 0); + mei_cl_read_start(device->cl, 0, NULL); return 0; } @@ -448,7 +444,7 @@ int mei_cl_enable_device(struct mei_cl_device *device) mutex_unlock(&dev->device_lock); if (device->event_cb && !cl->read_cb) - mei_cl_read_start(device->cl, 0); + mei_cl_read_start(device->cl, 0, NULL); if (!device->ops || !device->ops->enable) return 0; diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 5ecb6cc79d70..57461016f1ff 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -384,11 +384,13 @@ void mei_io_cb_free(struct mei_cl_cb *cb) * mei_io_cb_init - allocate and initialize io callback * * @cl: mei client + * @type: operation type * @fp: pointer to file structure * * Return: mei_cl_cb pointer or NULL; */ -struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, + struct file *fp) { struct mei_cl_cb *cb; @@ -401,6 +403,7 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) cb->file_object = fp; cb->cl = cl; cb->buf_idx = 0; + cb->fop_type = type; return cb; } @@ -429,6 +432,33 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length) return 0; } +/** + * mei_cl_alloc_cb - a convenient wrapper for allocating read cb + * + * @cl: host client + * @length: size of the buffer + * @type: operation type + * @fp: associated file pointer (might be NULL) + * + * Return: cb on success and NULL on failure + */ +struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, + enum mei_cb_file_ops type, struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = mei_io_cb_init(cl, type, fp); + if (!cb) + return NULL; + + if (mei_io_cb_alloc_buf(cb, length)) { + mei_io_cb_free(cb); + return NULL; + } + + return cb; +} + /** * mei_cl_flush_queues - flushes queue lists belonging to cl. * @@ -688,13 +718,10 @@ int mei_cl_disconnect(struct mei_cl *cl) return rets; } - cb = mei_io_cb_init(cl, NULL); - if (!cb) { - rets = -ENOMEM; + cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL); + rets = cb ? 0 : -ENOMEM; + if (rets) goto free; - } - - cb->fop_type = MEI_FOP_DISCONNECT; if (mei_hbuf_acquire(dev)) { if (mei_hbm_cl_disconnect_req(dev, cl)) { @@ -795,13 +822,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) return rets; } - cb = mei_io_cb_init(cl, file); - if (!cb) { - rets = -ENOMEM; + cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file); + rets = cb ? 0 : -ENOMEM; + if (rets) goto out; - } - - cb->fop_type = MEI_FOP_CONNECT; /* run hbuf acquire last so we don't have to undo */ if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { @@ -934,10 +958,11 @@ out: * * @cl: host client * @length: number of bytes to read + * @fp: pointer to file structure * * Return: 0 on success, <0 on failure. */ -int mei_cl_read_start(struct mei_cl *cl, size_t length) +int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp) { struct mei_device *dev; struct mei_cl_cb *cb; @@ -972,17 +997,11 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) return rets; } - cb = mei_io_cb_init(cl, NULL); - if (!cb) { - rets = -ENOMEM; - goto out; - } - - rets = mei_io_cb_alloc_buf(cb, length); + cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp); + rets = cb ? 0 : -ENOMEM; if (rets) goto out; - cb->fop_type = MEI_FOP_READ; if (mei_hbuf_acquire(dev)) { rets = mei_hbm_cl_flow_control_req(dev, cl); if (rets < 0) @@ -1128,7 +1147,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) return rets; } - cb->fop_type = MEI_FOP_WRITE; cb->buf_idx = 0; cl->writing_state = MEI_IDLE; diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index d430a6e09ae8..f7d0285b5f57 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -47,7 +47,8 @@ void mei_me_cl_rm_all(struct mei_device *dev); /* * MEI IO Functions */ -struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, + struct file *fp); void mei_io_cb_free(struct mei_cl_cb *priv_cb); int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length); @@ -77,6 +78,8 @@ int mei_cl_unlink(struct mei_cl *cl); int mei_cl_flush_queues(struct mei_cl *cl); struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl); +struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, + enum mei_cb_file_ops type, struct file *fp); int mei_cl_flow_ctrl_creds(struct mei_cl *cl); @@ -100,7 +103,7 @@ static inline bool mei_cl_is_transitioning(struct mei_cl *cl) bool mei_cl_is_other_connecting(struct mei_cl *cl); int mei_cl_disconnect(struct mei_cl *cl); int mei_cl_connect(struct mei_cl *cl, struct file *file); -int mei_cl_read_start(struct mei_cl *cl, size_t length); +int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp); int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr, struct mei_cl_cb *cmpl_list); int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 4f83e9aaa6f9..2c581dcaf3b1 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -684,10 +684,9 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev, cl->state = MEI_FILE_DISCONNECTED; cl->timer_count = 0; - cb = mei_io_cb_init(cl, NULL); + cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL); if (!cb) return -ENOMEM; - cb->fop_type = MEI_FOP_DISCONNECT_RSP; cl_dbg(dev, cl, "add disconnect response as first\n"); list_add(&cb->list, &dev->ctrl_wr_list.list); } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 1d44d110ed94..369de0a070f1 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -209,7 +209,7 @@ 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); @@ -383,15 +383,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, } else if (cl->reading_state == MEI_IDLE) *offset = 0; - - write_cb = mei_io_cb_init(cl, file); + write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!write_cb) { rets = -ENOMEM; goto out; } - rets = mei_io_cb_alloc_buf(write_cb, length); - if (rets) - goto out; rets = copy_from_user(write_cb->buf.data, ubuf, length); if (rets) { -- cgit v1.2.3-55-g7522 From 03b8d3419fdfc02d1984a0db51c8b74426e12605 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:44 +0200 Subject: mei: add mei_cl_alloc_linked function Add convenient wrapper mei_cl_alloc_linked to simplify error handling Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 35 +++++++++++++++++++++++++++++++++-- drivers/misc/mei/client.h | 2 ++ drivers/misc/mei/main.c | 17 +++++------------ drivers/misc/mei/nfc.c | 43 +++++++++++++++++++++---------------------- 4 files changed, 61 insertions(+), 36 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 57461016f1ff..e263c0713a6d 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -547,11 +547,11 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) * mei_cl_link - allocate host id in the host map * * @cl: host client - * @id: fixed host id or -1 for generic one + * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one * * Return: 0 on success * -EINVAL on incorrect values - * -ENONET if client not found + * -EMFILE if open count exceeded. */ int mei_cl_link(struct mei_cl *cl, int id) { @@ -869,6 +869,37 @@ out: return rets; } +/** + * mei_cl_alloc_linked - allocate and link host client + * + * @dev: the device structure + * @id: fixed host id or MEI_HOST_CLIENT_ID_ANY (-1) for generic one + * + * Return: cl on success ERR_PTR on failure + */ +struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev, int id) +{ + struct mei_cl *cl; + int ret; + + cl = mei_cl_allocate(dev); + if (!cl) { + ret = -ENOMEM; + goto err; + } + + ret = mei_cl_link(cl, id); + if (ret) + goto err; + + return cl; +err: + kfree(cl); + return ERR_PTR(ret); +} + + + /** * mei_cl_flow_ctrl_creds - checks flow_control credits for cl. * diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index f7d0285b5f57..c3d0e200a642 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -75,6 +75,8 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev); int mei_cl_link(struct mei_cl *cl, int id); int mei_cl_unlink(struct mei_cl *cl); +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_find_read_cb(struct mei_cl *cl); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 369de0a070f1..10fc3a6a1574 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -59,24 +59,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 +80,6 @@ static int mei_open(struct inode *inode, struct file *file) err_unlock: mutex_unlock(&dev->device_lock); - kfree(cl); return err; } diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index bb61a119b8bb..c3bcb63686d7 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -482,8 +482,8 @@ err: int mei_nfc_host_init(struct mei_device *dev) { struct mei_nfc_dev *ndev; - struct mei_cl *cl_info, *cl = NULL; - struct mei_me_client *me_cl; + struct mei_cl *cl_info, *cl; + struct mei_me_client *me_cl = NULL; int ret; @@ -500,17 +500,6 @@ int mei_nfc_host_init(struct mei_device *dev) goto err; } - ndev->cl_info = mei_cl_allocate(dev); - ndev->cl = mei_cl_allocate(dev); - - cl = ndev->cl; - cl_info = ndev->cl_info; - - if (!cl || !cl_info) { - ret = -ENOMEM; - goto err; - } - /* check for valid client id */ me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid); if (!me_cl) { @@ -519,17 +508,21 @@ int mei_nfc_host_init(struct mei_device *dev) goto err; } + cl_info = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY); + if (IS_ERR(cl_info)) { + ret = PTR_ERR(cl_info); + goto err; + } + 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) - goto err; - + me_cl = NULL; list_add_tail(&cl_info->device_link, &dev->device_list); + ndev->cl_info = cl_info; + /* check for valid client id */ me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid); if (!me_cl) { @@ -538,16 +531,21 @@ int mei_nfc_host_init(struct mei_device *dev) goto err; } + cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY); + if (IS_ERR(cl)) { + ret = PTR_ERR(cl); + goto err; + } + 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) - goto err; + me_cl = NULL; list_add_tail(&cl->device_link, &dev->device_list); + ndev->cl = cl; + ndev->req_id = 1; INIT_WORK(&ndev->init_work, mei_nfc_init); @@ -557,6 +555,7 @@ int mei_nfc_host_init(struct mei_device *dev) return 0; err: + mei_me_cl_put(me_cl); mei_nfc_free(ndev); return ret; -- cgit v1.2.3-55-g7522 From 928fa6664b362aad70c16f04483414f60743e15e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:45 +0200 Subject: mei: simplify io callback disposal Simplify disposal of io callback by removing the callback implicitly from its lookup list inside mei_io_cb_free Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 24 +++++------- drivers/misc/mei/bus.c | 22 ++--------- drivers/misc/mei/client.c | 88 ++++++++++++++++++++++---------------------- drivers/misc/mei/hbm.c | 2 +- drivers/misc/mei/interrupt.c | 3 +- drivers/misc/mei/main.c | 29 +++------------ 6 files changed, 63 insertions(+), 105 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 3fdd22395b9f..7b6ed0bbfc9c 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -196,16 +196,16 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, if (time_after(jiffies, timeout)) { dev_dbg(dev->dev, "amthif Time out\n"); /* 15 sec for the message has expired */ - list_del(&cb->list); + list_del_init(&cb->list); rets = -ETIME; goto free; } /* if the whole message will fit remove it from the list */ if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) - list_del(&cb->list); + list_del_init(&cb->list); else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { /* end of the message has been reached */ - list_del(&cb->list); + list_del_init(&cb->list); rets = 0; goto free; } @@ -504,26 +504,22 @@ void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) static bool mei_clear_list(struct mei_device *dev, const struct file *file, struct list_head *mei_cb_list) { - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; + struct mei_cl *cl = &dev->iamthif_cl; + struct mei_cl_cb *cb, *next; bool removed = false; /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { + list_for_each_entry_safe(cb, next, mei_cb_list, list) { /* check if list member associated with a file */ - if (file == cb_pos->file_object) { - /* remove member from the list */ - list_del(&cb_pos->list); + if (file == cb->file_object) { /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { + if (dev->iamthif_current_cb == cb) { dev->iamthif_current_cb = NULL; /* send flow control to iamthif client */ - mei_hbm_cl_flow_control_req(dev, - &dev->iamthif_cl); + mei_hbm_cl_flow_control_req(dev, cl); } /* free all allocated buffers */ - mei_io_cb_free(cb_pos); - cb_pos = NULL; + mei_io_cb_free(cb); removed = true; } } diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 3e6ffed9402a..b5385372693d 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -311,13 +311,13 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) mutex_lock(&dev->device_lock); } - cb = cl->read_cb; if (cl->reading_state != MEI_READ_COMPLETE) { rets = 0; goto out; } + cb = cl->read_cb; if (cb->status) { rets = cb->status; goto free; @@ -329,8 +329,8 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) free: mei_io_cb_free(cb); - cl->reading_state = MEI_IDLE; cl->read_cb = NULL; + cl->reading_state = MEI_IDLE; out: mutex_unlock(&dev->device_lock); @@ -486,23 +486,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) /* Flush queues and remove any pending read */ mei_cl_flush_queues(cl); - - if (cl->read_cb) { - struct mei_cl_cb *cb = NULL; - - 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; - - if (cb) { - mei_io_cb_free(cb); - cb = NULL; - } - } + mei_io_cb_free(cl->read_cb); device->event_cb = NULL; diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e263c0713a6d..624bf0182a50 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -320,6 +320,47 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, (cl1->me_client_id == cl2->me_client_id); } +/** + * mei_io_cb_free - free mei_cb_private related memory + * + * @cb: mei callback struct + */ +void mei_io_cb_free(struct mei_cl_cb *cb) +{ + if (cb == NULL) + return; + + list_del(&cb->list); + kfree(cb->buf.data); + kfree(cb); +} + +/** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl: mei client + * @type: operation type + * @fp: pointer to file structure + * + * Return: mei_cl_cb pointer or NULL; + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, + struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + INIT_LIST_HEAD(&cb->list); + cb->file_object = fp; + cb->cl = cl; + cb->buf_idx = 0; + cb->fop_type = type; + return cb; +} + /** * __mei_io_list_flush - removes and frees cbs belonging to cl. * @@ -330,13 +371,12 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, static void __mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl, bool free) { - struct mei_cl_cb *cb; - struct mei_cl_cb *next; + struct mei_cl_cb *cb, *next; /* enable removing everything if no cl is specified */ list_for_each_entry_safe(cb, next, &list->list, list) { if (!cl || mei_cl_cmp_id(cl, cb->cl)) { - list_del(&cb->list); + list_del_init(&cb->list); if (free) mei_io_cb_free(cb); } @@ -354,7 +394,6 @@ void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) __mei_io_list_flush(list, cl, false); } - /** * mei_io_list_free - removes cb belonging to cl and free them * @@ -366,47 +405,6 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) __mei_io_list_flush(list, cl, true); } -/** - * mei_io_cb_free - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_io_cb_free(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->buf.data); - kfree(cb); -} - -/** - * mei_io_cb_init - allocate and initialize io callback - * - * @cl: mei client - * @type: operation type - * @fp: pointer to file structure - * - * Return: mei_cl_cb pointer or NULL; - */ -struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type, - struct file *fp) -{ - struct mei_cl_cb *cb; - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return NULL; - - mei_io_list_init(cb); - - cb->file_object = fp; - cb->cl = cl; - cb->buf_idx = 0; - cb->fop_type = type; - return cb; -} - /** * mei_io_cb_alloc_buf - allocate callback buffer * diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 2c581dcaf3b1..58da92565c5e 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -639,7 +639,7 @@ static void mei_hbm_cl_res(struct mei_device *dev, continue; if (mei_hbm_cl_addr_equal(cl, rs)) { - list_del(&cb->list); + list_del_init(&cb->list); break; } } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 60469a0053bb..1e2f3c774853 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -202,7 +202,6 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, cl->state = MEI_FILE_DISCONNECTED; cl->status = 0; - list_del(&cb->list); mei_io_cb_free(cb); return ret; @@ -320,7 +319,7 @@ static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, if (ret) { cl->status = ret; cb->buf_idx = 0; - list_del(&cb->list); + list_del_init(&cb->list); return ret; } diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 10fc3a6a1574..c34853be963f 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -94,7 +94,6 @@ 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; @@ -118,23 +117,11 @@ static int mei_release(struct inode *inode, struct file *file) 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; - } + mei_io_cb_free(cl->read_cb); + cl->read_cb = NULL; file->private_data = NULL; - mei_io_cb_free(cb); - kfree(cl); out: mutex_unlock(&dev->device_lock); @@ -156,7 +143,6 @@ 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; int rets; @@ -279,13 +265,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; + + cl->reading_state = MEI_IDLE; out: dev_dbg(dev->dev, "end mei read rets= %d\n", rets); mutex_unlock(&dev->device_lock); @@ -355,7 +338,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, if (time_after(jiffies, timeout) || cl->reading_state == MEI_READ_COMPLETE) { *offset = 0; - list_del(&write_cb->list); mei_io_cb_free(write_cb); write_cb = NULL; } @@ -367,11 +349,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *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; + cl->reading_state = MEI_IDLE; } } else if (cl->reading_state == MEI_IDLE) *offset = 0; -- cgit v1.2.3-55-g7522 From a9bed61053af13c0768f82c9d1c8793515dd067c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:46 +0200 Subject: 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 Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 36 ++++++++++--------- drivers/misc/mei/client.c | 84 ++++++++++++++++++++++++++++---------------- drivers/misc/mei/client.h | 7 ++-- drivers/misc/mei/debugfs.c | 2 +- drivers/misc/mei/init.c | 1 - drivers/misc/mei/interrupt.c | 35 +++++------------- drivers/misc/mei/main.c | 42 +++++----------------- drivers/misc/mei/mei_dev.h | 10 +++--- 8 files changed, 98 insertions(+), 119 deletions(-) (limited to 'drivers/misc/mei') 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) mutex_lock(&dev->device_lock); - if (!cl->read_cb) { - rets = mei_cl_read_start(cl, length, NULL); - if (rets < 0) - goto out; - } + cb = mei_cl_read_cb(cl, NULL); + if (cb) + goto copy; + + rets = mei_cl_read_start(cl, length, NULL); + if (rets && rets != -EBUSY) + goto out; - if (cl->reading_state != MEI_READ_COMPLETE && - !waitqueue_active(&cl->rx_wait)) { + if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { mutex_unlock(&dev->device_lock); if (wait_event_interruptible(cl->rx_wait, - cl->reading_state == MEI_READ_COMPLETE || + (!list_empty(&cl->rd_completed)) || mei_cl_is_transitioning(cl))) { 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); - } + if (mei_cl_is_transitioning(cl)) { + rets = -EBUSY; + goto out; + } + } - if (cl->reading_state != MEI_READ_COMPLETE) { + cb = mei_cl_read_cb(cl, NULL); + if (!cb) { rets = 0; goto out; } - cb = cl->read_cb; +copy: if (cb->status) { rets = cb->status; goto free; @@ -329,9 +335,6 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) free: mei_io_cb_free(cb); - cl->read_cb = NULL; - cl->reading_state = MEI_IDLE; - out: mutex_unlock(&dev->device_lock); @@ -443,7 +446,7 @@ int mei_cl_enable_device(struct mei_cl_device *device) mutex_unlock(&dev->device_lock); - if (device->event_cb && !cl->read_cb) + if (device->event_cb) mei_cl_read_start(device->cl, 0, NULL); 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 */ - mei_cl_flush_queues(cl); - mei_io_cb_free(cl->read_cb); + mei_cl_flush_queues(cl, NULL); device->event_cb = NULL; 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 @@ -457,14 +457,56 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, 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. * * @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. */ -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; @@ -474,13 +516,15 @@ int mei_cl_flush_queues(struct mei_cl *cl) dev = cl->dev; 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_waiting_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->amthif_cmd_list, cl); mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); + + mei_cl_read_cb_flush(cl, fp); + 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->rx_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->device_link); - cl->reading_state = MEI_IDLE; cl->writing_state = MEI_IDLE; cl->dev = dev; } @@ -523,24 +568,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) 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 * @@ -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)) return -ENODEV; - if (cl->read_cb) { - cl_dbg(dev, cl, "read is pending.\n"); + /* HW currently supports only one pending read */ + if (!list_empty(&cl->rd_pending)) return -EBUSY; - } + 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); @@ -1036,13 +1063,11 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, struct file *fp) if (rets < 0) goto out; - list_add_tail(&cb->list, &dev->read_list.list); + list_add_tail(&cb->list, &cl->rd_pending); } else { list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } - cl->read_cb = cb; - out: cl_dbg(dev, cl, "rpm: autosuspend\n"); 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)) wake_up_interruptible(&cl->tx_wait); - } else if (cb->fop_type == MEI_FOP_READ && - MEI_READING == cl->reading_state) { - cl->reading_state = MEI_READ_COMPLETE; + } else if (cb->fop_type == MEI_FOP_READ) { + list_add_tail(&cb->list, &cl->rd_completed); if (waitqueue_active(&cl->rx_wait)) wake_up_interruptible(&cl->rx_wait); 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); 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_find_read_cb(struct mei_cl *cl); - +struct mei_cl_cb *mei_cl_read_cb(const 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, 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); 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, pos += scnprintf(buf + pos, bufsz - pos, "%2d|%2d|%4d|%5d|%2d|%2d|\n", 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++; } 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, dev->dev_state = MEI_DEV_INITIALIZING; dev->reset_count = 0; - mei_io_list_init(&dev->read_list); mei_io_list_init(&dev->write_list); mei_io_list_init(&dev->write_waiting_list); 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, return cl->host_client_id == mei_hdr->host_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 @@ -116,24 +104,18 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_cl_cb *cb; unsigned char *buffer = NULL; - list_for_each_entry(cb, &dev->read_list.list, list) { - if (cl == cb->cl) - break; - } - - if (&cb->list == &dev->read_list.list) { - dev_err(dev->dev, "no reader found\n"); + cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list); + if (!cb) { + cl_err(dev, cl, "pending read cb not found\n"); goto out; } - if (!mei_cl_is_reading(cl)) { - cl_err(dev, cl, "cl is not reading state=%d reading state=%d\n", - cl->state, cl->reading_state); + if (cl->state != MEI_FILE_CONNECTED) { + cl_dbg(dev, cl, "not connected\n"); + cb->status = -ENODEV; goto out; } - cl->reading_state = MEI_READING; - if (cb->buf.size == 0 || cb->buf.data == NULL) { cl_err(dev, cl, "response buffer is not allocated.\n"); 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) { cb->read_time = jiffies; - cl_dbg(dev, cl, "completed read length = %lu\n", - cb->buf_idx); + cl_dbg(dev, cl, "completed read length = %lu\n", cb->buf_idx); 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; } - list_move_tail(&cb->list, &dev->read_list.list); + list_move_tail(&cb->list, &cl->rd_pending); return 0; } 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) cl_dbg(dev, cl, "disconnecting\n"); rets = mei_cl_disconnect(cl); } - mei_cl_flush_queues(cl); + mei_cl_flush_queues(cl, file); cl_dbg(dev, cl, "removing\n"); mei_cl_unlink(cl); - mei_io_cb_free(cl->read_cb); - cl->read_cb = NULL; - file->private_data = NULL; kfree(cl); @@ -143,8 +140,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 = NULL; struct mei_device *dev; + struct mei_cl_cb *cb = NULL; int rets; int err; @@ -171,7 +168,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, goto out; } - cb = cl->read_cb; + cb = mei_cl_read_cb(cl, file); if (cb) { /* read what left */ if (cb->buf_idx > *offset) @@ -196,9 +193,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, 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; @@ -207,7 +202,7 @@ 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 || + (!list_empty(&cl->rd_completed)) || mei_cl_is_transitioning(cl))) { 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) { - rets = -ENODEV; - goto out; - } - - if (cl->reading_state != MEI_READ_COMPLETE) { rets = 0; goto out; } @@ -266,9 +255,7 @@ copy_buffer: free: mei_io_cb_free(cb); - cl->read_cb = NULL; - cl->reading_state = MEI_IDLE; out: dev_dbg(dev->dev, "end mei read rets= %d\n", rets); 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 + 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; mei_io_cb_free(write_cb); 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; - 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; - + *offset = 0; write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!write_cb) { 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 { * @me_client_id: me/fw id * @mei_flow_ctrl_creds: transmit flow credentials * @timer_count: watchdog timer for operation completion - * @reading_state: state of the rx * @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_link: link to bus clients @@ -251,9 +251,9 @@ struct mei_cl { u8 me_client_id; u8 mei_flow_ctrl_creds; u8 timer_count; - enum mei_file_transaction_states reading_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 */ struct mei_cl_device *device; @@ -425,7 +425,6 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @cdev : character device * @minor : minor number allocated for device * - * @read_list : read completion list * @write_list : write pending list * @write_waiting_list : write completion list * @ctrl_wr_list : pending control write list @@ -501,7 +500,6 @@ struct mei_device { struct cdev cdev; int minor; - struct mei_cl_cb read_list; struct mei_cl_cb write_list; struct mei_cl_cb write_waiting_list; struct mei_cl_cb ctrl_wr_list; -- cgit v1.2.3-55-g7522 From b3de8e3719e582f3182bb504295e4a8e43c8c96f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 10 Feb 2015 10:39:47 +0200 Subject: mei: bus: call device disable handler prior to disconnection call device's disable handler prior to disconnection so it can possibly close the communication with fw client in graceful way Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 17ca7e20fb6a..45896f95fed1 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -467,37 +467,34 @@ int mei_cl_disable_device(struct mei_cl_device *device) dev = cl->dev; + if (device->ops && device->ops->disable) + device->ops->disable(device); + + device->event_cb = NULL; + mutex_lock(&dev->device_lock); if (cl->state != MEI_FILE_CONNECTED) { - mutex_unlock(&dev->device_lock); dev_err(dev->dev, "Already disconnected"); - - return 0; + err = 0; + goto out; } cl->state = MEI_FILE_DISCONNECTING; err = mei_cl_disconnect(cl); if (err < 0) { - mutex_unlock(&dev->device_lock); - dev_err(dev->dev, - "Could not disconnect from the ME client"); - - return err; + dev_err(dev->dev, "Could not disconnect from the ME client"); + goto out; } /* Flush queues and remove any pending read */ mei_cl_flush_queues(cl, NULL); - device->event_cb = NULL; - +out: mutex_unlock(&dev->device_lock); + return err; - if (!device->ops || !device->ops->disable) - return 0; - - return device->ops->disable(device); } EXPORT_SYMBOL_GPL(mei_cl_disable_device); -- cgit v1.2.3-55-g7522 From b43baf694fde30dc2db2386c347324d1a013f3d1 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 4 Mar 2015 18:41:34 +0200 Subject: mei: free me client references on host init Fx fixes leak introduced by: commit b7d885145538 ("mei: revamp me clients list handling") Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 98a5363e1e8a..b6fec4d15307 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -668,14 +668,17 @@ void mei_host_client_init(struct work_struct *work) me_cl = mei_me_cl_by_uuid(dev, &mei_amthif_guid); if (me_cl) mei_amthif_host_init(dev); + mei_me_cl_put(me_cl); me_cl = mei_me_cl_by_uuid(dev, &mei_wd_guid); if (me_cl) mei_wd_host_init(dev); + mei_me_cl_put(me_cl); me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid); if (me_cl) mei_nfc_host_init(dev); + mei_me_cl_put(me_cl); dev->dev_state = MEI_DEV_ENABLED; -- cgit v1.2.3-55-g7522 From d2b5851d8583e690eeb5ac8dfff5da92e1f1468f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 4 Mar 2015 18:41:35 +0200 Subject: mei: trace: fix missing include to linux/device.h Fix warning (discovered using randconfig) drivers/misc/mei/mei-trace.h:30:24: warning: 'struct device' declared inside parameter list TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/mei-trace.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h index d5c38d15cdd9..5f4e1a17360b 100644 --- a/drivers/misc/mei/mei-trace.h +++ b/drivers/misc/mei/mei-trace.h @@ -21,6 +21,8 @@ #include #include +#include + #undef TRACE_SYSTEM #define TRACE_SYSTEM mei -- cgit v1.2.3-55-g7522 From ab3ae0096a6d31e1b244c5c5155f48ef3700329e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 19 Mar 2015 12:10:09 +0200 Subject: mei: fix regression on NFC connection In mei_host_client_init function we enable the all internal connected clients including NFC. This is done before we set the device to enabled state and let userspace call open. We need to check only for MEI_FILE_CONNECTED in mei_cl_is_connected in order to enable the communication with the clients before MEI_DEV_ENABLED is set. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index eb02f34b2fe0..7800d1bd8ba1 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -92,9 +92,7 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl); */ static inline bool mei_cl_is_connected(struct mei_cl *cl) { - return cl->dev && - cl->dev->dev_state == MEI_DEV_ENABLED && - cl->state == MEI_FILE_CONNECTED; + return cl->state == MEI_FILE_CONNECTED; } static inline bool mei_cl_is_transitioning(struct mei_cl *cl) { -- cgit v1.2.3-55-g7522 From 1d9013f09203c694e2cba478b05afc6484d55180 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 27 Mar 2015 00:27:57 +0200 Subject: mei: fix mei_poll operation mei_poll returned with POLLIN w/o checking whether the operation has really completed. remove redundant check and locking in amthif specific handler Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/amthif.c | 25 +++++++++++++++---------- drivers/misc/mei/client.c | 2 +- drivers/misc/mei/main.c | 24 +++++++++++------------- 3 files changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 7b6ed0bbfc9c..3c1fd87ee10b 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c @@ -362,6 +362,18 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) return mei_amthif_run_next_cmd(dev); } +/** + * mei_amthif_poll - the amthif poll function + * + * @dev: the device structure + * @file: pointer to file structure + * @wait: pointer to poll_table structure + * + * Return: poll mask + * + * Locking: called under "dev->device_lock" lock + */ + unsigned int mei_amthif_poll(struct mei_device *dev, struct file *file, poll_table *wait) { @@ -369,19 +381,12 @@ unsigned int mei_amthif_poll(struct mei_device *dev, poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (!mei_cl_is_connected(&dev->iamthif_cl)) { - - mask = POLLERR; - - } else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && + dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(dev->dev, "run next amthif cb\n"); + mask |= POLLIN | POLLRDNORM; mei_amthif_run_next_cmd(dev); } - mutex_unlock(&dev->device_lock); return mask; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index b6fec4d15307..e5aeb6fd1ba4 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1299,7 +1299,7 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) } else if (cb->fop_type == MEI_FOP_READ) { list_add_tail(&cb->list, &cl->rd_completed); if (waitqueue_active(&cl->rx_wait)) - wake_up_interruptible(&cl->rx_wait); + wake_up_interruptible_all(&cl->rx_wait); else mei_cl_bus_rx_event(cl); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index d80867e0d803..a1ec45054988 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -542,6 +542,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; @@ -558,22 +559,19 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) 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); -- cgit v1.2.3-55-g7522 From f3de9b635d93a3d268adda428e1df94091506a42 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 27 Mar 2015 00:27:58 +0200 Subject: mei: use mei_cl_is_connected consistently Replace open coded check for cl->state !=/== MEI_FILE_CONNECTED with mei_cl_is_connected function. Note that cl->state != MEI_FILE_CONNECTED is not the same as cl->state == MEI_FILE_DISCONNECTED Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 4 ++-- drivers/misc/mei/client.c | 2 +- drivers/misc/mei/interrupt.c | 2 +- drivers/misc/mei/main.c | 13 +++++++------ drivers/misc/mei/wd.c | 18 +++++++++++------- 5 files changed, 22 insertions(+), 17 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 45896f95fed1..b724a67696fc 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -238,7 +238,7 @@ static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, dev = cl->dev; mutex_lock(&dev->device_lock); - if (cl->state != MEI_FILE_CONNECTED) { + if (!mei_cl_is_connected(cl)) { rets = -ENODEV; goto out; } @@ -474,7 +474,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) mutex_lock(&dev->device_lock); - if (cl->state != MEI_FILE_CONNECTED) { + if (!mei_cl_is_connected(cl)) { dev_err(dev->dev, "Already disconnected"); err = 0; goto out; diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e5aeb6fd1ba4..1e99ef6a54a2 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -876,7 +876,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mutex_lock(&dev->device_lock); - if (cl->state != MEI_FILE_CONNECTED) { + if (!mei_cl_is_connected(cl)) { cl->state = MEI_FILE_DISCONNECTED; /* something went really wrong */ if (!cl->status) diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3f23629759db..3f84d2edcde4 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -110,7 +110,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, goto out; } - if (cl->state != MEI_FILE_CONNECTED) { + if (!mei_cl_is_connected(cl)) { cl_dbg(dev, cl, "not connected\n"); cb->status = -ENODEV; goto out; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index a1ec45054988..29fa88b6fa17 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -107,7 +107,7 @@ static int mei_release(struct inode *inode, struct file *file) rets = mei_amthif_release(dev, file); goto out; } - if (cl->state == MEI_FILE_CONNECTED) { + if (mei_cl_is_connected(cl)) { cl->state = MEI_FILE_DISCONNECTING; cl_dbg(dev, cl, "disconnecting\n"); rets = mei_cl_disconnect(cl); @@ -309,9 +309,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, 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); + if (!mei_cl_is_connected(cl)) { + cl_err(dev, cl, "is not connected"); rets = -ENODEV; goto out; } @@ -418,7 +417,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; } @@ -554,7 +553,9 @@ 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; } diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index ac1e6235692d..2725f865c3d6 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -160,9 +160,10 @@ int mei_wd_send(struct mei_device *dev) */ int mei_wd_stop(struct mei_device *dev) { + struct mei_cl *cl = &dev->wd_cl; int ret; - if (dev->wd_cl.state != MEI_FILE_CONNECTED || + if (!mei_cl_is_connected(cl) || dev->wd_state != MEI_WD_RUNNING) return 0; @@ -170,7 +171,7 @@ int mei_wd_stop(struct mei_device *dev) dev->wd_state = MEI_WD_STOPPING; - ret = mei_cl_flow_ctrl_creds(&dev->wd_cl); + ret = mei_cl_flow_ctrl_creds(cl); if (ret < 0) goto err; @@ -211,13 +212,16 @@ err: */ static int mei_wd_ops_start(struct watchdog_device *wd_dev) { - int err = -ENODEV; struct mei_device *dev; + struct mei_cl *cl; + int err = -ENODEV; dev = watchdog_get_drvdata(wd_dev); if (!dev) return -ENODEV; + cl = &dev->wd_cl; + mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { @@ -226,8 +230,8 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev) goto end_unlock; } - if (dev->wd_cl.state != MEI_FILE_CONNECTED) { - dev_dbg(dev->dev, "MEI Driver is not connected to Watchdog Client\n"); + if (!mei_cl_is_connected(cl)) { + cl_dbg(dev, cl, "MEI Driver is not connected to Watchdog Client\n"); goto end_unlock; } @@ -282,8 +286,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev) mutex_lock(&dev->device_lock); - if (cl->state != MEI_FILE_CONNECTED) { - dev_err(dev->dev, "wd: not connected.\n"); + if (!mei_cl_is_connected(cl)) { + cl_err(dev, cl, "wd: not connected.\n"); ret = -ENODEV; goto end; } -- cgit v1.2.3-55-g7522 From 6a84d63d22a0ac79ab422b69ef2b4d75002c5641 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 27 Mar 2015 00:27:59 +0200 Subject: mei: replace check for connection instead of transitioning The function mei_cl_is_transitioning is just opposite of mei_cl_is_connected. What we actually wanted to check is if we lost connection so we can discard the check for transition and check for 'not connected' Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 4 ++-- drivers/misc/mei/client.h | 14 ++++++++------ drivers/misc/mei/main.c | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index b724a67696fc..4cf38c39878a 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -302,7 +302,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) if (wait_event_interruptible(cl->rx_wait, (!list_empty(&cl->rd_completed)) || - mei_cl_is_transitioning(cl))) { + (!mei_cl_is_connected(cl)))) { if (signal_pending(current)) return -EINTR; @@ -311,7 +311,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) mutex_lock(&dev->device_lock); - if (mei_cl_is_transitioning(cl)) { + if (!mei_cl_is_connected(cl)) { rets = -EBUSY; goto out; } diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 7800d1bd8ba1..0a39e5d45171 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -90,16 +90,18 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl); /* * MEI input output function prototype */ + +/** + * mei_cl_is_connected - host client is connected + * + * @cl: host clinet + * + * Return: true if the host clinet is connected + */ static inline bool mei_cl_is_connected(struct mei_cl *cl) { return cl->state == MEI_FILE_CONNECTED; } -static inline bool mei_cl_is_transitioning(struct mei_cl *cl) -{ - return MEI_FILE_INITIALIZING == cl->state || - MEI_FILE_DISCONNECTED == cl->state || - MEI_FILE_DISCONNECTING == cl->state; -} bool mei_cl_is_other_connecting(struct mei_cl *cl); int mei_cl_disconnect(struct mei_cl *cl); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 29fa88b6fa17..7f77f39c24a7 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -203,7 +203,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, if (wait_event_interruptible(cl->rx_wait, (!list_empty(&cl->rd_completed)) || - mei_cl_is_transitioning(cl))) { + (!mei_cl_is_connected(cl)))) { if (signal_pending(current)) return -EINTR; @@ -211,7 +211,7 @@ 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; } -- cgit v1.2.3-55-g7522 From ea5505fabd3b59608750bfd3721d0f8bc5c8b0bb Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Mon, 13 Apr 2015 13:56:20 +0300 Subject: mei: trace: remove unused TRACE_SYSTEM_STRING fix warning: include/trace/ftrace.h:28:0: note: this is the location of the previous definition ^ In file included from include/trace/define_trace.h:90:0, from drivers/misc/mei/mei-trace.h:76, from drivers/misc/mei/mei-trace.c:21: include/trace/ftrace.h:28:0: warning: "TRACE_SYSTEM_STRING" redefined Cc: Stephen Rothwell Reported-by: Stephen Rothwell Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/mei-trace.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/misc/mei') diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h index 5f4e1a17360b..47e1bc6551d4 100644 --- a/drivers/misc/mei/mei-trace.h +++ b/drivers/misc/mei/mei-trace.h @@ -24,9 +24,7 @@ #include #undef TRACE_SYSTEM - #define TRACE_SYSTEM mei -#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) TRACE_EVENT(mei_reg_read, TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), -- cgit v1.2.3-55-g7522