* [char-misc-next 02/18] mei: revamp me clients list handling
@ 2015-02-10 8:39 Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 03/18] mei: me: use io register wrappers consistently Tomas Winkler
` (15 more replies)
0 siblings, 16 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 9541218c10eb..e7d28c9961fd 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,51 +83,146 @@ 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
*
* @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 6ad049a08e4d..ad18b0d16f61 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -389,6 +389,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);
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 03/18] mei: me: use io register wrappers consistently
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 04/18] mei: me: add io register tracing Tomas Winkler
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
drivers/misc/mei/hw-me.c | 123 +++++++++++++++++++++++++----------------------
1 file changed, 66 insertions(+), 57 deletions(-)
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;
}
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 04/18] mei: me: add io register tracing
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 03/18] mei: me: use io register wrappers consistently Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 05/18] mei: me: change power gating function name conventions Tomas Winkler
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
To make debugging a bit easier we add me register
access tracing
<debugfs>/tracing/events/mei/mei_reg_{read,write}
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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
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 <linux/module.h>
+
+/* 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 <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#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 <trace/define_trace.h>
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 05/18] mei: me: change power gating function name conventions
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 03/18] mei: me: use io register wrappers consistently Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 04/18] mei: me: add io register tracing Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 06/18] mei: fix function names and format in KDoc Tomas Winkler
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler
From: Alexander Usyskin <alexander.usyskin@intel.com>
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 <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
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);
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 06/18] mei: fix function names and format in KDoc
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (2 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 05/18] mei: me: change power gating function name conventions Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 07/18] mei: fix device reset on mei_cl_irq_read_msg allocation failure Tomas Winkler
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler
From: Alexander Usyskin <alexander.usyskin@intel.com>
Align functions names in KDoc with real ones.
Fix comment format to be KDoc and fix wrong syntax there.
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e7d28c9961fd..e9135246c00e 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
*/
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 07/18] mei: fix device reset on mei_cl_irq_read_msg allocation failure
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (3 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 06/18] mei: fix function names and format in KDoc Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 08/18] mei: iamthif: fix device reset on mei_amthif_irq_read_msg Tomas Winkler
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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;
};
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 08/18] mei: iamthif: fix device reset on mei_amthif_irq_read_msg
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (4 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 07/18] mei: fix device reset on mei_cl_irq_read_msg allocation failure Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 09/18] mei: iamthif: remove useless iamthif_ioctl variable Tomas Winkler
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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);
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 09/18] mei: iamthif: remove useless iamthif_ioctl variable
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (5 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 08/18] mei: iamthif: fix device reset on mei_amthif_irq_read_msg Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 10/18] mei: iamthif: send flow control as a regular client Tomas Winkler
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
iamthif_ioctl is obsolete and can be safely dropped
Currently it is set to true during driver runtime
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 10/18] mei: iamthif: send flow control as a regular client
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (6 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 09/18] mei: iamthif: remove useless iamthif_ioctl variable Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 11/18] mei: iamthif: use client write functions Tomas Winkler
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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
@@ -255,6 +255,47 @@ out:
}
/**
+ * 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
*
* @dev: the device structure
@@ -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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 11/18] mei: iamthif: use client write functions
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (7 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 10/18] mei: iamthif: send flow control as a regular client Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 12/18] mei: iamthif: use regular client read functions Tomas Winkler
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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 e9135246c00e..978f7f95d66d 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);
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 12/18] mei: iamthif: use regular client read functions
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (8 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 11/18] mei: iamthif: use client write functions Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 13/18] mei: use only one buffer in callback Tomas Winkler
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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
@@ -82,6 +82,24 @@ static bool mei_cl_is_reading(struct mei_cl *cl)
}
/**
+ * 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
*
* @cl: reading client
@@ -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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 13/18] mei: use only one buffer in callback
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (9 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 12/18] mei: iamthif: use regular client read functions Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 14/18] mei: always initialize the callback with the intended operation type Tomas Winkler
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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 978f7f95d66d..9eee3d4b2bc0 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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 14/18] mei: always initialize the callback with the intended operation type
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (10 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 13/18] mei: use only one buffer in callback Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 15/18] mei: add mei_cl_alloc_linked function Tomas Winkler
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
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(-)
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 9eee3d4b2bc0..86450c2fc810 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;
}
@@ -430,6 +433,33 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
}
/**
+ * 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.
*
* @cl: host client
@@ -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) {
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 15/18] mei: add mei_cl_alloc_linked function
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (11 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 14/18] mei: always initialize the callback with the intended operation type Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 16/18] mei: simplify io callback disposal Tomas Winkler
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
Add convenient wrapper mei_cl_alloc_linked
to simplify error handling
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 86450c2fc810..830a3facbb2b 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)
{
@@ -870,6 +870,37 @@ out:
}
/**
+ * 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.
*
* @cl: private data of the file object
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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 16/18] mei: simplify io callback disposal
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (12 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 15/18] mei: add mei_cl_alloc_linked function Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 17/18] mei: allow read concurrency Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 18/18] mei: bus: call device disable handler prior to disconnection Tomas Winkler
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
Simplify disposal of io callback by removing the callback
implicitly from its lookup list inside mei_io_cb_free
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
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 830a3facbb2b..f28eed12e7ab 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -321,6 +321,47 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
}
/**
+ * 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.
*
* @list: an instance of our list structure
@@ -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
*
@@ -367,47 +406,6 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
}
/**
- * 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
*
* @cb: io callback structure
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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 17/18] mei: allow read concurrency
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (13 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 16/18] mei: simplify io callback disposal Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 18/18] mei: bus: call device disable handler prior to disconnection Tomas Winkler
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
Replace clunky read state machine with read stack
implemented as per client read list, this is important
mostly for mei drivers with unsolicited reads
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
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(-)
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 f28eed12e7ab..e220bef0173c 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -458,13 +458,55 @@ struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
}
/**
+ * 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;
}
@@ -524,24 +569,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
}
/**
- * 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
*
* @cl: host client
@@ -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);
@@ -1267,9 +1292,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 ad18b0d16f61..97353cf8d9b6 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -397,7 +397,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;
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
* [char-misc-next 18/18] mei: bus: call device disable handler prior to disconnection
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
` (14 preceding siblings ...)
2015-02-10 8:39 ` [char-misc-next 17/18] mei: allow read concurrency Tomas Winkler
@ 2015-02-10 8:39 ` Tomas Winkler
15 siblings, 0 replies; 17+ messages in thread
From: Tomas Winkler @ 2015-02-10 8:39 UTC (permalink / raw)
To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler
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 <tomas.winkler@intel.com>
---
drivers/misc/mei/bus.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
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);
--
1.9.3
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2015-02-10 8:45 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-10 8:39 [char-misc-next 02/18] mei: revamp me clients list handling Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 03/18] mei: me: use io register wrappers consistently Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 04/18] mei: me: add io register tracing Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 05/18] mei: me: change power gating function name conventions Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 06/18] mei: fix function names and format in KDoc Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 07/18] mei: fix device reset on mei_cl_irq_read_msg allocation failure Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 08/18] mei: iamthif: fix device reset on mei_amthif_irq_read_msg Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 09/18] mei: iamthif: remove useless iamthif_ioctl variable Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 10/18] mei: iamthif: send flow control as a regular client Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 11/18] mei: iamthif: use client write functions Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 12/18] mei: iamthif: use regular client read functions Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 13/18] mei: use only one buffer in callback Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 14/18] mei: always initialize the callback with the intended operation type Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 15/18] mei: add mei_cl_alloc_linked function Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 16/18] mei: simplify io callback disposal Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 17/18] mei: allow read concurrency Tomas Winkler
2015-02-10 8:39 ` [char-misc-next 18/18] mei: bus: call device disable handler prior to disconnection Tomas Winkler
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®