All of lore.kernel.org
 help / color / mirror / Atom feed
* [char-misc-next 00/11] mei fixes and cleanups
@ 2014-02-17 13:13 Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper Tomas Winkler
                   ` (10 more replies)
  0 siblings, 11 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler


Alexander Usyskin (4):
  mei: hbm: revamp client connect and disconnection status
  mei: fix potential read outside of array bounds
  mei: use helper function to find me client by id
  mei: make return values consistent across the driver

Tomas Winkler (7):
  mei: add mei_hbuf_acquire wrapper
  mei: revamp writing slot counting
  mei: Remove all bus devices from the mei_dev list when stopping the
    MEI
  mei: wd and amthif use mei_cl_ api for dis/connection
  mei: don't of list_for_each_entry_safe when not deleting
  mei: wd: simplify wd_send command
  mei: wd: fix stop completion failure

 drivers/misc/mei/amthif.c    |  63 +++++-------
 drivers/misc/mei/bus.c       |  20 +++-
 drivers/misc/mei/client.c    | 222 +++++++++++++++++++++++--------------------
 drivers/misc/mei/client.h    |   4 +-
 drivers/misc/mei/hbm.c       | 209 ++++++++++++++++++++--------------------
 drivers/misc/mei/hw-me.c     |  12 ++-
 drivers/misc/mei/hw-txe.c    |  38 ++++----
 drivers/misc/mei/hw-txe.h    |   1 +
 drivers/misc/mei/hw.h        |  16 ++--
 drivers/misc/mei/init.c      |   2 +
 drivers/misc/mei/interrupt.c | 113 ++++++++++------------
 drivers/misc/mei/main.c      |   4 +-
 drivers/misc/mei/mei_dev.h   |   9 +-
 drivers/misc/mei/nfc.c       |  14 +--
 drivers/misc/mei/wd.c        | 135 ++++++++++++++------------
 15 files changed, 441 insertions(+), 421 deletions(-)

-- 
1.8.5.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-18 18:03   ` Greg KH
  2014-02-17 13:13 ` [char-misc-next 02/11 RESEND] mei: revamp writing slot counting Tomas Winkler
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

A client has to acquire host buffer
before writing, we add lock like wrapper
to replace the code snippet

if (dev->hbuf_is_ready)
        dev->hbuf_is_ready = false;

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    |  7 +-----
 drivers/misc/mei/client.c    | 56 ++++++++++++++++++++++++++++----------------
 drivers/misc/mei/hw-me.c     |  2 ++
 drivers/misc/mei/hw-txe.c    | 17 +++++---------
 drivers/misc/mei/interrupt.c |  6 ++---
 drivers/misc/mei/mei_dev.h   |  2 ++
 drivers/misc/mei/wd.c        | 14 +++++------
 7 files changed, 57 insertions(+), 47 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index f88cb26..71af677 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -301,9 +301,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
 	if (ret < 0)
 		return ret;
 
-	if (ret && dev->hbuf_is_ready) {
+	if (ret && mei_hbuf_acquire(dev)) {
 		ret = 0;
-		dev->hbuf_is_ready = false;
 		if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
 			mei_hdr.length = mei_hbuf_max_len(dev);
 			mei_hdr.msg_complete = 0;
@@ -335,10 +334,6 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
 			list_add_tail(&cb->list, &dev->write_list.list);
 		}
 	} else {
-		if (!dev->hbuf_is_ready)
-			dev_dbg(&dev->pdev->dev, "host buffer is not empty");
-
-		dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
 		list_add_tail(&cb->list, &dev->write_list.list);
 	}
 	return 0;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 9c840ef..24fa85e 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -375,6 +375,23 @@ void mei_host_client_init(struct work_struct *work)
 	mutex_unlock(&dev->device_lock);
 }
 
+/**
+ * mei_hbuf_acquire: try to acquire host buffer
+ *
+ * @dev: the device structure
+ * returns true if host buffer was acquired
+ */
+bool mei_hbuf_acquire(struct mei_device *dev)
+{
+	if (!dev->hbuf_is_ready) {
+		dev_dbg(&dev->pdev->dev, "hbuf is not ready\n");
+		return false;
+	}
+
+	dev->hbuf_is_ready = false;
+
+	return true;
+}
 
 /**
  * mei_cl_disconnect - disconnect host client from the me one
@@ -406,8 +423,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
 		return -ENOMEM;
 
 	cb->fop_type = MEI_FOP_CLOSE;
-	if (dev->hbuf_is_ready) {
-		dev->hbuf_is_ready = false;
+	if (mei_hbuf_acquire(dev)) {
 		if (mei_hbm_cl_disconnect_req(dev, cl)) {
 			rets = -ENODEV;
 			cl_err(dev, cl, "failed to disconnect.\n");
@@ -507,9 +523,8 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 
 	cb->fop_type = MEI_FOP_CONNECT;
 
-	if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
-		dev->hbuf_is_ready = false;
-
+	/* run hbuf acquire last so we don't have to undo */
+	if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
 		if (mei_hbm_cl_connect_req(dev, cl)) {
 			rets = -ENODEV;
 			goto out;
@@ -666,8 +681,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
 		goto err;
 
 	cb->fop_type = MEI_FOP_READ;
-	if (dev->hbuf_is_ready) {
-		dev->hbuf_is_ready = false;
+	if (mei_hbuf_acquire(dev)) {
 		if (mei_hbm_cl_flow_control_req(dev, cl)) {
 			cl_err(dev, cl, "flow control send failed\n");
 			rets = -ENODEV;
@@ -802,21 +816,29 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 
 
 	cb->fop_type = MEI_FOP_WRITE;
+	cb->buf_idx = 0;
+	cl->writing_state = MEI_IDLE;
+
+	mei_hdr.host_addr = cl->host_client_id;
+	mei_hdr.me_addr = cl->me_client_id;
+	mei_hdr.reserved = 0;
+	mei_hdr.msg_complete = 0;
+	mei_hdr.internal = cb->internal;
 
 	rets = mei_cl_flow_ctrl_creds(cl);
 	if (rets < 0)
 		goto err;
 
-	/* Host buffer is not ready, we queue the request */
-	if (rets == 0 || !dev->hbuf_is_ready) {
-		cb->buf_idx = 0;
-		/* unseting complete will enqueue the cb for write */
-		mei_hdr.msg_complete = 0;
+	if (rets == 0) {
+		cl_dbg(dev, cl, "No flow control credentials: not sending.\n");
+		rets = buf->size;
+		goto out;
+	}
+	if (!mei_hbuf_acquire(dev)) {
+		cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n");
 		rets = buf->size;
 		goto out;
 	}
-
-	dev->hbuf_is_ready = false;
 
 	/* Check for a maximum length */
 	if (buf->size > mei_hbuf_max_len(dev)) {
@@ -827,12 +849,6 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 		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 = cb->internal;
-
-
 	rets = mei_write_message(dev, &mei_hdr, buf->data);
 	if (rets)
 		goto err;
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 847c9e5..b0c42d6 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -513,6 +513,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
 		}
 	}
 
+	dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
+
 	rets = mei_irq_write_handler(dev, &complete_list);
 
 	dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index 19579e5..ab0442e 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -604,7 +604,6 @@ static int mei_txe_write(struct mei_device *dev,
 		mei_txe_input_payload_write(dev, i + 1, reg);
 	}
 
-	dev->hbuf_is_ready = false;
 	/* Set Input-Doorbell */
 	mei_txe_input_doorbell_set(hw);
 
@@ -982,20 +981,16 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
 		dev->hbuf_is_ready = true;
 
 	if (hw->aliveness && dev->hbuf_is_ready) {
-		/* if SeC did not complete reading the written data by host */
-		if (!mei_txe_is_input_ready(dev)) {
-			dev_dbg(&dev->pdev->dev, "got Input Ready Int, but SEC_IPC_INPUT_STATUS_RDY is 0.\n");
-			goto end;
-		}
 
+		/* get the real register value */
+		dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
 		rets = mei_irq_write_handler(dev, &complete_list);
-		if (rets)
-			dev_err(&dev->pdev->dev,
-				"mei_irq_write_handler ret = %d.\n", rets);
+		if (rets && rets != -EMSGSIZE)
+			dev_err(&dev->pdev->dev, "mei_irq_write_handler ret = %d.\n",
+				rets);
+		dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
 	}
 
-
-
 	mei_irq_compl_handler(dev, &complete_list);
 
 end:
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 75ff409..8f8ab08 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -446,10 +446,10 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 	s32 slots;
 	int ret;
 
-	if (!mei_hbuf_is_ready(dev)) {
-		dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
+
+	if (!mei_hbuf_acquire(dev))
 		return 0;
-	}
+
 	slots = mei_hbuf_empty_slots(dev);
 	if (slots <= 0)
 		return -EMSGSIZE;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 21e5249..c77b747 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -629,6 +629,8 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
 	return dev->ops->rdbuf_full_slots(dev);
 }
 
+bool mei_hbuf_acquire(struct mei_device *dev);
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 int mei_dbgfs_register(struct mei_device *dev, const char *name);
 void mei_dbgfs_deregister(struct mei_device *dev);
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index f70945e..a769fb1 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -153,9 +153,8 @@ int mei_wd_stop(struct mei_device *dev)
 	if (ret < 0)
 		goto out;
 
-	if (ret && dev->hbuf_is_ready) {
+	if (ret && mei_hbuf_acquire(dev)) {
 		ret = 0;
-		dev->hbuf_is_ready = false;
 
 		if (!mei_wd_send(dev)) {
 			ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
@@ -260,8 +259,8 @@ static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
  */
 static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 {
-	int ret = 0;
 	struct mei_device *dev;
+	int ret;
 
 	dev = watchdog_get_drvdata(wd_dev);
 	if (!dev)
@@ -277,10 +276,12 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 
 	dev->wd_state = MEI_WD_RUNNING;
 
+	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
+	if (ret < 0)
+		goto end;
 	/* Check if we can send the ping to HW*/
-	if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
+	if (ret && mei_hbuf_acquire(dev)) {
 
-		dev->hbuf_is_ready = false;
 		dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
 
 		if (mei_wd_send(dev)) {
@@ -290,8 +291,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 		}
 
 		if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
-			dev_err(&dev->pdev->dev,
-				"wd: mei_cl_flow_ctrl_reduce() failed.\n");
+			dev_err(&dev->pdev->dev, "wd: mei_cl_flow_ctrl_reduce() failed.\n");
 			ret = -EIO;
 			goto end;
 		}
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 02/11 RESEND] mei: revamp writing slot counting
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 03/11] mei: Remove all bus devices from the mei_dev list when stopping the MEI Tomas Winkler
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

Since txe use doorbell and not circular buffer
we have to cheat in write slot counting, txe always consume all the
slots upon write. In order for it to work we need to track
slots using mei_hbuf_empty_slots() instead of tracking it in mei layer

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    | 19 ++++++-----
 drivers/misc/mei/client.c    | 19 +++++------
 drivers/misc/mei/client.h    |  4 +--
 drivers/misc/mei/hw-me.c     |  2 +-
 drivers/misc/mei/hw-txe.c    | 21 +++++++-----
 drivers/misc/mei/hw-txe.h    |  1 +
 drivers/misc/mei/interrupt.c | 78 +++++++++++++++++---------------------------
 drivers/misc/mei/mei_dev.h   |  4 +--
 8 files changed, 68 insertions(+), 80 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 71af677..b8dfc61 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -441,23 +441,23 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
 
 
 /**
- * mei_amthif_irq_write_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write - write iamthif command in irq thread context.
  *
  * @dev: the device structure.
- * @slots: free slots.
  * @cb_pos: callback block.
  * @cl: private data of the file object.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-				  s32 *slots, struct mei_cl_cb *cmpl_list)
+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);
@@ -474,13 +474,15 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 	mei_hdr.reserved = 0;
 	mei_hdr.internal = 0;
 
-	if (*slots >= msg_slots) {
+	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);
+	} 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 {
@@ -490,7 +492,6 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 
 	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT,  MEI_HDR_PRM(&mei_hdr));
 
-	*slots -=  msg_slots;
 	rets = mei_write_message(dev, &mei_hdr,
 			dev->iamthif_msg_buf + dev->iamthif_msg_buf_index);
 	if (rets) {
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 24fa85e..f505764 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -701,27 +701,26 @@ err:
 }
 
 /**
- * mei_cl_irq_write_complete - write a message to device
+ * mei_cl_irq_write - write a message to device
  *	from the interrupt thread context
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise error.
  */
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-				     s32 *slots, struct mei_cl_cb *cmpl_list)
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+		     struct mei_cl_cb *cmpl_list)
 {
 	struct mei_device *dev;
 	struct mei_msg_data *buf;
 	struct mei_msg_hdr mei_hdr;
 	size_t len;
 	u32 msg_slots;
+	int slots;
 	int rets;
 
-
 	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
 
@@ -738,6 +737,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 		return 0;
 	}
 
+	slots = mei_hbuf_empty_slots(dev);
 	len = buf->size - cb->buf_idx;
 	msg_slots = mei_data2slots(len);
 
@@ -746,13 +746,13 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
 	mei_hdr.reserved = 0;
 	mei_hdr.internal = cb->internal;
 
-	if (*slots >= msg_slots) {
+	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);
+	} 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 {
@@ -763,7 +763,6 @@ int mei_cl_irq_write_complete(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);
 
-	*slots -=  msg_slots;
 	rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
 	if (rets) {
 		cl->status = rets;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index c8396e5..c11b663 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -102,8 +102,8 @@ 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_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
-int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-				s32 *slots, struct mei_cl_cb *cmpl_list);
+int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
+		     struct mei_cl_cb *cmpl_list);
 
 void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
 
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index b0c42d6..84165cc 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -354,7 +354,7 @@ static int mei_me_write_message(struct mei_device *dev,
 
 	dw_cnt = mei_data2slots(length);
 	if (empty_slots < 0 || dw_cnt > empty_slots)
-		return -EIO;
+		return -EMSGSIZE;
 
 	mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
 
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c
index ab0442e..69a5ce7 100644
--- a/drivers/misc/mei/hw-txe.c
+++ b/drivers/misc/mei/hw-txe.c
@@ -565,7 +565,9 @@ static int mei_txe_write(struct mei_device *dev,
 	struct mei_txe_hw *hw = to_txe_hw(dev);
 	unsigned long rem;
 	unsigned long length;
+	int slots = dev->hbuf_depth;
 	u32 *reg_buf = (u32 *)buf;
+	u32 dw_cnt;
 	int i;
 
 	if (WARN_ON(!header || !buf))
@@ -575,11 +577,9 @@ static int mei_txe_write(struct mei_device *dev,
 
 	dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(header));
 
-	if ((length + sizeof(struct mei_msg_hdr)) > PAYLOAD_SIZE) {
-		dev_err(&dev->pdev->dev, "write length exceeded = %ld > %d\n",
-			length + sizeof(struct mei_msg_hdr), PAYLOAD_SIZE);
-		return -ERANGE;
-	}
+	dw_cnt = mei_data2slots(length);
+	if (dw_cnt > slots)
+		return -EMSGSIZE;
 
 	if (WARN(!hw->aliveness, "txe write: aliveness not asserted\n"))
 		return -EAGAIN;
@@ -604,6 +604,9 @@ static int mei_txe_write(struct mei_device *dev,
 		mei_txe_input_payload_write(dev, i + 1, reg);
 	}
 
+	/* after each write the whole buffer is consumed */
+	hw->slots = 0;
+
 	/* Set Input-Doorbell */
 	mei_txe_input_doorbell_set(hw);
 
@@ -631,7 +634,8 @@ static size_t mei_txe_hbuf_max_len(const struct mei_device *dev)
  */
 static int mei_txe_hbuf_empty_slots(struct mei_device *dev)
 {
-	return dev->hbuf_depth;
+	struct mei_txe_hw *hw = to_txe_hw(dev);
+	return hw->slots;
 }
 
 /**
@@ -977,11 +981,12 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id)
 		}
 	}
 	/* Input Ready: Detection if host can write to SeC */
-	if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause))
+	if (test_and_clear_bit(TXE_INTR_IN_READY_BIT, &hw->intr_cause)) {
 		dev->hbuf_is_ready = true;
+		hw->slots = dev->hbuf_depth;
+	}
 
 	if (hw->aliveness && dev->hbuf_is_ready) {
-
 		/* get the real register value */
 		dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
 		rets = mei_irq_write_handler(dev, &complete_list);
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h
index 857d88c..3d8d6e5 100644
--- a/drivers/misc/mei/hw-txe.h
+++ b/drivers/misc/mei/hw-txe.h
@@ -44,6 +44,7 @@ struct mei_txe_hw {
 	void __iomem *mem_addr[NUM_OF_MEM_BARS];
 	u32 aliveness;
 	u32 readiness;
+	u32 slots;
 
 	wait_queue_head_t wait_aliveness;
 	bool recvd_aliveness;
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 8f8ab08..8fbdb59 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -165,25 +165,24 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
-			s32 *slots, struct mei_cl_cb *cmpl_list)
+				     struct mei_cl_cb *cmpl_list)
 {
 	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
 	int ret;
 
-	u32 msg_slots =
-		mei_data2slots(sizeof(struct hbm_client_connect_response));
+	slots = mei_hbuf_empty_slots(dev);
+	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_response));
 
-	if (*slots < msg_slots)
+	if (slots < msg_slots)
 		return -EMSGSIZE;
 
-	*slots -= msg_slots;
-
 	ret = mei_hbm_cl_disconnect_rsp(dev, cl);
 
 	cl->state = MEI_FILE_DISCONNECTED;
@@ -201,24 +200,23 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
-			s32 *slots, struct mei_cl_cb *cmpl_list)
+			    struct mei_cl_cb *cmpl_list)
 {
 	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
 
-	u32 msg_slots =
-		mei_data2slots(sizeof(struct hbm_client_connect_request));
+	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+	slots = mei_hbuf_empty_slots(dev);
 
-	if (*slots < msg_slots)
+	if (slots < msg_slots)
 		return -EMSGSIZE;
 
-	*slots -= msg_slots;
-
 	if (mei_hbm_cl_disconnect_req(dev, cl)) {
 		cl->status = 0;
 		cb->buf_idx = 0;
@@ -242,27 +240,23 @@ static int mei_cl_irq_close(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
-			   s32 *slots, struct mei_cl_cb *cmpl_list)
+			   struct mei_cl_cb *cmpl_list)
 {
 	struct mei_device *dev = cl->dev;
-	u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
-
+	u32 msg_slots;
+	int slots;
 	int ret;
 
+	msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+	slots = mei_hbuf_empty_slots(dev);
 
-	if (*slots < msg_slots) {
-		/* return the cancel routine */
-		list_del(&cb->list);
+	if (slots < msg_slots)
 		return -EMSGSIZE;
-	}
-
-	*slots -= msg_slots;
 
 	ret = mei_hbm_cl_flow_control_req(dev, cl);
 	if (ret) {
@@ -283,30 +277,26 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: client
  * @cb: callback block.
- * @slots: free slots.
  * @cmpl_list: complete list.
  *
  * returns 0, OK; otherwise, error.
  */
 static int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
-			   s32 *slots, struct mei_cl_cb *cmpl_list)
+			      struct mei_cl_cb *cmpl_list)
 {
 	struct mei_device *dev = cl->dev;
+	u32 msg_slots;
+	int slots;
 	int ret;
 
-	u32 msg_slots =
-		mei_data2slots(sizeof(struct hbm_client_connect_request));
+	msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request));
+	slots = mei_hbuf_empty_slots(dev);
 
 	if (mei_cl_is_other_connecting(cl))
 		return 0;
 
-	if (*slots < msg_slots) {
-		/* return the cancel routine */
-		list_del(&cb->list);
+	if (slots < msg_slots)
 		return -EMSGSIZE;
-	}
-
-	*slots -=  msg_slots;
 
 	cl->state = MEI_FILE_CONNECTING;
 
@@ -494,13 +484,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
 			else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
 				return -ENODEV;
-
 			dev->wd_pending = false;
-
-			if (dev->wd_state == MEI_WD_RUNNING)
-				slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
-			else
-				slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
 		}
 	}
 
@@ -515,28 +499,28 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 		switch (cb->fop_type) {
 		case MEI_FOP_CLOSE:
 			/* send disconnect message */
-			ret = mei_cl_irq_close(cl, cb, &slots, cmpl_list);
+			ret = mei_cl_irq_close(cl, cb, cmpl_list);
 			if (ret)
 				return ret;
 
 			break;
 		case MEI_FOP_READ:
 			/* send flow control message */
-			ret = mei_cl_irq_read(cl, cb, &slots, cmpl_list);
+			ret = mei_cl_irq_read(cl, cb, cmpl_list);
 			if (ret)
 				return ret;
 
 			break;
 		case MEI_FOP_CONNECT:
 			/* connect message */
-			ret = mei_cl_irq_connect(cl, cb, &slots, cmpl_list);
+			ret = mei_cl_irq_connect(cl, cb, cmpl_list);
 			if (ret)
 				return ret;
 
 			break;
 		case MEI_FOP_DISCONNECT_RSP:
 			/* send disconnect resp */
-			ret = mei_cl_irq_disconnect_rsp(cl, cb, &slots, cmpl_list);
+			ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list);
 			if (ret)
 				return ret;
 		default:
@@ -551,11 +535,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 		if (cl == NULL)
 			continue;
 		if (cl == &dev->iamthif_cl)
-			ret = mei_amthif_irq_write_complete(cl, cb,
-						&slots, cmpl_list);
+			ret = mei_amthif_irq_write(cl, cb, cmpl_list);
 		else
-			ret = mei_cl_irq_write_complete(cl, cb,
-						&slots, cmpl_list);
+			ret = mei_cl_irq_write(cl, cb, cmpl_list);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index c77b747..49bf2cf 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -514,8 +514,8 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 
 void mei_amthif_run_next_cmd(struct mei_device *dev);
 
-int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
-				  s32 *slots, struct mei_cl_cb *cmpl_list);
+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,
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 03/11] mei: Remove all bus devices from the mei_dev list when stopping the MEI
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 02/11 RESEND] mei: revamp writing slot counting Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 04/11] mei: hbm: revamp client connect and disconnection status Tomas Winkler
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

When stopping the MEI, we should remove and potentially unregister
all bus devices queued on the mei_dev linked list.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/bus.c     | 16 ++++++++++++++++
 drivers/misc/mei/init.c    |  2 ++
 drivers/misc/mei/mei_dev.h |  1 +
 drivers/misc/mei/nfc.c     |  8 +-------
 4 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 4bc7d62..cf4cc0b 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -524,6 +524,22 @@ void mei_cl_bus_rx_event(struct mei_cl *cl)
 	schedule_work(&device->event_work);
 }
 
+void mei_cl_bus_remove_devices(struct mei_device *dev)
+{
+	struct mei_cl *cl, *next;
+
+	mutex_lock(&dev->device_lock);
+	list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+		if (cl->device)
+			mei_cl_remove_device(cl->device);
+
+		list_del(&cl->device_link);
+		mei_cl_unlink(cl);
+		kfree(cl);
+	}
+	mutex_unlock(&dev->device_lock);
+}
+
 int __init mei_cl_bus_init(void)
 {
 	return bus_register(&mei_cl_bus_type);
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 214dcef..4460975 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -288,6 +288,8 @@ void mei_stop(struct mei_device *dev)
 
 	mei_nfc_host_exit(dev);
 
+	mei_cl_bus_remove_devices(dev);
+
 	mutex_lock(&dev->device_lock);
 
 	mei_wd_stop(dev);
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 49bf2cf..c59c56b 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -296,6 +296,7 @@ int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
 int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
 void mei_cl_bus_rx_event(struct mei_cl *cl);
+void mei_cl_bus_remove_devices(struct mei_device *dev);
 int mei_cl_bus_init(void);
 void mei_cl_bus_exit(void);
 
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index a58320c..7626dde 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -552,13 +552,7 @@ err:
 void mei_nfc_host_exit(struct mei_device *dev)
 {
 	struct mei_nfc_dev *ndev = &nfc_dev;
-
 	cancel_work_sync(&ndev->init_work);
+}
 
-	mutex_lock(&dev->device_lock);
-	if (ndev->cl && ndev->cl->device)
-		mei_cl_remove_device(ndev->cl->device);
 
-	mei_nfc_free(ndev);
-	mutex_unlock(&dev->device_lock);
-}
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 04/11] mei: hbm: revamp client connect and disconnection status
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (2 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 03/11] mei: Remove all bus devices from the mei_dev list when stopping the MEI Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 05/11] mei: wd and amthif use mei_cl_ api for dis/connection Tomas Winkler
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

From: Alexander Usyskin <alexander.usyskin@intel.com>

1. Return -ENOTTY on client connect if the requested client was not found
 on the enumeration list or the client was internally disabled, in the later
 case FW will return NOT_FOUND.
2. Return -EBUSY if the client cannot be connected because of resource
 contention
3. Change response status enum to have MEI_CL_ prefix
4. Add function to translate response status to a string
for more readable logging

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c | 13 ++++-----
 drivers/misc/mei/hbm.c    | 67 ++++++++++++++++++++++++++++++-----------------
 drivers/misc/mei/hw.h     | 16 +++++------
 drivers/misc/mei/main.c   |  2 +-
 4 files changed, 59 insertions(+), 39 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index f505764..6639bc3 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -536,18 +536,19 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
 	}
 
 	mutex_unlock(&dev->device_lock);
-	rets = wait_event_timeout(dev->wait_recvd_msg,
-				 (cl->state == MEI_FILE_CONNECTED ||
-				  cl->state == MEI_FILE_DISCONNECTED),
-				 mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
+	wait_event_timeout(dev->wait_recvd_msg,
+			(cl->state == MEI_FILE_CONNECTED ||
+			 cl->state == MEI_FILE_DISCONNECTED),
+			mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT));
 	mutex_lock(&dev->device_lock);
 
 	if (cl->state != MEI_FILE_CONNECTED) {
-		rets = -EFAULT;
+		/* something went really wrong */
+		if (!cl->status)
+			cl->status = -EFAULT;
 
 		mei_io_list_flush(&dev->ctrl_rd_list, cl);
 		mei_io_list_flush(&dev->ctrl_wr_list, cl);
-		goto out;
 	}
 
 	rets = cl->status;
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index d3fcb23..d360e9a 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -23,6 +23,40 @@
 #include "hbm.h"
 #include "hw-me.h"
 
+static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
+{
+#define MEI_CL_CS(status) case MEI_CL_CONN_##status: return #status
+	switch (status) {
+	MEI_CL_CS(SUCCESS);
+	MEI_CL_CS(NOT_FOUND);
+	MEI_CL_CS(ALREADY_STARTED);
+	MEI_CL_CS(OUT_OF_RESOURCES);
+	MEI_CL_CS(MESSAGE_SMALL);
+	default: return "unknown";
+	}
+#undef MEI_CL_CCS
+}
+
+/**
+ * mei_cl_conn_status_to_errno - convert client connect response
+ * status to error code
+ *
+ * @status: client connect response status
+ *
+ * returns corresponding error code
+ */
+static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
+{
+	switch (status) {
+	case MEI_CL_CONN_SUCCESS:          return 0;
+	case MEI_CL_CONN_NOT_FOUND:        return -ENOTTY;
+	case MEI_CL_CONN_ALREADY_STARTED:  return -EBUSY;
+	case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
+	case MEI_CL_CONN_MESSAGE_SMALL:    return -EINVAL;
+	default:                           return -EINVAL;
+	}
+}
+
 /**
  * mei_hbm_me_cl_allocate - allocates storage for me clients
  *
@@ -111,14 +145,11 @@ static bool is_treat_specially_client(struct mei_cl *cl,
 		struct hbm_client_connect_response *rs)
 {
 	if (mei_hbm_cl_addr_equal(cl, rs)) {
-		if (!rs->status) {
+		if (rs->status == MEI_CL_CONN_SUCCESS)
 			cl->state = MEI_FILE_CONNECTED;
-			cl->status = 0;
-
-		} else {
+		else
 			cl->state = MEI_FILE_DISCONNECTED;
-			cl->status = -ENODEV;
-		}
+		cl->status = mei_cl_conn_status_to_errno(rs->status);
 		cl->timer_count = 0;
 
 		return true;
@@ -438,14 +469,8 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
 	struct mei_cl *cl;
 	struct mei_cl_cb *pos = NULL, *next = NULL;
 
-	dev_dbg(&dev->pdev->dev,
-			"disconnect_response:\n"
-			"ME Client = %d\n"
-			"Host Client = %d\n"
-			"Status = %d\n",
-			rs->me_addr,
-			rs->host_addr,
-			rs->status);
+	dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
+			rs->me_addr, rs->host_addr, rs->status);
 
 	list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
 		cl = pos->cl;
@@ -458,7 +483,7 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
 		dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
 		if (mei_hbm_cl_addr_equal(cl, rs)) {
 			list_del(&pos->list);
-			if (!rs->status)
+			if (rs->status == MEI_CL_DISCONN_SUCCESS)
 				cl->state = MEI_FILE_DISCONNECTED;
 
 			cl->status = 0;
@@ -500,14 +525,9 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
 	struct mei_cl *cl;
 	struct mei_cl_cb *pos = NULL, *next = NULL;
 
-	dev_dbg(&dev->pdev->dev,
-			"connect_response:\n"
-			"ME Client = %d\n"
-			"Host Client = %d\n"
-			"Status = %d\n",
-			rs->me_addr,
-			rs->host_addr,
-			rs->status);
+	dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
+			rs->me_addr, rs->host_addr,
+			mei_cl_conn_status_str(rs->status));
 
 	/* if WD or iamthif client treat specially */
 
@@ -532,7 +552,6 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
 		if (pos->fop_type == MEI_FOP_CONNECT) {
 			if (is_treat_specially_client(cl, rs)) {
 				list_del(&pos->list);
-				cl->status = 0;
 				cl->timer_count = 0;
 				break;
 			}
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h
index e06779d..6b476ab 100644
--- a/drivers/misc/mei/hw.h
+++ b/drivers/misc/mei/hw.h
@@ -89,19 +89,19 @@ enum mei_stop_reason_types {
  * Client Connect Status
  * used by hbm_client_connect_response.status
  */
-enum client_connect_status_types {
-	CCS_SUCCESS = 0x00,
-	CCS_NOT_FOUND = 0x01,
-	CCS_ALREADY_STARTED = 0x02,
-	CCS_OUT_OF_RESOURCES = 0x03,
-	CCS_MESSAGE_SMALL = 0x04
+enum mei_cl_connect_status {
+	MEI_CL_CONN_SUCCESS          = 0x00,
+	MEI_CL_CONN_NOT_FOUND        = 0x01,
+	MEI_CL_CONN_ALREADY_STARTED  = 0x02,
+	MEI_CL_CONN_OUT_OF_RESOURCES = 0x03,
+	MEI_CL_CONN_MESSAGE_SMALL    = 0x04
 };
 
 /*
  * Client Disconnect Status
  */
-enum client_disconnect_status_types {
-	CDS_SUCCESS = 0x00
+enum  mei_cl_disconnect_status {
+	MEI_CL_DISCONN_SUCCESS = 0x00
 };
 
 /*
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5424f8f..434242b 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -471,7 +471,7 @@ static int mei_ioctl_connect_client(struct file *file,
 	if (i < 0 || dev->me_clients[i].props.fixed_address) {
 		dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
 				&data->in_client_uuid);
-		rets = -ENODEV;
+		rets = -ENOTTY;
 		goto end;
 	}
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 05/11] mei: wd and amthif use mei_cl_ api for dis/connection
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (3 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 04/11] mei: hbm: revamp client connect and disconnection status Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 06/11] mei: fix potential read outside of array bounds Tomas Winkler
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler, Alexander Usyskin

Connect wd and amthif through regular mei_cl_connect API
as there is no reason to connect in asynchronous mode.
Also use mei_cl_is_connected in order to protect flows
instead of depending on wd_pending and amthif_timer

Now we can remove all the special handling in hbm layer

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/amthif.c    | 13 +++----
 drivers/misc/mei/hbm.c       | 89 +++++++++++++++-----------------------------
 drivers/misc/mei/interrupt.c |  5 ++-
 drivers/misc/mei/mei_dev.h   |  2 +-
 drivers/misc/mei/wd.c        | 37 ++++++++++++------
 5 files changed, 66 insertions(+), 80 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index b8dfc61..708bbb6 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -115,14 +115,11 @@ int mei_amthif_host_init(struct mei_device *dev)
 
 	cl->state = MEI_FILE_CONNECTING;
 
-	if (mei_hbm_cl_connect_req(dev, cl)) {
-		dev_dbg(&dev->pdev->dev, "amthif: Failed to connect to ME client\n");
-		cl->state = MEI_FILE_DISCONNECTED;
-		cl->host_client_id = 0;
-	} else {
-		cl->timer_count = MEI_CONNECT_TIMEOUT;
-	}
-	return 0;
+	ret = mei_cl_connect(cl, NULL);
+
+	dev->iamthif_state = MEI_IAMTHIF_IDLE;
+
+	return ret;
 }
 
 /**
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index d360e9a..46743e2 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -134,30 +134,6 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf)
 
 
 /**
- * is_treat_specially_client - checks if the message belongs
- * to the file private data.
- *
- * @cl: private data of the file object
- * @rs: connect response bus message
- *
- */
-static bool is_treat_specially_client(struct mei_cl *cl,
-		struct hbm_client_connect_response *rs)
-{
-	if (mei_hbm_cl_addr_equal(cl, rs)) {
-		if (rs->status == MEI_CL_CONN_SUCCESS)
-			cl->state = MEI_FILE_CONNECTED;
-		else
-			cl->state = MEI_FILE_DISCONNECTED;
-		cl->status = mei_cl_conn_status_to_errno(rs->status);
-		cl->timer_count = 0;
-
-		return true;
-	}
-	return false;
-}
-
-/**
  * mei_hbm_idle - set hbm to idle state
  *
  * @dev: the device structure
@@ -467,22 +443,22 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev,
 		struct hbm_client_connect_response *rs)
 {
 	struct mei_cl *cl;
-	struct mei_cl_cb *pos = NULL, *next = NULL;
+	struct mei_cl_cb *cb, *next;
 
 	dev_dbg(&dev->pdev->dev, "hbm: disconnect response cl:host=%02d me=%02d status=%d\n",
 			rs->me_addr, rs->host_addr, rs->status);
 
-	list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
-		cl = pos->cl;
+	list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
+		cl = cb->cl;
 
-		if (!cl) {
-			list_del(&pos->list);
+		/* this should not happen */
+		if (WARN_ON(!cl)) {
+			list_del(&cb->list);
 			return;
 		}
 
-		dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
 		if (mei_hbm_cl_addr_equal(cl, rs)) {
-			list_del(&pos->list);
+			list_del(&cb->list);
 			if (rs->status == MEI_CL_DISCONN_SUCCESS)
 				cl->state = MEI_FILE_DISCONNECTED;
 
@@ -523,40 +499,41 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
 {
 
 	struct mei_cl *cl;
-	struct mei_cl_cb *pos = NULL, *next = NULL;
+	struct mei_cl_cb *cb, *next;
 
 	dev_dbg(&dev->pdev->dev, "hbm: connect response cl:host=%02d me=%02d status=%s\n",
 			rs->me_addr, rs->host_addr,
 			mei_cl_conn_status_str(rs->status));
 
-	/* if WD or iamthif client treat specially */
+	cl = NULL;
 
-	if (is_treat_specially_client(&dev->wd_cl, rs)) {
-		dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
-		mei_watchdog_register(dev);
+	list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) {
 
-		return;
-	}
+		cl = cb->cl;
+		/* this should not happen */
+		if (WARN_ON(!cl)) {
+			list_del_init(&cb->list);
+			continue;
+		}
 
-	if (is_treat_specially_client(&dev->iamthif_cl, rs)) {
-		dev->iamthif_state = MEI_IAMTHIF_IDLE;
-		return;
-	}
-	list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) {
+		if (cb->fop_type !=  MEI_FOP_CONNECT)
+			continue;
 
-		cl = pos->cl;
-		if (!cl) {
-			list_del(&pos->list);
-			return;
-		}
-		if (pos->fop_type == MEI_FOP_CONNECT) {
-			if (is_treat_specially_client(cl, rs)) {
-				list_del(&pos->list);
-				cl->timer_count = 0;
-				break;
-			}
+		if (mei_hbm_cl_addr_equal(cl, rs)) {
+			list_del(&cb->list);
+			break;
 		}
 	}
+
+	if (!cl)
+		return;
+
+	cl->timer_count = 0;
+	if (rs->status == MEI_CL_CONN_SUCCESS)
+		cl->state = MEI_FILE_CONNECTED;
+	else
+		cl->state = MEI_FILE_DISCONNECTED;
+	cl->status = mei_cl_conn_status_to_errno(rs->status);
 }
 
 
@@ -582,10 +559,6 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
 					disconnect_req->me_addr);
 			cl->state = MEI_FILE_DISCONNECTED;
 			cl->timer_count = 0;
-			if (cl == &dev->wd_cl)
-				dev->wd_pending = false;
-			else if (cl == &dev->iamthif_cl)
-				dev->iamthif_timer = 0;
 
 			cb = mei_io_cb_init(cl, NULL);
 			if (!cb)
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 8fbdb59..7d37d83 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -477,7 +477,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 		wake_up_interruptible(&dev->wait_stop_wd);
 	}
 
-	if (dev->dev_state == MEI_DEV_ENABLED) {
+	if (mei_cl_is_connected(&dev->wd_cl)) {
 		if (dev->wd_pending &&
 		    mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
 			if (mei_wd_send(dev))
@@ -595,6 +595,9 @@ void mei_timer(struct work_struct *work)
 		}
 	}
 
+	if (!mei_cl_is_connected(&dev->iamthif_cl))
+		goto out;
+
 	if (dev->iamthif_stall_timer) {
 		if (--dev->iamthif_stall_timer == 0) {
 			dev_err(&dev->pdev->dev, "timer: amthif  hanged.\n");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index c59c56b..36640b9 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -543,7 +543,7 @@ int mei_wd_host_init(struct mei_device *dev);
  *   once we got connection to the WD Client
  * @dev - mei device
  */
-void mei_watchdog_register(struct mei_device *dev);
+int mei_watchdog_register(struct mei_device *dev);
 /*
  * mei_watchdog_unregister  - Unregistering watchdog interface
  * @dev - mei device
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index a769fb1..afe976a 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -87,15 +87,20 @@ int mei_wd_host_init(struct mei_device *dev)
 
 	cl->state = MEI_FILE_CONNECTING;
 
-	if (mei_hbm_cl_connect_req(dev, cl)) {
-		dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
-		cl->state = MEI_FILE_DISCONNECTED;
-		cl->host_client_id = 0;
-		return -EIO;
+	ret = mei_cl_connect(cl, NULL);
+
+	if (ret) {
+		dev_err(&dev->pdev->dev, "wd: failed to connect = %d\n", ret);
+		mei_cl_unlink(cl);
+		return ret;
 	}
-	cl->timer_count = MEI_CONNECT_TIMEOUT;
 
-	return 0;
+	ret = mei_watchdog_register(dev);
+	if (ret) {
+		mei_cl_disconnect(cl);
+		mei_cl_unlink(cl);
+	}
+	return ret;
 }
 
 /**
@@ -363,17 +368,25 @@ static struct watchdog_device amt_wd_dev = {
 };
 
 
-void mei_watchdog_register(struct mei_device *dev)
+int mei_watchdog_register(struct mei_device *dev)
 {
-	if (watchdog_register_device(&amt_wd_dev)) {
-		dev_err(&dev->pdev->dev,
-			"wd: unable to register watchdog device.\n");
-		return;
+
+	int ret;
+
+	/* unlock to perserve correct locking order */
+	mutex_unlock(&dev->device_lock);
+	ret = watchdog_register_device(&amt_wd_dev);
+	mutex_lock(&dev->device_lock);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "wd: unable to register watchdog device = %d.\n",
+			ret);
+		return ret;
 	}
 
 	dev_dbg(&dev->pdev->dev,
 		"wd: successfully register watchdog interface.\n");
 	watchdog_set_drvdata(&amt_wd_dev, dev);
+	return 0;
 }
 
 void mei_watchdog_unregister(struct mei_device *dev)
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 06/11] mei: fix potential read outside of array bounds
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (4 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 05/11] mei: wd and amthif use mei_cl_ api for dis/connection Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 07/11] mei: use helper function to find me client by id Tomas Winkler
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

From: Alexander Usyskin <alexander.usyskin@intel.com>

Drop not-very-useful check and with this
fix read on index that can be after array end.
Cleanup search function as byproduct.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 6639bc3..488edd0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -29,20 +29,21 @@
  * mei_me_cl_by_uuid - locate index of me client
  *
  * @dev: mei device
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
  * returns me client index or -ENOENT if not found
  */
 int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
 {
-	int i, res = -ENOENT;
+	int i;
 
 	for (i = 0; i < dev->me_clients_num; ++i)
 		if (uuid_le_cmp(*uuid,
-				dev->me_clients[i].props.protocol_name) == 0) {
-			res = i;
-			break;
-		}
+				dev->me_clients[i].props.protocol_name) == 0)
+			return i;
 
-	return res;
+	return -ENOENT;
 }
 
 
@@ -60,16 +61,12 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *uuid)
 int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
 {
 	int i;
+
 	for (i = 0; i < dev->me_clients_num; i++)
 		if (dev->me_clients[i].client_id == client_id)
-			break;
-	if (WARN_ON(dev->me_clients[i].client_id != client_id))
-		return -ENOENT;
+			return i;
 
-	if (i == dev->me_clients_num)
-		return -ENOENT;
-
-	return i;
+	return -ENOENT;
 }
 
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 07/11] mei: use helper function to find me client by id
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (5 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 06/11] mei: fix potential read outside of array bounds Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 08/11] mei: make return values consistent across the driver Tomas Winkler
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

From: Alexander Usyskin <alexander.usyskin@intel.com>

We already have a helper to find me client by id, let's
use it in all relevant places.

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/client.c | 62 +++++++++++++++++++++++------------------------
 drivers/misc/mei/hbm.c    | 42 +++++++++++++++++++-------------
 2 files changed, 56 insertions(+), 48 deletions(-)

diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 488edd0..35c84ac 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -567,7 +567,8 @@ out:
 int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 {
 	struct mei_device *dev;
-	int i;
+	struct mei_me_client *me_cl;
+	int id;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -EINVAL;
@@ -580,19 +581,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 	if (cl->mei_flow_ctrl_creds > 0)
 		return 1;
 
-	for (i = 0; i < dev->me_clients_num; i++) {
-		struct mei_me_client  *me_cl = &dev->me_clients[i];
-		if (me_cl->client_id == cl->me_client_id) {
-			if (me_cl->mei_flow_ctrl_creds) {
-				if (WARN_ON(me_cl->props.single_recv_buf == 0))
-					return -EINVAL;
-				return 1;
-			} else {
-				return 0;
-			}
-		}
+	id = mei_me_cl_by_id(dev, cl->me_client_id);
+	if (id < 0) {
+		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+		return id;
 	}
-	return -ENOENT;
+
+	me_cl = &dev->me_clients[id];
+	if (me_cl->mei_flow_ctrl_creds) {
+		if (WARN_ON(me_cl->props.single_recv_buf == 0))
+			return -EINVAL;
+		return 1;
+	}
+	return 0;
 }
 
 /**
@@ -608,32 +609,31 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
 int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
 {
 	struct mei_device *dev;
-	int i;
+	struct mei_me_client *me_cl;
+	int id;
 
 	if (WARN_ON(!cl || !cl->dev))
 		return -EINVAL;
 
 	dev = cl->dev;
 
-	if (!dev->me_clients_num)
-		return -ENOENT;
+	id = mei_me_cl_by_id(dev, cl->me_client_id);
+	if (id < 0) {
+		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
+		return id;
+	}
 
-	for (i = 0; i < dev->me_clients_num; i++) {
-		struct mei_me_client  *me_cl = &dev->me_clients[i];
-		if (me_cl->client_id == cl->me_client_id) {
-			if (me_cl->props.single_recv_buf != 0) {
-				if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
-					return -EINVAL;
-				dev->me_clients[i].mei_flow_ctrl_creds--;
-			} else {
-				if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
-					return -EINVAL;
-				cl->mei_flow_ctrl_creds--;
-			}
-			return 0;
-		}
+	me_cl = &dev->me_clients[id];
+	if (me_cl->props.single_recv_buf != 0) {
+		if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
+			return -EINVAL;
+		me_cl->mei_flow_ctrl_creds--;
+	} else {
+		if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+			return -EINVAL;
+		cl->mei_flow_ctrl_creds--;
 	}
-	return -ENOENT;
+	return 0;
 }
 
 /**
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 46743e2..7e99e41 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -22,6 +22,7 @@
 #include "mei_dev.h"
 #include "hbm.h"
 #include "hw-me.h"
+#include "client.h"
 
 static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
 {
@@ -340,27 +341,34 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
  *
  * @dev: the device structure
  * @flow: flow control.
+ *
+ * return 0 on success, < 0 otherwise
  */
-static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
+static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
 				  struct hbm_flow_control *flow)
 {
-	struct mei_me_client *client;
-	int i;
-
-	for (i = 0; i < dev->me_clients_num; i++) {
-		client = &dev->me_clients[i];
-		if (client && flow->me_addr == client->client_id) {
-			if (client->props.single_recv_buf) {
-				client->mei_flow_ctrl_creds++;
-				dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
-				    flow->me_addr);
-				dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
-				    client->mei_flow_ctrl_creds);
-			} else {
-				BUG();	/* error in flow control */
-			}
-		}
+	struct mei_me_client *me_cl;
+	int id;
+
+	id = mei_me_cl_by_id(dev, flow->me_addr);
+	if (id < 0) {
+		dev_err(&dev->pdev->dev, "no such me client %d\n",
+			flow->me_addr);
+		return id;
 	}
+
+	me_cl = &dev->me_clients[id];
+	if (me_cl->props.single_recv_buf) {
+		me_cl->mei_flow_ctrl_creds++;
+		dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
+		    flow->me_addr);
+		dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
+		    me_cl->mei_flow_ctrl_creds);
+	} else {
+		BUG();	/* error in flow control */
+	}
+
+	return 0;
 }
 
 /**
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 08/11] mei: make return values consistent across the driver
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (6 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 07/11] mei: use helper function to find me client by id Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 09/11] mei: don't of list_for_each_entry_safe when not deleting Tomas Winkler
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Alexander Usyskin, Tomas Winkler

From: Alexander Usyskin <alexander.usyskin@intel.com>

1. Propagate ENOTTY  to user space if the client is not present
in the system
2. Use ETIME consistently on timeouts
3. Return EIO on write failures
4. Return ENODEV on recoverable device failures such as resets

Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    | 12 +++++-------
 drivers/misc/mei/client.c    | 26 ++++++++++++++------------
 drivers/misc/mei/hbm.c       |  2 +-
 drivers/misc/mei/hw-me.c     |  8 ++++----
 drivers/misc/mei/interrupt.c |  4 ++--
 drivers/misc/mei/main.c      |  2 +-
 drivers/misc/mei/nfc.c       |  6 +++---
 drivers/misc/mei/wd.c        |  6 +++---
 8 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 708bbb6..c0b54a0 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -78,10 +78,9 @@ int mei_amthif_host_init(struct mei_device *dev)
 
 	i = mei_me_cl_by_uuid(dev, &mei_amthif_guid);
 	if (i < 0) {
-		ret = i;
 		dev_info(&dev->pdev->dev,
-			"amthif: failed to find the client %d\n", ret);
-		return ret;
+			"amthif: failed to find the client %d\n", i);
+		return -ENOTTY;
 	}
 
 	cl->me_client_id = dev->me_clients[i].client_id;
@@ -176,14 +175,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 	/* Only possible if we are in timeout */
 	if (!cl || cl != &dev->iamthif_cl) {
 		dev_dbg(&dev->pdev->dev, "bad file ext.\n");
-		return -ETIMEDOUT;
+		return -ETIME;
 	}
 
 	i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
-
 	if (i < 0) {
 		dev_dbg(&dev->pdev->dev, "amthif client not found.\n");
-		return -ENODEV;
+		return -ENOTTY;
 	}
 	dev_dbg(&dev->pdev->dev, "checking amthif data\n");
 	cb = mei_amthif_find_read_list_entry(dev, file);
@@ -224,7 +222,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
 			dev_dbg(&dev->pdev->dev, "amthif Time out\n");
 			/* 15 sec for the message has expired */
 			list_del(&cb->list);
-			rets = -ETIMEDOUT;
+			rets = -ETIME;
 			goto free;
 		}
 	}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 35c84ac..ec19e38 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -665,7 +665,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
 	i = mei_me_cl_by_id(dev, cl->me_client_id);
 	if (i < 0) {
 		cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
-		return  -ENODEV;
+		return  -ENOTTY;
 	}
 
 	cb = mei_io_cb_init(cl, NULL);
@@ -853,13 +853,12 @@ 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;
 
-	rets = buf->size;
 out:
 	if (mei_hdr.msg_complete) {
-		if (mei_cl_flow_ctrl_reduce(cl)) {
-			rets = -ENODEV;
+		rets = mei_cl_flow_ctrl_reduce(cl);
+		if (rets < 0)
 			goto err;
-		}
+
 		list_add_tail(&cb->list, &dev->write_waiting_list.list);
 	} else {
 		list_add_tail(&cb->list, &dev->write_list.list);
@@ -869,15 +868,18 @@ out:
 	if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
 
 		mutex_unlock(&dev->device_lock);
-		if (wait_event_interruptible(cl->tx_wait,
-			cl->writing_state == MEI_WRITE_COMPLETE)) {
-				if (signal_pending(current))
-					rets = -EINTR;
-				else
-					rets = -ERESTARTSYS;
-		}
+		rets = wait_event_interruptible(cl->tx_wait,
+				cl->writing_state == MEI_WRITE_COMPLETE);
 		mutex_lock(&dev->device_lock);
+		/* wait_event_interruptible returns -ERESTARTSYS */
+		if (rets) {
+			if (signal_pending(current))
+				rets = -EINTR;
+			goto err;
+		}
 	}
+
+	rets = buf->size;
 err:
 	return rets;
 }
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 7e99e41..023173d 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -161,7 +161,7 @@ int mei_hbm_start_wait(struct mei_device *dev)
 	if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
 		dev->hbm_state = MEI_HBM_IDLE;
 		dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
-		return -ETIMEDOUT;
+		return -ETIME;
 	}
 	return 0;
 }
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 84165cc..7e769c5 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -244,7 +244,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
 	mutex_lock(&dev->device_lock);
 	if (!err && !dev->recvd_hw_ready) {
 		if (!err)
-			err = -ETIMEDOUT;
+			err = -ETIME;
 		dev_err(&dev->pdev->dev,
 			"wait hw ready failed. status = %d\n", err);
 		return err;
@@ -303,7 +303,7 @@ static bool mei_me_hbuf_is_empty(struct mei_device *dev)
  *
  * @dev: the device structure
  *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
+ * returns -EOVERFLOW if overflow, otherwise empty slots count
  */
 static int mei_me_hbuf_empty_slots(struct mei_device *dev)
 {
@@ -326,7 +326,7 @@ static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
 
 
 /**
- * mei_write_message - writes a message to mei device.
+ * mei_me_write_message - writes a message to mei device.
  *
  * @dev: the device structure
  * @header: mei HECI header of message
@@ -381,7 +381,7 @@ static int mei_me_write_message(struct mei_device *dev,
  *
  * @dev: the device structure
  *
- * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
+ * returns -EOVERFLOW if overflow, otherwise filled slots count
  */
 static int mei_me_count_full_read_slots(struct mei_device *dev)
 {
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 7d37d83..5df04fc 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -350,7 +350,7 @@ int mei_irq_read_handler(struct mei_device *dev,
 		dev_err(&dev->pdev->dev, "less data available than length=%08x.\n",
 				*slots);
 		/* we can't read the message */
-		ret = -ERANGE;
+		ret = -EBADMSG;
 		goto end;
 	}
 
@@ -483,7 +483,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 			if (mei_wd_send(dev))
 				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
 			else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
-				return -ENODEV;
+				return -EIO;
 			dev->wd_pending = false;
 		}
 	}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 434242b..49e3bb8 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -340,7 +340,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 
 	id = mei_me_cl_by_id(dev, cl->me_client_id);
 	if (id < 0) {
-		rets = -ENODEV;
+		rets = -ENOTTY;
 		goto out;
 	}
 
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 7626dde..3095fc5 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -364,7 +364,7 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
 	if (!wait_event_interruptible_timeout(ndev->send_wq,
 				ndev->recv_req_id == ndev->req_id, HZ)) {
 		dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
-		err = -ETIMEDOUT;
+		err = -ETIME;
 	} else {
 		ndev->req_id++;
 	}
@@ -502,7 +502,7 @@ int mei_nfc_host_init(struct mei_device *dev)
 	i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
 	if (i < 0) {
 		dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
-		ret = -ENOENT;
+		ret = -ENOTTY;
 		goto err;
 	}
 
@@ -520,7 +520,7 @@ int mei_nfc_host_init(struct mei_device *dev)
 	i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
 	if (i < 0) {
 		dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
-		ret = -ENOENT;
+		ret = -ENOTTY;
 		goto err;
 	}
 
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index afe976a..4644b62 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -53,7 +53,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
  *
  * @dev: the device structure
  *
- * returns -ENENT if wd client cannot be found
+ * returns -ENOTTY if wd client cannot be found
  *         -EIO if write has failed
  *         0 on success
  */
@@ -73,7 +73,7 @@ int mei_wd_host_init(struct mei_device *dev)
 	id = mei_me_cl_by_uuid(dev, &mei_wd_guid);
 	if (id < 0) {
 		dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
-		return id;
+		return -ENOTTY;
 	}
 
 	cl->me_client_id = dev->me_clients[id].client_id;
@@ -185,7 +185,7 @@ int mei_wd_stop(struct mei_device *dev)
 		ret = 0;
 	} else {
 		if (!ret)
-			ret = -ETIMEDOUT;
+			ret = -ETIME;
 		dev_warn(&dev->pdev->dev,
 			"wd: stop failed to complete ret=%d.\n", ret);
 	}
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 09/11] mei: don't of list_for_each_entry_safe when not deleting
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (7 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 08/11] mei: make return values consistent across the driver Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 10/11] mei: wd: simplify wd_send command Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 11/11] mei: wd: fix stop completion failure Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

We can use simply list_for_each_entry if there is no
entry removal

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/amthif.c    | 12 +++++-------
 drivers/misc/mei/bus.c       |  4 ++--
 drivers/misc/mei/client.c    | 23 +++++++++++------------
 drivers/misc/mei/hbm.c       |  9 ++++-----
 drivers/misc/mei/interrupt.c | 13 ++++++-------
 5 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index c0b54a0..f05d54d 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -132,14 +132,12 @@ int mei_amthif_host_init(struct mei_device *dev)
 struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
 						struct file *file)
 {
-	struct mei_cl_cb *pos = NULL;
-	struct mei_cl_cb *next = NULL;
+	struct mei_cl_cb *cb;
 
-	list_for_each_entry_safe(pos, next,
-				&dev->amthif_rd_complete_list.list, list) {
-		if (pos->cl && pos->cl == &dev->iamthif_cl &&
-			pos->file_object == file)
-			return pos;
+	list_for_each_entry(cb, &dev->amthif_rd_complete_list.list, list) {
+		if (cb->cl && cb->cl == &dev->iamthif_cl &&
+			cb->file_object == file)
+			return cb;
 	}
 	return NULL;
 }
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index cf4cc0b..463ae51 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -145,9 +145,9 @@ static struct device_type mei_cl_device_type = {
 static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
 						uuid_le uuid)
 {
-	struct mei_cl *cl, *next;
+	struct mei_cl *cl;
 
-	list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+	list_for_each_entry(cl, &dev->device_list, device_link) {
 		if (!uuid_le_cmp(uuid, cl->device_uuid))
 			return cl;
 	}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index ec19e38..aac7cdb 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -251,10 +251,9 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
 struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
 {
 	struct mei_device *dev = cl->dev;
-	struct mei_cl_cb *cb = NULL;
-	struct mei_cl_cb *next = NULL;
+	struct mei_cl_cb *cb;
 
-	list_for_each_entry_safe(cb, next, &dev->read_list.list, list)
+	list_for_each_entry(cb, &dev->read_list.list, list)
 		if (mei_cl_cmp_id(cl, cb->cl))
 			return cb;
 	return NULL;
@@ -474,17 +473,17 @@ free:
 bool mei_cl_is_other_connecting(struct mei_cl *cl)
 {
 	struct mei_device *dev;
-	struct mei_cl *pos;
-	struct mei_cl *next;
+	struct mei_cl *ocl; /* the other client */
 
 	if (WARN_ON(!cl || !cl->dev))
 		return false;
 
 	dev = cl->dev;
 
-	list_for_each_entry_safe(pos, next, &dev->file_list, link) {
-		if ((pos->state == MEI_FILE_CONNECTING) &&
-		    (pos != cl) && cl->me_client_id == pos->me_client_id)
+	list_for_each_entry(ocl, &dev->file_list, link) {
+		if (ocl->state == MEI_FILE_CONNECTING &&
+		    ocl != cl &&
+		    cl->me_client_id == ocl->me_client_id)
 			return true;
 
 	}
@@ -919,9 +918,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 
 void mei_cl_all_disconnect(struct mei_device *dev)
 {
-	struct mei_cl *cl, *next;
+	struct mei_cl *cl;
 
-	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+	list_for_each_entry(cl, &dev->file_list, link) {
 		cl->state = MEI_FILE_DISCONNECTED;
 		cl->mei_flow_ctrl_creds = 0;
 		cl->timer_count = 0;
@@ -936,8 +935,8 @@ void mei_cl_all_disconnect(struct mei_device *dev)
  */
 void mei_cl_all_wakeup(struct mei_device *dev)
 {
-	struct mei_cl *cl, *next;
-	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+	struct mei_cl *cl;
+	list_for_each_entry(cl, &dev->file_list, link) {
 		if (waitqueue_active(&cl->rx_wait)) {
 			cl_dbg(dev, cl, "Waking up reading client!\n");
 			wake_up_interruptible(&cl->rx_wait);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 023173d..9555791 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -380,8 +380,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
 static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
 		struct hbm_flow_control *flow_control)
 {
-	struct mei_cl *cl = NULL;
-	struct mei_cl *next = NULL;
+	struct mei_cl *cl;
 
 	if (!flow_control->host_addr) {
 		/* single receive buffer */
@@ -390,7 +389,7 @@ static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
 	}
 
 	/* normal connection */
-	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+	list_for_each_entry(cl, &dev->file_list, link) {
 		if (mei_hbm_cl_addr_equal(cl, flow_control)) {
 			cl->mei_flow_ctrl_creds++;
 			dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
@@ -557,10 +556,10 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
 static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
 		struct hbm_client_connect_request *disconnect_req)
 {
-	struct mei_cl *cl, *next;
+	struct mei_cl *cl;
 	struct mei_cl_cb *cb;
 
-	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+	list_for_each_entry(cl, &dev->file_list, link) {
 		if (mei_hbm_cl_addr_equal(cl, disconnect_req)) {
 			dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
 					disconnect_req->host_addr,
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 5df04fc..31cb345 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -556,8 +556,7 @@ EXPORT_SYMBOL_GPL(mei_irq_write_handler);
 void mei_timer(struct work_struct *work)
 {
 	unsigned long timeout;
-	struct mei_cl *cl_pos = NULL;
-	struct mei_cl *cl_next = NULL;
+	struct mei_cl *cl;
 	struct mei_cl_cb  *cb_pos = NULL;
 	struct mei_cl_cb  *cb_next = NULL;
 
@@ -585,9 +584,9 @@ void mei_timer(struct work_struct *work)
 		goto out;
 
 	/*** connect/disconnect timeouts ***/
-	list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
-		if (cl_pos->timer_count) {
-			if (--cl_pos->timer_count == 0) {
+	list_for_each_entry(cl, &dev->file_list, link) {
+		if (cl->timer_count) {
+			if (--cl->timer_count == 0) {
 				dev_err(&dev->pdev->dev, "timer: connect/disconnect timeout.\n");
 				mei_reset(dev);
 				goto out;
@@ -637,10 +636,10 @@ void mei_timer(struct work_struct *work)
 			list_for_each_entry_safe(cb_pos, cb_next,
 				&dev->amthif_rd_complete_list.list, list) {
 
-				cl_pos = cb_pos->file_object->private_data;
+				cl = cb_pos->file_object->private_data;
 
 				/* Finding the AMTHI entry. */
-				if (cl_pos == &dev->iamthif_cl)
+				if (cl == &dev->iamthif_cl)
 					list_del(&cb_pos->list);
 			}
 			mei_io_cb_free(dev->iamthif_current_cb);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 10/11] mei: wd: simplify wd_send command
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (8 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 09/11] mei: don't of list_for_each_entry_safe when not deleting Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  2014-02-17 13:13 ` [char-misc-next 11/11] mei: wd: fix stop completion failure Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler, Alexander Usyskin

Add reduce credits to wd_send to remove code
repetition and simplify error handling

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
---
 drivers/misc/mei/interrupt.c |  7 +++---
 drivers/misc/mei/wd.c        | 52 +++++++++++++++++++++++---------------------
 2 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 31cb345..834220a 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -480,10 +480,9 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 	if (mei_cl_is_connected(&dev->wd_cl)) {
 		if (dev->wd_pending &&
 		    mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
-			if (mei_wd_send(dev))
-				dev_dbg(&dev->pdev->dev, "wd send failed.\n");
-			else if (mei_cl_flow_ctrl_reduce(&dev->wd_cl))
-				return -EIO;
+			ret = mei_wd_send(dev);
+			if (ret)
+				return ret;
 			dev->wd_pending = false;
 		}
 	}
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 4644b62..13bb7a9 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -111,13 +111,16 @@ int mei_wd_host_init(struct mei_device *dev)
  * returns 0 if success,
  *	-EIO when message send fails
  *	-EINVAL when invalid message is to be sent
+ *	-ENODEV on flow control failure
  */
 int mei_wd_send(struct mei_device *dev)
 {
+	struct mei_cl *cl = &dev->wd_cl;
 	struct mei_msg_hdr hdr;
+	int ret;
 
-	hdr.host_addr = dev->wd_cl.host_client_id;
-	hdr.me_addr = dev->wd_cl.me_client_id;
+	hdr.host_addr = cl->host_client_id;
+	hdr.me_addr = cl->me_client_id;
 	hdr.msg_complete = 1;
 	hdr.reserved = 0;
 	hdr.internal = 0;
@@ -126,10 +129,24 @@ int mei_wd_send(struct mei_device *dev)
 		hdr.length = MEI_WD_START_MSG_SIZE;
 	else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
 		hdr.length = MEI_WD_STOP_MSG_SIZE;
-	else
+	else {
+		dev_err(&dev->pdev->dev, "wd: invalid message is to be sent, aborting\n");
 		return -EINVAL;
+	}
+
+	ret = mei_write_message(dev, &hdr, dev->wd_data);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "wd: write message failed\n");
+		return ret;
+	}
 
-	return mei_write_message(dev, &hdr, dev->wd_data);
+	ret = mei_cl_flow_ctrl_reduce(cl);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "wd: flow_ctrl_reduce failed.\n");
+		return ret;
+	}
+
+	return 0;
 }
 
 /**
@@ -159,16 +176,9 @@ int mei_wd_stop(struct mei_device *dev)
 		goto out;
 
 	if (ret && mei_hbuf_acquire(dev)) {
-		ret = 0;
-
-		if (!mei_wd_send(dev)) {
-			ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
-			if (ret)
-				goto out;
-		} else {
-			dev_err(&dev->pdev->dev, "wd: send stop failed\n");
-		}
-
+		ret = mei_wd_send(dev);
+		if (ret)
+			goto out;
 		dev->wd_pending = false;
 	} else {
 		dev->wd_pending = true;
@@ -289,18 +299,10 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 
 		dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
 
-		if (mei_wd_send(dev)) {
-			dev_err(&dev->pdev->dev, "wd: send failed.\n");
-			ret = -EIO;
+		ret = mei_wd_send(dev);
+		if (ret)
 			goto end;
-		}
-
-		if (mei_cl_flow_ctrl_reduce(&dev->wd_cl)) {
-			dev_err(&dev->pdev->dev, "wd: mei_cl_flow_ctrl_reduce() failed.\n");
-			ret = -EIO;
-			goto end;
-		}
-
+		dev->wd_pending = false;
 	} else {
 		dev->wd_pending = true;
 	}
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [char-misc-next 11/11] mei: wd: fix stop completion failure
  2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
                   ` (9 preceding siblings ...)
  2014-02-17 13:13 ` [char-misc-next 10/11] mei: wd: simplify wd_send command Tomas Winkler
@ 2014-02-17 13:13 ` Tomas Winkler
  10 siblings, 0 replies; 16+ messages in thread
From: Tomas Winkler @ 2014-02-17 13:13 UTC (permalink / raw)
  To: gregkh; +Cc: arnd, linux-kernel, Tomas Winkler

While running Documentation/watchdog/src/watchdog-simple.c
and quiting by Ctrl-C, fallowing error is displayed:
mei_me 0000:00:16.0: wd: stop failed to complete ret=-512.

The whatchdog core framework is not able to propagate
-ESYSRESTART or -EINTR. Also There is no much sense in
restarting the close system call so instead of using
wait_event_interruptible_timeout we can use wait_event_timeout
with reasonable 10 msecs timeout.

Reported-by: Prarit Bhargava <prarit@redhat.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/misc/mei/interrupt.c |  2 +-
 drivers/misc/mei/wd.c        | 32 +++++++++++++++++---------------
 2 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 834220a..5aab335 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -474,7 +474,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
 
 	if (dev->wd_state == MEI_WD_STOPPING) {
 		dev->wd_state = MEI_WD_IDLE;
-		wake_up_interruptible(&dev->wait_stop_wd);
+		wake_up(&dev->wait_stop_wd);
 	}
 
 	if (mei_cl_is_connected(&dev->wd_cl)) {
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 13bb7a9..e084adf 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -155,9 +155,11 @@ int mei_wd_send(struct mei_device *dev)
  * @dev: the device structure
  * @preserve: indicate if to keep the timeout value
  *
- * returns 0 if success,
- *	-EIO when message send fails
+ * returns 0 if success
+ * on error:
+ *	-EIO    when message send fails
  *	-EINVAL when invalid message is to be sent
+ *	-ETIME  on message timeout
  */
 int mei_wd_stop(struct mei_device *dev)
 {
@@ -173,12 +175,12 @@ int mei_wd_stop(struct mei_device *dev)
 
 	ret = mei_cl_flow_ctrl_creds(&dev->wd_cl);
 	if (ret < 0)
-		goto out;
+		goto err;
 
 	if (ret && mei_hbuf_acquire(dev)) {
 		ret = mei_wd_send(dev);
 		if (ret)
-			goto out;
+			goto err;
 		dev->wd_pending = false;
 	} else {
 		dev->wd_pending = true;
@@ -186,21 +188,21 @@ int mei_wd_stop(struct mei_device *dev)
 
 	mutex_unlock(&dev->device_lock);
 
-	ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-					dev->wd_state == MEI_WD_IDLE,
-					msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
+	ret = wait_event_timeout(dev->wait_stop_wd,
+				dev->wd_state == MEI_WD_IDLE,
+				msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
 	mutex_lock(&dev->device_lock);
-	if (dev->wd_state == MEI_WD_IDLE) {
-		dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
-		ret = 0;
-	} else {
-		if (!ret)
-			ret = -ETIME;
+	if (dev->wd_state != MEI_WD_IDLE) {
+		/* timeout */
+		ret = -ETIME;
 		dev_warn(&dev->pdev->dev,
 			"wd: stop failed to complete ret=%d.\n", ret);
+		goto err;
 	}
-
-out:
+	dev_dbg(&dev->pdev->dev, "wd: stop completed after %u msec\n",
+			MEI_WD_STOP_TIMEOUT - jiffies_to_msecs(ret));
+	return 0;
+err:
 	return ret;
 }
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper
  2014-02-17 13:13 ` [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper Tomas Winkler
@ 2014-02-18 18:03   ` Greg KH
  2014-02-19  9:58     ` Winkler, Tomas
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2014-02-18 18:03 UTC (permalink / raw)
  To: Tomas Winkler; +Cc: arnd, linux-kernel

On Mon, Feb 17, 2014 at 03:13:17PM +0200, Tomas Winkler wrote:
> A client has to acquire host buffer
> before writing, we add lock like wrapper
> to replace the code snippet
> 
> if (dev->hbuf_is_ready)
>         dev->hbuf_is_ready = false;
> 
> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
> ---
>  drivers/misc/mei/amthif.c    |  7 +-----
>  drivers/misc/mei/client.c    | 56 ++++++++++++++++++++++++++++----------------
>  drivers/misc/mei/hw-me.c     |  2 ++
>  drivers/misc/mei/hw-txe.c    | 17 +++++---------
>  drivers/misc/mei/interrupt.c |  6 ++---
>  drivers/misc/mei/mei_dev.h   |  2 ++
>  drivers/misc/mei/wd.c        | 14 +++++------
>  7 files changed, 57 insertions(+), 47 deletions(-)

This patch fails to apply to my char-misc-next branch (I've pulled in
3.14-rc3 into this branch now):
	checking file drivers/misc/mei/amthif.c
	checking file drivers/misc/mei/client.c
	Hunk #4 FAILED at 681.
	Hunk #5 succeeded at 815 (offset -2 lines).
	Hunk #6 succeeded at 848 (offset -2 lines).
	1 out of 6 hunks FAILED
	checking file drivers/misc/mei/hw-me.c
	checking file drivers/misc/mei/hw-txe.c
	checking file drivers/misc/mei/interrupt.c
	checking file drivers/misc/mei/mei_dev.h
	checking file drivers/misc/mei/wd.c

Care to fix this up and resend this series?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper
  2014-02-18 18:03   ` Greg KH
@ 2014-02-19  9:58     ` Winkler, Tomas
  2014-02-19 14:35       ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Winkler, Tomas @ 2014-02-19  9:58 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, linux-kernel


> 
> This patch fails to apply to my char-misc-next branch (I've pulled in
> 3.14-rc3 into this branch now):
> 	checking file drivers/misc/mei/amthif.c
> 	checking file drivers/misc/mei/client.c
> 	Hunk #4 FAILED at 681.
> 	Hunk #5 succeeded at 815 (offset -2 lines).
> 	Hunk #6 succeeded at 848 (offset -2 lines).
> 	1 out of 6 hunks FAILED
> 	checking file drivers/misc/mei/hw-me.c
> 	checking file drivers/misc/mei/hw-txe.c
> 	checking file drivers/misc/mei/interrupt.c
> 	checking file drivers/misc/mei/mei_dev.h
> 	checking file drivers/misc/mei/wd.c
> 
> Care to fix this up and resend this series?


The patch 'mei: set client's read_cb to NULL when flow control fails' (accb884b32e82f943340688c9cd30290531e73e0)
Which is in char-misc-linus, still haven't make it to the  upstream...I thought it would be in rc3 already.

I can either fix the current series and then you will need to resolve quite simple conflict in merge (it's just a two line patch) or we wait for another cycle. 
I would prefer the first option as I have few more patches in the queue I won't to send for review but it's up to you.

Thanks
Tomas

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper
  2014-02-19 14:35       ` Greg KH
@ 2014-02-19 14:34         ` Winkler, Tomas
  0 siblings, 0 replies; 16+ messages in thread
From: Winkler, Tomas @ 2014-02-19 14:34 UTC (permalink / raw)
  To: Greg KH; +Cc: arnd, linux-kernel


> > The patch 'mei: set client's read_cb to NULL when flow control fails'
> > (accb884b32e82f943340688c9cd30290531e73e0) Which is in
> > char-misc-linus, still haven't make it to the  upstream...I thought it
> > would be in rc3 already.
> 
> No, you sent it too late for that.
> 
> > I can either fix the current series and then you will need to resolve
> > quite simple conflict in merge (it's just a two line patch) or we wait
> > for another cycle.  I would prefer the first option as I have few more
> > patches in the queue I won't to send for review but it's up to you.
> 
> I'll merge char-misc-linus into char-misc-next and then can you resend
> the pending patches to me?

Works for me.
Tomas


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper
  2014-02-19  9:58     ` Winkler, Tomas
@ 2014-02-19 14:35       ` Greg KH
  2014-02-19 14:34         ` Winkler, Tomas
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2014-02-19 14:35 UTC (permalink / raw)
  To: Winkler, Tomas; +Cc: arnd, linux-kernel

On Wed, Feb 19, 2014 at 09:58:08AM +0000, Winkler, Tomas wrote:
> 
> > 
> > This patch fails to apply to my char-misc-next branch (I've pulled in
> > 3.14-rc3 into this branch now):
> > 	checking file drivers/misc/mei/amthif.c
> > 	checking file drivers/misc/mei/client.c
> > 	Hunk #4 FAILED at 681.
> > 	Hunk #5 succeeded at 815 (offset -2 lines).
> > 	Hunk #6 succeeded at 848 (offset -2 lines).
> > 	1 out of 6 hunks FAILED
> > 	checking file drivers/misc/mei/hw-me.c
> > 	checking file drivers/misc/mei/hw-txe.c
> > 	checking file drivers/misc/mei/interrupt.c
> > 	checking file drivers/misc/mei/mei_dev.h
> > 	checking file drivers/misc/mei/wd.c
> > 
> > Care to fix this up and resend this series?
> 
> 
> The patch 'mei: set client's read_cb to NULL when flow control fails'
> (accb884b32e82f943340688c9cd30290531e73e0) Which is in
> char-misc-linus, still haven't make it to the  upstream...I thought it
> would be in rc3 already.

No, you sent it too late for that.

> I can either fix the current series and then you will need to resolve
> quite simple conflict in merge (it's just a two line patch) or we wait
> for another cycle.  I would prefer the first option as I have few more
> patches in the queue I won't to send for review but it's up to you.

I'll merge char-misc-linus into char-misc-next and then can you resend
the pending patches to me?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2014-02-19 14:35 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-17 13:13 [char-misc-next 00/11] mei fixes and cleanups Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 01/11 RESEND] mei: add mei_hbuf_acquire wrapper Tomas Winkler
2014-02-18 18:03   ` Greg KH
2014-02-19  9:58     ` Winkler, Tomas
2014-02-19 14:35       ` Greg KH
2014-02-19 14:34         ` Winkler, Tomas
2014-02-17 13:13 ` [char-misc-next 02/11 RESEND] mei: revamp writing slot counting Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 03/11] mei: Remove all bus devices from the mei_dev list when stopping the MEI Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 04/11] mei: hbm: revamp client connect and disconnection status Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 05/11] mei: wd and amthif use mei_cl_ api for dis/connection Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 06/11] mei: fix potential read outside of array bounds Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 07/11] mei: use helper function to find me client by id Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 08/11] mei: make return values consistent across the driver Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 09/11] mei: don't of list_for_each_entry_safe when not deleting Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 10/11] mei: wd: simplify wd_send command Tomas Winkler
2014-02-17 13:13 ` [char-misc-next 11/11] mei: wd: fix stop completion failure Tomas Winkler

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.